레이블이 nsenter인 게시물을 표시합니다. 모든 게시물 표시
레이블이 nsenter인 게시물을 표시합니다. 모든 게시물 표시

overlay network 사용하기

# 들어가기 전에
# overlay network 실제 네트워크가 위에서 동작하는 가상네트워크다.
# overlay network 로 물리적으로 떨어져 있는 네트워크들도 마치 같은 네트워크에 있는 LAN 처럼 취급할 수 있다.
# 종류로 Virtual eXtensible LAN (VXLan)가 있다.
# OSI7계층 중 L2(datalink), L3(network) 에 걸쳐 사용되고, L2 프레임을 캡슐화해 터널링한다.
# MTU(Maximum Transmission Unit)는 패킷이나 프레임단위로 전송할때 최대 크기로 일반적으로 1500byte 으로 설정되는데 VXLan 사용시 캡슐화에 50byte 가 필요하기 때문에 1450byte 로 설정한다.
# ICMP(Internet Control Message Protocol) 는 L3 동작하며 대상 IP 의 상태(이상없는지)를 확인하는 프로토콜이다.
# ARP(Address Resolution Protocol)은 L3 동작하며 IP 주소를 L2의 물리주소(MAC, Media Access Control)주소로 바인딩시키기 위한 프로토콜이다.
# FDB(Fowarding DataBase)는 L2 에서 포워딩을 위해 MAC 주소를 저장하고 있다.


#####


# 테스트 환경 : vagrant ubuntu-1804
HOST_NAME = "ubuntu1804"    # node1 192.168.104.2
HOST_NAME2 = "ubuntu1804-2" # node2 192.168.104.3

# node1,2 각각 접속시 
vagrant ssh ubuntu184
vagrant ssh ubuntu184-2

# vxlan 으로 노드간 통신하기
# node1, node2 는 다음과 같이 구성(연결)할 것이다.
[node1]
pinkns(eth0:12.12.12.2/24) <-> overns(veth1 <-> br0:arp참고 <-> vxlan1:fdb참고) <-> host(eth1:192.168.104.2) <-> 외부
[node2]
pinkns(eth0:12.12.12.3/24),skyns(eth0:12.12.12.4/24) <-> overns(veth1 <-> br0:arp참고 <-> vxlan1:fdb참고) <-> host(eth1:192.168.104.3) <-> 외부

# node1, node2 각각 overns, pinkns 이름의 network namespace(netns) 생성
ip netns add overns
ip netns add pinkns

# node1, node2 각각 network namespace 확인
ip netns

# node1, node2 각각 veth1(overns) <-> eth0(pinkns) 연결(link 생성)
ip link add dev veth1 mtu 1450 netns overns type veth peer name eth0 mtu 1450 netns pinkns

# 참고로 ip netns exec overns 대신 overns 에 조인해서 작업할 경우
# 작업후 호스트 network namespace 로 돌아오기 위해 exit 잊지 말자.
# nsenter --net=/var/run/netns/overns

# node1(overns), node2(overns) 에서 ip link 확인
ip netns exec overns ip link

# node1(pinkns) 에서 �eth0 에 mac,ip address 추가
ip netns exec pinkns ip link set dev eth0 address 02:42:c0:a8:00:02
ip netns exec pinkns ip addr add dev eth0 12.12.12.2/24

# node2(pinkns) 에서 eth0 에 mac,ip address 추가
ip netns exec pinkns ip link set dev eth0 address 02:42:c0:a8:00:03
ip netns exec pinkns ip addr add dev eth0 12.12.12.3/24

# node1(overns), node2(overns) 에서 bridge 생성
ip netns exec overns ip link add dev br0 type bridge
ip netns exec overns ip addr add dev br0 12.12.12.1/24

# node1(overns), node2(overns) 에서 ip, link 확인
ip netns exec overns ip a
ip netns exec overns ip link

# node1, node2 에서 vxlan(overns) 생성
# type vxlan : vxlan 타입 생성
# id 42 : vxlan 식별자 42
# proxy : vxlan 이 ARP 요청에 대신 응답하도록 설정
# learning : 커널이 패킷을 파악해 bridge FDB 를 자동으로 설정할 수 있도록 설정
# dstport 4789 : vxlan 터널링에 사용하는 UDP 포트로 4789 사용
ip link add dev vxlan1 netns overns type vxlan id 42 proxy learning dstport 4789

