ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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]

     

     

    반응형
Designed by Tistory.