docker container 활용 #3
PID namespace 외에 Network namespace 를 알아보겠습니다.
처음 글을 시작한 의도는 docker 를 잘 활용하자는 의미였는데 하다보니 아직 그 내용은 들어가 보지도 못했네요.
개발자나 운영자들은 잘 인식하지 못하지만 linux 의 Network 는 모두 namespace 구조하에 움직이고 있습니다.
기본적으로 host 기반으로 사용하는 network 의 namespace 는 1 입니다. 그리고 docker 가 실행되면 docker process 에 대해서 내부적인 network 를 사용합니다.
network namespace 와 network namespace 간의 연결은 virtual ethernet (veth) 를 사용하여 연결합니다. 즉, veth pair 를 만들어서 하나는 docker 내부에 다른 하나는 host 로 하여 서로 네트워크로 연결하고 host 에 있는 veth 는 host 의 bridge 로 연결하면 docker 내부에서 host 의 bridge 로 연결이 됩니다.
docker 컨테이너 (eth0) <-> host veth <-> host bridge (docker0) <-> host network (ens2f0)
먼저, host veth 의 리스트를 보겠습니다.
$ sudo ip addr show
15479: vethf5fa5c1@if15478: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 32:83:61:96:55:4a brd ff:ff:ff:ff:ff:ff link-netnsid 1
15481: veth4667f7d@if15480: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 56:39:6e:41:3d:50 brd ff:ff:ff:ff:ff:ff link-netnsid 0
15483: vethd61c546@if15482: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether b2:4a:88:71:d0:03 brd ff:ff:ff:ff:ff:ff link-netnsid 2
15489: vethbe5dd5b@if15488: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker_gwbridge state UP
link/ether fe:85:37:ac:ea:76 brd ff:ff:ff:ff:ff:ff link-netnsid 4
15493: veth66998b7@if15492: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 42:5f:03:92:45:9d brd ff:ff:ff:ff:ff:ff link-netnsid 5
총 5개가 보이는데 이중 하나는 docker gateway bridge 로 연결되고 나머지 4개는 1:1 로 각각 docker 내부의 eth0 와 연결되어 있습니다.
이를 좀 쉽게 찾기 위해서 veth.sh 파일을 만들었습니다.
#!/bin/bash
VETHS=`ifconfig -a | grep veth | sed 's/ .*//g'`
DOCKERS=$(docker ps -a | grep Up | awk '{print $1}')
for VETH in $VETHS
do
PEER_IFINDEX=`ethtool -S $VETH 2>/dev/null | grep peer_ifindex | sed 's/ *peer_ifindex: *//g'`
for DOCKER in $DOCKERS
do
PEER_IF=`docker exec $DOCKER ip link list 2>/dev/null | grep "^$PEER_IFINDEX:" | awk '{print $2}' | sed 's/:.*//g'`
if [ -z "$PEER_IF" ]; then
continue
else
printf "%-10s is paired with %-10s on %-20s\n" $VETH $PEER_IF $DOCKER
break
fi
done
done
위 파일을 실행하면 아래와 같이 나옵니다.
veth4667f7d: is paired with eth0@if15481 on b75a945f84fa
veth66998b7: is paired with eth0@if15493 on 67246d3e1c68
vethd61c546: is paired with eth0@if15483 on 87faa6bacbba
vethf5fa5c1: is paired with eth0@if15479 on 0b4bc5ba78f9
마지막에 보이는 것은 docker id 입니다.
host 의 docker0 bridge 가 어떻게 연결되어 있는 지는 brctl 로 알 수 있습니다.
$ sudo yum install -y bridge-utils
$ sudo brctl show
docker0 bridge 가 어떻게 host 의 외부 네트워크로 나가는 지는 iptables 와 routing 을 보면 알 수 있습니다.
$ sudo iptables -t nat -S
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
source 가 docker 내부 ip 대역이고 host 입장에서 패킷이 나가는 인터페이스가 docker0 가 아니면 jump 를 하고 host의 ip 로 변경해서 (masquerade) 나가라고 되어 있습니다.
$ netstat -rn
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 192.168.30.1 0.0.0.0 UG 0 0 0 ens2f0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker_gwbridge
그리고 위와 같이 외부로 나갈 때는 default gateway 로 외부로 나가게 됩니다.