# node1(overns), node2(overns) 에서 veth1 <-> br0 연결
ip netns exec overns ip link set veth1 master br0

# node1(overns), node2(overns) 에서 vxlan1 <-> br0 연결
ip netns exec overns ip link set vxlan1 master br0

# node1, node2 각각 overns, pinkns 의 장치들 모두 power on
ip netns exec overns ip link set br0 up
ip netns exec overns ip link set vxlan1 up
ip netns exec overns ip link set veth1 up
ip netns exec pinkns ip link set eth0 up

# node1(overns) 에서
# 목적지 ip(12.12.12.3),mac(02:42:c0:a8:00:03)를 사용하는 vxlan1 정보를 ARP 테이블에 기록
ip netns exec overns ip neighbor add 12.12.12.3 lladdr 02:42:c0:a8:00:03 dev vxlan1

# node2(overns)에서
# 목적지 ip(12.12.12.2),mac(02:42:c0:a8:00:02)를 사용하는 vxlan1 정보를 ARP 테이블에 기록
ip netns exec overns ip neighbor add 12.12.12.2 lladdr 02:42:c0:a8:00:02 dev vxlan1

# node1(overns), node2(overns) 에서 neighbor 확인
ip netns exec overns ip neighbor show

# node1(overns) 에서
# bridge fdb 설정 추가
# 192.168.104.3 : 목적지 IP
# 42 : 목적지 vni(VXLAN Network Identifier) ID
# 4789 : 목적지 Port
# 다음과 같이 수동으로 설정하면 permanent 하게 유지된다.
ip netns exec overns bridge fdb add 02:42:c0:a8:00:03 dev vxlan1 self dst 192.168.104.3 vni 42 port 4789

# node1(overns) 에서 fdb 설정 확인하면 permanent 표시가 있다.
ip netns exec overns bridge fdb show | grep 02:42:c0:a8:00:03

# node1(overns) 에서 br0, vxlan 에서 패킷 확인시
ip netns exec overns tcpdump -l -i br0
ip netns exec overns tcpdump -l -i vxlan1

# 위에서 vxlan 디바이스 생성 시에 learning 옵션사용했기 때문에 fdb, ARP 정보는 커널에서 패킷 분석해서 설정해준다.
# 하지만 수동설정(permanent)와 달리 aging 으로 인해 일정 시간 지나면 설정이 제거된다.
# node2(overns)에서 다음과 같이 다시 수동으로 변경하면 permanent 하게 설정된다.
ip netns exec overns bridge fdb replace 02:42:c0:a8:00:02 dev vxlan1 self dst 192.168.104.2 vni 42 port 4789

# node2(overns)에서 다시 fdb 설정 확인하면 permanent 가 있다.
ip netns exec overns bridge fdb show | grep 02:42:c0:a8:00:02

# 참고로 overns 의 FORWARD 가 허용으로 되어 있는지 확인
ip netns exec overns iptables -t filter -L | grep -i policy
Chain INPUT (policy ACCEPT)
Chain FORWARD (policy ACCEPT)
Chain OUTPUT (policy ACCEPT)

# node1(pinkns조인 상태) -> node2(pinkns) ping 해보면 응답을 받는다.
ip netns exec pinkns ping 12.12.12.3

# node2(pinkns조인 상태) -> node1(pinkns) ping 해보면 응답을 받는다.
ip netns exec pinkns ping 12.12.12.2



#####


# node1 에 새로운 skyns network namespace 추가하고 통신하기

# node1 에서 skyns 네트워크네임스페이스 추가, mac,ip 등 추가하고 power on
ip netns add skyns
ip link add dev veth2 mtu 1450 netns overns type veth peer name eth0 mtu 1450 netns skyns
ip netns exec skyns ip link set dev eth0 address 02:42:c0:a8:00:04
ip netns exec skyns ip addr add dev eth0 12.12.12.4/24
ip netns exec overns ip link set veth2 master br0
ip netns exec overns ip link set veth2 up
ip netns exec skyns ip link set eth0 up

