최근에 쿠버네티스를 공부할 일이 있어서 보고 있는데, 쿠버네티스 자체가 도커(Docker) 오케스트레이션을 해주는 툴이라 도커에 대한 개념이 없으니, 공부하기가 힘들었습니다. 그래서 이렇게 급하게 책을 사서 공부하면서 내용을 정리하고자 합니다.

해당 내용은 위키북스에서 나온 시작하세요! 도커 책을 보면서 정리한 내용입니다. 책의 내용이 매우 좋아서 강추합니다.

이번에는 도커의 네트워크에 대해서 한번 정리해보도록 하겠습니다.


Docker Network

컨테이너는 기본적으로 eth0lo 네트워크 인터페이스를 가지고 있습니다.

$ root@1758dcf92334:/# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:04
        inet addr:172.17.0.4  Bcast:172.17.255.255  Mask:255.255.0.0
        UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
        RX packets:7 errors:0 dropped:0 overruns:0 frame:0
        TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:0
        RX bytes:578 (578.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
        inet addr:127.0.0.1  Mask:255.0.0.0
        UP LOOPBACK RUNNING  MTU:65536  Metric:1
        RX packets:0 errors:0 dropped:0 overruns:0 frame:0
        TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:1
        RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

컨테이너는 내부 IP를 순차적으로 할당을 하며 컨테이너가 재시작될때마다 변경될 수 있습니다.

만약 외부와 연결을 해야할 경우에는 호스트에 veth(=virtual eth)라는 네트워크 인터페이스를 생성하고 컨테이너의 eth와 연결이 됩니다. veth 인터페이스는 사용자가 직접 생성할 필요 없이 도커엔진에 의해 자동으로 생성이 됩니다.

veth 인터페이스 뿐만 아니라 docker()라는 브리지도 있는데, 이는 veth 인터페이스와 바인딩되어 호스트의 eth 인터페이스 와 연결을 해줍니다.

그래서 도커의 네트워크는 다음과 같이 구성이 됩니다.


도커 네트워크 기능

도커에서 제공하는 대표적인 네트워크 드라이버로는 브릿지(bridge), 호스트(host), 논(none), 컨테이너(container, 오버레이(overlay)가 있습니다.

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
7c901cfddf66        bridge              bridge              local
64c96a434fc9        host                host                local
ab86e55ed2b4        none                null                local

이제 네트워크 드라이버 하나 하나 어떤 특징을 가지고 있는지 살펴보도록 하겠습니다.


브릿지 네트워크

docker() 브리지와 비슷하지만 사용자가 정의한 브리지를 생성해 각 컨테이너에 연결하는 네트워크 구조로 컨테이너는 연결된 브리지를 통해 외부와 통신할 수 있습니다.

브리지는 아래 명령어로 생성할 수 있습니다.

$ docker network create --driver bridge [브릿지 이름]

예시

$ docker network create --driver bridge mybridge
a8ea7918433e059cb7ae275e46080ab2765a766a2bbd01d7c0010885480b494b

docker run 또는 docker create 명령어에서 --net 옵션을 설정하면 커스텀 브리지를 사용할 수 있습니다.

$ docker run -i -t --name mynetwork_container \     # --name : 컨테이너의 이름을 지정, mynetwork_container란 이름을 사용
> --net mybridge \                                  # --net : 네트워크 설정, 위에서 만든 mybridge와 연결
> ubuntu:14.04                                      # 이미지로는 ubuntu:14.04 사용

호스트 네트워크

네트워크를 호스트로 설정하면 호스트의 네트워크 환경을 그대로 사용할 수 있습니다(= 내가 MacOS를 사용하면 MacOS의 네트워크를 그대로 이용한다는 의미)

$ docker run -i -t --name network_host \        # --name : 컨테이너의 이름을 지정, network_host 이름을 사용
> --net host \                                  # --net : 네트워크 설정, 'host'를 설정하면 호스트의 네트워크 환경을 가져다 사용
> ubuntu:14.04                                  # 이미지로는 ubuntu:14.04 사용

또 컨테이너의 네트워크를 호스트 모드로 설정하면 컨테이너 내부의 어플리케이션을 별도의 포트 포워딩 없이 바로 서비스 할 수 있습니다.


논 네트워크

none은 말 그대로 네트워크를 사용하지 않는 것을 의미합니다. none 네트워크로 설정을 하면 네트워크 인터페이스는 lo 인터페이스만 나타납니다. 이렇게 설정된 컨테이너는 외부와 단절 됩니다.

$ docker run -i -t --name network_none \    # --name : 컨테이너의 이름을 지정, network_none 이름을 사용 
> --net none \                              # --net : 네트워크 설정, 'host'를 설정하면 호스트의 네트워크 환경을 가져다 사용
> ubuntu:14.04                              # 이미지로는 ubuntu:14.04 사용

root@a64390b51af9:/# ifconfig
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)


컨테이너 네트워크

–net 옵션으로 container를 입력하면 다른 컨테이너의 네트워크 환경을 공유 할 수 있습니다. 사용방법은 다음과 같습니다.

--net container:[다른 컨테이너의 ID]
$ docker run -i -t -d --name network_container_1 ubuntu:14.04       # Daemon 형태의 컨테이너 network_container_1을 만듭니다.
193009d55ad3d084d777758c5ae73880eb27d634f557efd0b778a5130586b6e7

$  docker run -i -t -d --name network_container_2 \                 # Daemon 형태의 컨테이너 network_container_2을 만듭니다.
> --net container:network_container_1 \                             # --net container:network_container_1의 네트워크 구성을 설정합니다.
> ubuntu:14.04
62d44d71d03f3978ad0699db9bc2ba2032a9f43405bdff4e980f5f8bfb3cf8ea

이 경우 아래와 같이 ifconfig 명령을 입력해보면 동일한것을 확인할 수 있습니다.

$ docker exec network_container_1 ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:04
          inet addr:172.17.0.4  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:11 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:858 (858.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

$ docker exec network_container_2 ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:04
          inet addr:172.17.0.4  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:11 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:858 (858.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

브릿지 네트워크와 –net-alias

브릿지 타입의 네트워크와 run 명령어의 --net-alias 옵션을 같이 사용하면, 네트워크 구성에 대해서 별칭을 줄 수 있습니다. 아래에는 --net-alias 옵션을 이용하여 net_byjw이란 별칭을 주도록 하겠습니다.

$ docker run -i -t -d --name networkalias_container1 \             # networkalias_container1 이란 컨테이너 생성
> --net mybridge \                                                 # 위에서 만든 브릿지인 mybridge 사용
> --net-alias net_byjw \                                           # --net-alias [별칭]을 이용하여 'net_byjw'이란 네트워크 별칭 지정 
> ubuntu:14.04
54125a255958ea016218ff55a8451c3a86527e2a175bb57bb4a1bcf504ae99a8

$ docker run -i -t -d --name networkalias_container2 \             # networkalias_container2 이란 컨테이너 생성
> --net mybridge \                                                 # 위에서 만든 브릿지인 mybridge 사용
> --net-alias net_byjw \                                           # --net-alias [별칭]을 이용하여 'net_byjw'이란 네트워크 별칭 지정
> ubuntu:14.04
0a399eaad3d8a52456b30fd0dedda4ec359cb4e95476c8a2cce0bc63bba0b9c5

$ docker run -i -t -d --name networkalias_container3 \             # networkalias_container3 이란 컨테이너 생성
> --net mybridge \                                                 # 위에서 만든 브릿지인 mybridge 사용
> --net-alias net_byjw \                                           # --net-alias [별칭]을 이용하여 'net_byjw'이란 네트워크 별칭 지정
> ubuntu:14.04
f956c342843ac109e2f08cabc73666adffddc81756120ac1e85db6f00ffec545

위에서 만든 3 컨테이너의 IP 확인

$ docker exec networkalias_container1 ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:12:00:02
          inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:13 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1038 (1.0 KB)  TX bytes:0 (0.0 B)
$ docker exec networkalias_container2 ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:12:00:03
          inet addr:172.18.0.3  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:11 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:858 (858.0 B)  TX bytes:0 (0.0 B)
$ docker exec networkalias_container3 ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:12:00:04
          inet addr:172.18.0.4  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:11 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:858 (858.0 B)  TX bytes:0 (0.0 B)

이제 ping을 날릴 새로운 컨테이너를 생성해서 ‘net_byjw’에 ping을 날려보도록 하겠습니다.

$ docker run -i -t --name ping_test_container \
> --net mybridge \
> ubuntu:14.04

여기서는 172.18.0.4에서 응답했습니다.

root@85986984667e:/# ping -c 1 net_byjw
PING net_byjw (172.18.0.4) 56(84) bytes of data.
64 bytes from networkalias_container3.mybridge (172.18.0.4): icmp_seq=1 ttl=64 time=0.154 ms

--- net_byjw ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.154/0.154/0.154/0.000 ms

여기서는 172.18.0.3에서 응답했습니다.

root@85986984667e:/# ping -c 1 net_byjw
PING net_byjw (172.18.0.3) 56(84) bytes of data.
64 bytes from networkalias_container2.mybridge (172.18.0.3): icmp_seq=1 ttl=64 time=0.353 ms

--- net_byjw ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.353/0.353/0.353/0.000 ms

여기서는 172.18.0.2에서 응답했습니다.

root@85986984667e:/# ping -c 1 net_byjw
PING net_byjw (172.18.0.2) 56(84) bytes of data.
64 bytes from networkalias_container1.mybridge (172.18.0.2): icmp_seq=1 ttl=64 time=0.274 ms

--- net_byjw ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.274/0.274/0.274/0.000 ms

이렇듯 하나의 브릿지 네트워크로 설정이 되어있고, 별칭으로 묶인 컨테이너들은 도커 내부 DNS를 통해서 동일한 별칭(=net_byjw)으로 묶인 컨테이너들을 알고 있어서 개별 컨테이너들의 IP를 반환해줍니다. 만약 IP가 바뀌더라도 도커 내부 DNS가 감지를 해서 정확한 IP를 반환합니다.