-
[Docker] Docker Container 와 veth ( Virtual Ethernet Network Interface ) 알아보기Docker 2024. 6. 20. 07:24반응형
- 목차
들어가며.
이번 글에서는 Docker Container 와 Network Namespace 격리에 대해서 알아보려고 합니다.
Docker Container 는 Linux 의 Network Namespace 를 활용하여 Network 를 격리합니다.
그 외에 PID, UTS, MOUNT 등의 Namespace 를 통해서 하나의 격리된 Container 를 생성하게 되는데요.
이번 글에선 특히 Network Namespace 를 통한 Network Isolation 에 대해서 알아보도록 하겠습니다.
veth 이란 ?
Linux 의 Network Interface 를 여러 가지 Type 이 존재합니다.
Loopback, Dummy, Ethernet, Virtual Ethernet, Bridge 등이 존재합니다.
흔히 ip link show 명령어를 통해서 그 목록들을 확인할 수 있습니다.
아래의 목록들이 바로 그 예시입니다.
ip link show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0 3: gre0@NONE: <NOARP> mtu 1476 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/gre 0.0.0.0 brd 0.0.0.0 4: gretap0@NONE: <BROADCAST,MULTICAST> mtu 1462 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff 5: erspan0@NONE: <BROADCAST,MULTICAST> mtu 1450 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff 6: ip_vti0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0 7: ip6_vti0@NONE: <NOARP> mtu 1428 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/tunnel6 :: brd :: permaddr 6ef:d2c8:3081:: 8: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/sit 0.0.0.0 brd 0.0.0.0 9: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/tunnel6 :: brd :: permaddr 3e7d:7c3d:24d6:: 10: ip6gre0@NONE: <NOARP> mtu 1448 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/gre6 :: brd :: permaddr 7653:e:be60:: 11: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 02:42:40:2d:5c:bd brd ff:ff:ff:ff:ff:ff 15: veth744a50b@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether fa:37:e2:2f:bb:0a brd ff:ff:ff:ff:ff:ff link-netnsid 1 17: vethcc31343@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether da:48:f0:c5:bc:b7 brd ff:ff:ff:ff:ff:ff link-netnsid 2 19: veth93c7e59@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether ca:28:5e:6d:71:9a brd ff:ff:ff:ff:ff:ff link-netnsid 3 44: eth0@if45: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65535 qdisc noqueue state UP mode DEFAULT group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
ip link 는 각 Network Interface 를 표현합니다.
실제 Ethernet 랜선으로 연결되거나 Wireless LAN 으로 연결된 물리적인 Network Interface 가 존재하며,
그 외의 가상의 Network Interface 가 존재합니다.
Docker Container 에서는 이번 글의 주제인 veth (Virtual Ethernet) 인터페이스를 사용하여 네트워크 격리를 수행합니다.
실제 Docker Container 를 실행하는 Host 와 그 내부의 Container 는 아래와 같이 Network 가 연결됩니다.
이는 하나의 IP Link 로써 아래와 같이 표현됩니다.
vethcc31343@if16 이라는 이름으로 표현되는데요.
이는 @ 을 경계로 Host 의 vethcc31343 와 Container 의 if16 인터페이스가 서로 연결됨을 의미합니다.
17: vethcc31343@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether da:48:f0:c5:bc:b7 brd ff:ff:ff:ff:ff:ff link-netnsid 2
veth 와 Network Namespace 알아보기.
아래와 같은 아주 간단한 Docker Container 를 실행합니다.
그리고 실행 중인 Docker Container 의 Network 상태를 파악해보겠습니다.
docker run -d busybox sleep 100000
docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 794e0b37a9c6 busybox "sleep 100000" 3 seconds ago Up 2 seconds eloquent_lehmann
그리고 ip link show 명령어를 통해서 현재 Host 에 생성된 Network Interface 을 조회합니다.
그럼 아래와 같이 1개의 Virtual Ethernet Network Interface 를 확인할 수 있습니다.
이 veth 의 이름은 veth4a67fcf 입니다.
그리고 veth4a67fcf 인터페이스는 if20 인터페이스와 연결됩니다.
ip link show
21: veth4a67fcf@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether aa:48:e8:22:84:b3 brd ff:ff:ff:ff:ff:ff link-netnsid 1
여기서 중요한 점은 if20 네트워크 인터페이스는 Host 의 Network Interface 와 다른 Namespace 공간에 존재합니다.
그래서 Host 에서 ip link show, ip addr show 등의 명령어를 호출해서 if20 에 해당하는 Network Interface 를 확인할 수 없습니다.
( 참고로 if20 은 20번째 Network Interface 라는 의미입니다. )
Container 의 Network Namespace 확인하기.
사실상 모든 Container 는 호스트 머신에서 실행되는 하나의 Process 입니다.
그래서 ps aux 명령을 통해서 모든 Process 목록을 확인하게 되면, Container 와 관련된 여러가지 Process 들을 확인할 수 있습니다.
dockerd, containerd, containerd-shim 등이 존재하는데요.
저희는 sleep 10000 명령어를 실행하는 실질적인 Container process 를 주목해야합니다.
ps aux PID USER TIME COMMAND 1 root 0:02 docker-init -- dockerd --host=unix:///var/run/docker.sock --host=tcp://0.0.0.0:2376 56 root 0:16 dockerd --host=unix:///var/run/docker.sock --host=tcp://0.0.0.0:2376 --tlsverify -- 66 root 0:10 containerd --config /var/run/docker/containerd/containerd.toml 1186 root 0:00 sh 1192 root 0:00 sh 1536 root 0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace moby -id 794e0b37a9c672a709766621 1557 root 0:00 sleep 100000 1596 root 0:00 ps aux
Container Process 의 PID 는 1557 입니다.
그리고 각 Process 의 Namespace 를 관리하는 /proc/*/ns/net 를 확인합니다.
그리고 1557 Process 의 Network Namespace 의 값만이 다른 Network Namespace 와 상이함을 확인할 수 있습니다.
즉, Sleep 명령어를 실행하는 Docker Container 는 Host 입장에서 하나의 Process 이고,
이 Process 는 별도의 Network Namespace 를 가지게 됩니다.
ls -l /proc/*/ns/net
/proc/1/ns/net -> net:[4026532564] /proc/1186/ns/net -> net:[4026532564] /proc/1192/ns/net -> net:[4026532564] /proc/1536/ns/net -> net:[4026532564] /proc/1557/ns/net -> net:[4026532701] /proc/56/ns/net -> net:[4026532564] /proc/66/ns/net -> net:[4026532564] /proc/self/ns/net -> net:[4026532564] /proc/thread-self/ns/net -> net:[4026532564]
그리고 nsenter 명령어를 통해서 새로운 Network Namespace 에 속한 veth 인터페이스를 조회합니다.
nsenter 로 특정 Network Namespace 를 지정하여 Network Namespace 내부의 Interface 를 조회합니다.
nsenter --net=/proc/1557/ns/net ip link show
20: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
조회 결과는 eth0@if21 로 표현됩니다.
이는 아래와 같은 그림으로 표현될 수 있습니다.
결론적으로 Network Interface 의 이름은 조금 헷갈릴 수 있지만,
if20 와 if21 인터페이스는 서로 Peer Virtual Ethernet Interface 로써 서로 연결되어 있게 됩니다.
nsenter --net=/proc/1557/ns/net ip link show | grep eth0 nsenter --net=/proc/1/ns/net ip link show | grep veth
20: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default 21: veth4a67fcf@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
Container 의 갯수만큼 veth 인터페이스는 생성된다.
Docker Container 의 갯수만큼 veth 인터페이스와 Network Namespace 를 생성됩니다.
테스트를 위해서 10개 이상의 Docker Container 를 생성하였습니다.
docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES de1470ec33f4 busybox "sleep 100000" 1 second ago Up 1 second angry_bartik 39ea8f3444a0 busybox "sleep 100000" 2 seconds ago Up 2 seconds unruffled_gates 21d847281f80 busybox "sleep 100000" 2 seconds ago Up 2 seconds nice_bassi fed4337c267f busybox "sleep 100000" 2 seconds ago Up 2 seconds friendly_burnell 436ec20b26b4 busybox "sleep 100000" 2 seconds ago Up 2 seconds keen_golick 39855a1f4c13 busybox "sleep 100000" 2 seconds ago Up 2 seconds quizzical_bhaskara 59131cba0fef busybox "sleep 100000" 3 seconds ago Up 3 seconds romantic_mcnulty 6a168d460ac9 busybox "sleep 100000" 3 seconds ago Up 3 seconds kind_colden 4947e370dc89 busybox "sleep 100000" 3 seconds ago Up 3 seconds loving_elbakyan 73700d9f1d26 busybox "sleep 100000" 3 seconds ago Up 3 seconds sleepy_grothendieck 179b41c413c2 busybox "sleep 100000" 4 seconds ago Up 3 seconds lucid_brattain d4bc397a67a1 busybox "sleep 100000" 4 seconds ago Up 4 seconds confident_kowalevski 8244062a82e6 busybox "sleep 100000" 4 seconds ago Up 4 seconds nifty_beaver 794e0b37a9c6 busybox "sleep 100000" 22 minutes ago Up 22 minutes eloquent_lehmann
그리고 ip netns list-id 명령어를 통해서 생성된 Network Namespace 목록을 조회합니다.
아래와 같이 생성된 Docker Container 의 수만큼 별도의 Network Namespace 가 생성됩니다.
ip netns list-id
ip netns list-id nsid 0 nsid 1 nsid 2 nsid 3 nsid 4 nsid 5 nsid 6 nsid 7 nsid 8 nsid 9 nsid 10 nsid 11 nsid 12 nsid 13 nsid 14
또한 /proc/*/ns/net 디렉토리를 조회함으로써 Network Namespace 를 확인할 수 있습니다.
ls -l /proc/*/ns/net
/proc/1/ns/net -> net:[4026532564] /proc/1186/ns/net -> net:[4026532564] /proc/1192/ns/net -> net:[4026532564] /proc/1536/ns/net -> net:[4026532564] /proc/1557/ns/net -> net:[4026532701] /proc/1628/ns/net -> net:[4026532564] /proc/1649/ns/net -> net:[4026532836] /proc/1690/ns/net -> net:[4026532564] /proc/1710/ns/net -> net:[4026532971] /proc/1750/ns/net -> net:[4026532564] /proc/1769/ns/net -> net:[4026533234] /proc/1813/ns/net -> net:[4026532564] /proc/1832/ns/net -> net:[4026533369] /proc/1874/ns/net -> net:[4026532564] /proc/1894/ns/net -> net:[4026533504] /proc/1936/ns/net -> net:[4026532564] /proc/1957/ns/net -> net:[4026533639] /proc/1996/ns/net -> net:[4026532564] /proc/2015/ns/net -> net:[4026533774] /proc/2058/ns/net -> net:[4026532564] /proc/2077/ns/net -> net:[4026533909] /proc/2118/ns/net -> net:[4026532564] /proc/2138/ns/net -> net:[4026534044] /proc/2179/ns/net -> net:[4026532564] /proc/2199/ns/net -> net:[4026534179] /proc/2239/ns/net -> net:[4026532564] /proc/2258/ns/net -> net:[4026534314] /proc/2299/ns/net -> net:[4026532564] /proc/2318/ns/net -> net:[4026534449] /proc/2360/ns/net -> net:[4026532564] /proc/2381/ns/net -> net:[4026534584] /proc/56/ns/net -> net:[4026532564] /proc/66/ns/net -> net:[4026532564] /proc/self/ns/net -> net:[4026532564] /proc/thread-self/ns/net -> net:[4026532564]
반응형