# node1(skyns) -> node1(pinkns) ping 테스트
ip netns exec skyns ping 12.12.12.2

# node1(pinkns) -> node1(skyns) ping 테스트
ip netns exec pinkns ping 12.12.12.4

# node2(overns) 에서 fdb 추가
ip netns exec overns ip neighbor add 12.12.12.4 lladdr 02:42:c0:a8:00:04 dev vxlan1

# node1(skyns) -> node2(pinkns) ping 테스트
ip netns exec skyns ping 12.12.12.3


#####


# node3(192.168.104.4) 추가하고 node1,2와 통신하기

# vagrantfile 노드 추가 후 
# HOST_NAME3 = "ubuntu1804-3" # node3 192.168.104.4
# ubuntu1804-3(node3) 만 추가로 띄우기
# vagrant up
# ubuntu1804-3(node3) 접속
vagrant ssh ubuntu184-3

# node3 overns,pinkns, skyns network namespace 추가
ip netns add overns
ip netns add pinkns
ip netns add skyns

# node3 veth1(overns) <-> eth0(pinkns) 연결(link 생성)
ip link add dev veth1 mtu 1450 netns overns type veth peer name eth0 mtu 1450 netns pinkns

# node3 veth1(overns) <-> eth0(skyns) 연결(link 생성)
ip link add dev veth2 mtu 1450 netns overns type veth peer name eth0 mtu 1450 netns skyns

# node3(pinkns) 에서 eth0 에 mac,ip address 추가
ip netns exec pinkns ip link set dev eth0 address 02:42:c0:a8:00:0a
ip netns exec pinkns ip addr add dev eth0 12.12.12.10/24

# node3(skyns) 에서 eth0 에 mac,ip address 추가
ip netns exec skyns ip link set dev eth0 address 02:42:c0:a8:00:0b
ip netns exec skyns ip addr add dev eth0 12.12.12.11/24

# node3(overns) 에서 bridge 생성
ip netns exec overns ip link add dev br0 type bridge
ip netns exec overns ip addr add dev br0 12.12.12.1/24

# node3(overns) 에서 vxlan 생성
ip link add dev vxlan1 netns overns type vxlan id 42 proxy learning dstport 4789

# node3(overns) 에서 veth1 <-> br0, veth2 <-> br0, vxlan1 <-> br0 연결
ip netns exec overns ip link set veth1 master br0
ip netns exec overns ip link set veth2 master br0
ip netns exec overns ip link set vxlan1 master br0

# node3 overns, pinkns, skyns 의 장치들 모두 power on
ip netns exec overns ip link set br0 up
ip netns exec overns ip link set vxlan1 up
ip netns exec overns ip link set veth1 up
ip netns exec overns ip link set veth2 up
ip netns exec pinkns ip link set eth0 up
ip netns exec skyns ip link set eth0 up

# node3(overns) 에 node1,node2 ip,mac 정보를 ARP 테이블에 기록
ip netns exec overns ip neighbor add 12.12.12.3 lladdr 02:42:c0:a8:00:03 dev vxlan1
ip netns exec overns ip neighbor add 12.12.12.2 lladdr 02:42:c0:a8:00:02 dev vxlan1

# node3(overns) 에 node1,nod2 ip,mac 정보를 fdb 로 기록
ip netns exec overns bridge fdb add 02:42:c0:a8:00:02 dev vxlan1 self dst 192.168.104.2 vni 42 port 4789
ip netns exec overns bridge fdb add 02:42:c0:a8:00:03 dev vxlan1 self dst 192.168.104.3 vni 42 port 4789

# node1(overns), node2(overns) 에 node3 ip,mac 정보를 ARP 테이블에 기록
ip netns exec overns ip neighbor add 12.12.12.10 lladdr 02:42:c0:a8:00:0a dev vxlan1
ip netns exec overns ip neighbor add 12.12.12.11 lladdr 02:42:c0:a8:00:0b dev vxlan1

# node1(overns), node2(overns) 에 node3 ip,mac 정보를 fdb 로 기록
ip netns exec overns bridge fdb add 02:42:c0:a8:00:0a dev vxlan1 self dst 192.168.104.4 vni 42 port 4789
ip netns exec overns bridge fdb add 02:42:c0:a8:00:0b dev vxlan1 self dst 192.168.104.4 vni 42 port 4789

# node1(pinkns) -> node3(pinkns), node3(skyns) ping 테스트
ip netns exec pinkns ping 12.12.12.10
ip netns exec pinkns ping 12.12.12.11

# node2(pinkns) -> node3(pinkns), node3(skyns) ping 테스트
ip netns exec pinkns ping 12.12.12.10
ip netns exec pinkns ping 12.12.12.11

# node3(pinkns) -> node1(skyns) ping 테스트
ip netns exec pinkns ping 12.12.12.2

# node3(pinkns) -> node2(skyns) ping 테스트
ip netns exec pinkns ping 12.12.12.3

# 모든 테스트가 끝나고 network namespace 삭제하려면
ip netns delete overns
ip netns delete pinkns
ip netns delete skyns

container 에 없는 iptables 커맨드 실행하기

# container 에 없는 iptables 커맨드 실행하기

# 방법1
# container 시작시 호스트 볼륨 연결하기
# 이미 컨테이너가 존재하면 삭제(--rm)
# 호스트의 root path 를 컨테이너의 /host 로 연결하고, (--volume /:/new_root)
# 컨테이너에게 확장권한을 부여한다.(--privileged)
# 컨테이너 실행시 /new_root 로 root 를 변경한다.
docker run -it \
--name=ysoftman
--hostname=ysoftman \
--rm \
--volume /:/new_root \
--privileged  \
busybox \
chroot /new_root

# 이제 컨테이너 내에서 호스트의 커맨드가 실행된다.
iptables -t filter -S


# 방법2
# 컨테이너 내에서 --pid=host 로 호스트 PID namespace 를 사용한다.
# 호스트의 pid 1(system) 대상으로(-t) -m(--mount[=file], 파일을 명시하지 않으면 target process 의 mount namespace 조인)
docker run -it \
--name=ysoftman \
--hostname=ysoftman \
--rm \
--privileged \
--pid=host \
busybox \
nsenter -t 1 -m sh

# 이제 컨테이너 내에서 호스트의 mount 정보로 호스트의 커맨드가 실행된다.
iptables -t filter -S


# 방법3
# 그냥 컨테이너 실행
docker run -it --name=ysoftman --hostname=ysoftman busybox

# 터미널을 하나 더 열고 호스트에서
# 위 컨테이너의 pid 의 network namespace 조인해 iptables 명령 실행한다.
# -t(--target) pid -n(--net[=file], 파일을 명시하지 않으면 target process의 네트워크 네임스페이스로 조인)
nsenter -t $(docker inspect --format {{.State.Pid}} ysoftman) -n iptables -t filter -S

linux namespace

# 2002년 리눅스 커널에 포함된 namespace(mnt, pid, net, ipc, cgroup...타입) 로 isolation 구현
# 모든 프로세스들은 특정 네임스페이스에 속하고 unshare 로 새로운 네임스페이스에서 프로세스를 실행할 수 있다. 네임스페이스는 exit 로 빠져나올 수 있다.
# unshare 시 프로세스를 명시하지 않으면 ${SHELL}값(/bin/sh 또는 /bin/bash등)이 디폴트로 실행된다.

#####

# mnt namespace
# 부모(호스트)로 부터 격리된 mount타입(-m, --mount)의 네임스페이스로 /bin/bash 프로그램 실행
unshare --mount /bin/sh

# mount_ns 에 마운트하면 현재 네임스페이스에서만 마운트된것을 알 수 있다.
# tmpfs : 가상 메모리 파일시스템
# ushare 된 마운트 스페이스(격리됨)에서 생성한 마운트는 호스트에서 보이지 않는다.
mkdir /tmp/mount_ns
mount -n -t tmpfs tmpfs /tmp/mount_ns
mount | grep mount_ns

# 터미널을 하나 더 띄워 호스트 네임스페이스에서 보면 값이 다른것을 알 수 있다.
readlink /proc/$$/ns/mnt

# 호스트에서 tmpfs 마운트 정보가 안보이는것을 확인
mount | grep mount_ns

# 테스트 결과

#####

# pid namespace
# 새로운 pid(-p, --pid), -f(--fork) 네임스페이스으로 실행
# --mount-proc Just before running the program, mount the proc filesystem at mountpoint (default is /proc)
# --mount-prod 옵션을 사용하면 pid 네임스페이스가 /proc/{pid} 로 마운트되어 쉽게 pid 네임스페이스 접근할 수 있도록 해준다.(mount namspace 도 생긴다.)
unshare -fp --mount-proc /bin/sh

# 호스트 네임스페이스와 현재 pid 네임스페이스에 다른 pid 로 보인다.
# 현재 pid 네임스페이스에서 프로세스를 확인해보면 1번이다.
echo $$
ps -ef

# pid 네임스페이스에서의 pid namespace 정보를 보면
# 아래 호스트의 unshare mount namespace 와 다른것을 알 수 있다.
# unshare(mt ns id:4026532202) ---> pid-namespace /bin/sh (pid ns id:4026532203)
lsns -t pid -p 1

# 호스트에서 unshare 프로세스 pid 찾기
ps -ef | grep unshare

# ushare 프로세스의 namespace 정보
# ls -ahl /proc/{pid}/ns 로도 알 수 있다.
lsns -p {pid}

# mnt 네임스페이스ID 로 확인
lsns {namespace id}

# 테스트 결과 화면

#####

# cgroup namespace
# cgroup 는 controlgroup으로 프로세스의 리소스 제어하는 파일시스템이다.(sys/fs/cgroup)
# sleep 백그라운드 프로세스를 freezer(cgroup 작업 중지,재개를 위한 subsystem)의 sub2로 등록
mkdir -p /sys/fs/cgroup/freezer/sub2
sleep 100000 &
[1] 2932

# 테스트를 위해 sleep pid 환경변수로 설정 
export sleep_pid=2932

# sleep pid 를 sub2 cgroup 으로 등록
echo ${sleep_pid} > /sys/fs/cgroup/freezer/sub2/cgroup.procs

# 현재 프로세스도 freezer sub1 로 등록하자.
mkdir -p /sys/fs/cgroup/freezer/sub1

# 현재프로세스 확인, 테스트를 위해 현재 pid 환경변수로 설정 
echo $$
2178
export parent_pid=$(echo $$)

# 현재 프로세스 pid 를 sub1 cgroup 으로 등록
echo ${parent_pid} > /sys/fs/cgroup/freezer/sub1/cgroup.procs

# freezer (init process, PID 1), parent, sleep pid 확인
cat /proc/1/cgroup | grep freezer
cat /proc/${parent_pid}/cgroup | grep freezer
cat /proc/${sleep_pid}/cgroup | grep freezer

# freezer 파일 확인
tree -L 1 /sys/fs/cgroup/freezer/
/sys/fs/cgroup/freezer/
├── cgroup.clone_children
├── cgroup.procs
├── cgroup.sane_behavior
├── docker
├── notify_on_release
├── release_agent
├── sub1
├── sub2
└── tasks

# 새로운 cgroup(-C, --cgroup) 네임스페이스로 실행
unshare -Cm /bin/sh

# freezer (init process, PID 1), parent, sleep pid 확인해보면
# sub1 --> / 가 루트가 되고
# sub2 --> ../sub2 로 변경되었지만 호스트 cgroup 은 그대로 보인다.
cat /proc/1/cgroup | grep freezer
cat /proc/2178/cgroup | grep freezer
cat /proc/2932/cgroup | grep freezer

# 테스트 결과

#####

# stress 툴로 시스템 부하(cpu)를 테스트해보자.
# new_root 에 bash 준비하기
mkdir -p new_root/{bin,usr,lib,lib64} new_root/lib/x86_64-linux-gnu/ new_root/usr/lib/x86_64-linux-gnu
cp /bin/bash new_root/bin
cp /bin/mount new_root/bin
cp /lib/x86_64-linux-gnu/{libtinfo.so.5,libdl.so.2,libc.so.6} new_root/lib
cp /lib64/ld-linux-x86-64.so.2 new_root/lib64

# mount 명령등 준비하기
cp -rv /bin/{ls,cat,mount,umount,mkdir,rmdir,rm,cp,grep,ps} new_root/bin
cp -rv /usr/lib/x86_64-linux-gnu/* new_root/usr/lib/x86_64-linux-gnu
cp -rv /lib/x86_64-linux-gnu/* new_root/lib/x86_64-linux-gnu
cp -rv /lib64/* new_root/lib64

# stress, cgroup 툴 설치
apt-get install -y stress cgroup-tools

# chroot 후 필요한 파일들 복사
mkdir -p new_root/usr/bin/bin
cp /usr/bin/{top,stress,cgcreate,cgset,cgexec} new_root/usr/bin/

# top 실행시 필요한 파일들 복사
mkdir -p new_root/usr/share/terminfo
cp -r /usr/share/terminfo/ new_root/usr/share/terminfo

# cgcreate 시 root uid 파악에 필요
mkdir -p new_root/etc
cp /etc/group new_root/etc/group
cp /etc/passwd new_root/etc/passwd

# cgroup 관련 마운트 확인
mount | grep -E "cgroup*.cpu"

# chroot 후 mount 하기
chroot new_root
mkdir -p /sys/fs/cgroup
mkdir -p /sys/fs/cgroup/{cpuset,"cpu,cpuacct"}
mount -t cgroup -o cpuset cgroup /sys/fs/cgroup/cpuset
mount -t cgroup -o cpu,cpuacct cgroup /sys/fs/cgroup/cpu,cpuacct

# /proc 마운트
mkdir -p /proc
mount -t proc proc /proc

# mycgroup 생성 및 확인
cgcreate -a root -g cpu:mycgroup
ls -al /sys/fs/cgroup/cpu,cpuacct/ | grep mycgroup

# CPU 사용률(%) = (cpu.cfs_quota_us / cpu.cfs_period_us) * 100
# cpu.cfs_period_us 를 확인해 보면 100000(us, 100ms) 이다.
# cat /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us
# 따라서 cpu.cfs_quota_us=30000 을 주면 30% cpu 사용률로 제한한다.
cgset -r cpu.cfs_quota_us=30000 mycgroup

# mycgroup 에 strecc -c(--cpu) 1로 부하 테스트 백그라운드로 실행
cgexec -g cpu:mycgroup stress -c 1 &

# top 으로 stress 프로세스 30% 사용 확인
export TERM="xterm-256color"
top
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
 3129 root      20   0    8248     96      0 R  30.0  0.0   0:03.50 stress

# 테스트 결과

#####

# net namespace
# 새로운 network(-n, --net) 네임스페이스으로 실행
unshare --net /bin/sh

# 호스트 네임스페이스와 정보가 다른것을 알 수 있다.
ip a

# 테스트 결과

# ip 로 net namespace 생성해보기
ip netns add mynet

# net namespace 확인
ip netns list
# 또는
ls /var/run/netns

# nsenter 로 net네임스페이스(--net)에 들어가기
# 별도 프로그램 명시하지 않으면 디폴트로 $SHELL -> /bin/bash 를 실행한다.
nsenter --net=/var/run/netns/mynet
ip a

# net 네임스페이스에서 현재 프로세스의 pid,user,ipc,mnt등의 네임스페이스 정보 확인
lsns -p $$

# 호스트에서 net 네임스페이스 id 확인
# readlink /proc/$$/ns/net 대신 lsns 명령어로도 네임스페이스 정보를 확일 수 있다.
# lsns -t 타입 -p pid
lsns -t net -p $$

# 테스트 결과

#####

# user namespace 생성
# 새로운 user(-U, --user) 네임스페이스으로 실행
unshare --user /bin/sh

# 새로운 user 네임스페이스에서의 사용자 정보 확인
whoami
id

# 네임스페이스 확인해보기
ls -al /proc/$$/ns
lsns -p $$

# 테스트 결과 화면

# container 와 호스트 root 가 같은것인지 확인해보기
# docker 로 busybox 컨테이너 띄우기
docker container run -it --name busybox --rm busybox

# ps 로 보면 root 로 실행됐고, uid=0 으로 되어 있다
ps -ef
id

# 현재 프로세스의 user 네임스페이스 확인
readlink /proc/$$/ns/user

# 호스트에서도 확인해보면 root 이름이고 uid=0 이다.
ps -ef | grep root | head -3
id

# 호스트에서 현재 프로세스의 user 네임스페이스 확인해보면 위 container user namespace id 와 같은것을 알 수 있다.
# 결국 container 의 root 도 호스트 user 네임스페이스를 공유하기 때문에 호스트 root 와 같은것이다.
readlink /proc/$$/ns/user

# 테스트 결과 화면

# 참고로 docker v1.10 이상 부터는 별도의 user namespace 를 지원하지만
기본적으로 docker 로 컨테이너를 실행하면 root 로 프로세스를 실행한다.(user namespace 를 별도로 만들지 않고 호스트를 user namespace 를 사용한다.)
# 이 때문에 container root 계정이 악용될 수 있음을 인지해야 한다.
# docker remap 설정으로 uid 를 다르게할 수 있다. 아래 별도 포스트로 정리

#####

# uts(unix time sharing system) namespace
# 새로운 uts(-u, --uts) 네임스페이스으로 실행
unshare --uts /bin/sh

# 호스트명 변경하고 확인
hostname ysoftman
hostname

# 터미널을 하나 더 띄워 호스트를 확인해 보면 영향을 주지 않는것을 알 수 있다.
# 테스트 화면

#####

# ipc(interprocess communication) namespace
# shared memory, queue, semaphore 등의 리소스에서 사용되며 같은 ipc 네임스페이스안 프로세스들은 ipc 통신할 수 있다.
# ipc (shared memory, pipe) 상태 정보 보기
# -m  Write information about active shared memory segments.
ipcs -m

# ipc shared memeory 리소스 1000byte 생성
# -m Create a shared memory segment of size bytes.
ipcmk -M 1000

# 1000 byte shared memory segemnt 가 생성된것을 확인할 수 있다.
ipcs -m

# 새로운 ipc(-i, --ipc) 네임스페이스 생성
unshare --ipc /bin/sh

# 새로운 ipc 네임스페이스에서는 호스트에서 만든 1000bytes 리소스가 보이지 않는다.
ipcs -m

# 호스트로 나오기
exit

# ipc 리소스 삭제
# -M Remove the shared memory segment created with shmkey after the last detach is performed.
ipcrm -M {shared memory segment key}

# 삭제된 리소스 확인 
ipcs -m

# 위 과정을 테스트한 결과

linux ip iptables 사용하기

# linux 에서 자주 사용되는 ip 명령 예제들
# 참고로 다음과 같이 각 명령에 대한 도움말을 볼 수 있다.
ip addr help 
ip link help 

# 네트워크 장치�ipv4, ipv6 주소 정보
ip addr

# ip 주소할당, dev(device)로 eth0 를 사용
ip addr add 10.10.10.2/24 dev eth0

# ip 주소 삭제
ip addr add 10.10.10.10/24 dev eth0
ip addr delete 10.10.10.10/24 dev eth0

# 장치별 링크 정보 
ip link

# 라우터 정보
ip route

# 연결된 이웃 장치 정보
ip neighbor


##### 네트워크 네임스페이스 구분해서 통신하기 #####


# veth(virtual Ethernet devices) 타입으로
# lemon_eth0 apple_eth0 를 생성하고 연결한다.
ip link add lemon_eth0 type veth peer name apple_eth0

# namespace 확인
ip netns

# LEMON namespace(네트워크가 호스트 네트워크와 격리됨) 생성
# /var/run/netns/LEMON 파일이 생성된다.
ip netns add LEMON
ip netns add APPLE

# lemon_eth0 의 네임스페이스를 LEMON 으로 설정
ip link set lemon_eth0 netns LEMON
ip link set apple_eth0 netns APPLE

# LEMON 네임스페이스에 접속해서 lemon_eth0 장치 시작하기 
ip netns exec LEMON ip link set lemon_eth0 up
ip netns exec APPLE ip link set apple_eth0 up

# LEMON 네임스페이스에 접속해서 lemon_eth0 장치에 ip 설정하기
ip netns exec LEMON ip addr add 10.10.10.2/24 dev lemon_eth0
ip netns exec APPLE ip addr add 10.10.10.3/24 dev apple_eth0

# APPLE apple_eth0 의 패킷을 모니터링 하고
ip netns exec APPLE tcpdump -l -i apple_eth0
# LEMON(lemon_eth0) --> APPLE(apple_eth0) 로 핑을 보내 확인 할 수 있다.
ip netns exec LEMON ping 10.10.10.3

# 참고로 매번 네임스페이스 exec 를 명시하지 않고,
# nsenter 명령으로 네임스페이스 들어가 있을 수 있다.
# 들어간 네임스페이스에 exit 를 하면 빠져나온다.
nsenter --net=/var/run/netns/LEMON
ping 10.10.10.3

# 통신시 ARP 로 매번 브로드캐스팅은 비효율적이라 캐싱하게 된다.
# LEMON 네임스페이스 상에서 이웃을 조회하면 10.10.10.3(apple_eth0)가 캐싱되있다.
ip neighbor

# 현재 네임스페이스를 빠져나온다.(호스트(루트) 네임스페이스로 이동)
exit

# 이제 LEMON, APPLE 네임스페이스 삭제하면 LEMON, BLUE 네임스페이스 안의 이더넷도 모두 삭제된다.
ip netns del LEMON
ip netns del APPLE


##### iptables(netfilter) 설정하기 #####


# iptables 은 커널의 netfilter(프레임워크)에 rules를 설정하고 실제로는 netfilter 로 방화벽 기능이 동작한다.
# netfilter 는 다음 5개의 chain 을 hook 하고 룰에 따라 패킷을 필터링한다.
# PREROUTING: 외부로부터 들어오는 패킷
# INPUT: PREROUTING -> 로컬에서 받아야 하는 패킷
# FORWARD: PREROUTING -> FORWARD -> POSTROUTING 으로 로컬을 거치지 않고 외부로 부터 들어온 패킷을 다른 외부로 가야하는 패킷
# OUTPUT: 로컬 -> POSTROUTING 으로 로컬에서 외부로 가는 패킷
# POSTROUTING: FORWARD 또는 로컬에서 외부로 나가야하는 패킷

# 각 chain 에 맞는 다음과 같은 성격의 룰 테이블이 있다.
# filter:  패킷 필터링에 사용하는 테이블, INTPUT,FORWARD,OUTPUT 에서 사용
# nat: 출발지, 목적지 변경시 사용하는 테이블, PREROUTING,POSTROUTING 에서 사용
# mangle: 패킷 변조시 사용하는 테이블�, 5개 chain 모두에서 사용
# raw: 주로 netfilter 에서 추적하지 않도록 NOTRACK 설정하는데 사용하는 테이블, PREROUTING,OUTPUT 에서 사용
# security: SELinux 보안 사용시 사용하는 테이블, INPUT,FORWARD,OUTPUT 에서 사용

# filter 테이블 -S(list-rules) 룰 리스트 보기
iptables -t filter -S 
# -t 명시하지 않으면 filter 가 기본값이다.
iptables -S

# FOWARD chain에 설정된 rule들 보기 -v(가 없으면 in,out 이더넷 장치가 보인다) 
iptables -L FORWARD -v
iptables -L INPUT -v

# 10.10.10.3 으로 부터 들어오는(INPUT chain) -j(--jump) DROP(패킷 차단) 룰 추가(-A, --append)
iptables -A INPUT -s 10.10.10.3/32 -j DROP

# 10.10.10.3 으로 부터 들어오는(INPUT chain) -j(--jump) ACCEPT(패킷 허용) 룰 추가(-A, --append)
iptables -A INPUT -s 10.10.10.3/32 -j ACCEPT

# 룰 삭제(-D, --delete)
iptables -D INPUT -s 10.10.10.3/32 -j ACCEPT

# -A 같은 내용의 룰이 계속 추가 되 때문에
# -D 같은 내용이라도 마지막 룰만 삭제되어 모두 삭제하려면 N번 실행해야 한다.

# 외부(인터넷) 통신을 위해서는
# POSTROUTING 에 nat 추가
iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -j MASQUERADE
# 패킷을 내 사설IP 에서 받을 수 있도록 -d(--destination) 허용
iptables -t filter -A FORWARD -d 10.10.10.3/24 -j ACCEPT

# nat 설정 상태 확인
iptables -t nat -S