본문 바로가기
DevOps/Docker

4. Docker Network

by 비어원 2022. 5. 14.
728x90

이번에는 도커의 네트워크 구조에 대하여 알아볼 것이다. 도커 엔진을 설치하면 호스트에 하나의 네트워크 인터페이스가 생긴다. 확인을 위해 먼저 도커 컨테이너를 하나 띄워보자.

$ docker run -it ubuntu:14.04

 

 

컨테이너 내에서 ifconfig 명령어를 입력하면 다음과 같은 결과가 나온다.

root@b98f1051876a:/# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:03
          inet addr:172.17.0.3  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:24 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:2977 (2.9 KB)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
          ...

 

컨테이너에는 lo 인터페이스를 제외하면 eth0이라는 하나의 네트워크 인터페이스가 생긴다. 컨테이너가 생성되면 도커는 컨테이너에 IP를 순차적으로 할당한다. 그리고 컨테이너가 재시작되면 IP가 변경될 수 있다. 이 IP는 호스트의 docker0의 IP 대역대로 생성된다.

 

그리고 이 IP는 도커가 설치된 호스트에서만 쓸 수 있는 IP이므로 외부와 연결될 필요가 있다. 이 과정은 컨테이너를 시작할 때마다 호스트에 veth... 라는 네트워크 인터페이스를 생성함으로써 이루어진다. 일단 생성된 네트워크 인터페이스를 확인하기 위해 호스트에서 ifconfig를 해보자.

 

$ ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:40ff:fecc:6fb7  prefixlen 64  scopeid 0x20<link>
        ether 02:42:40:cc:6f:b7  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 32  bytes 4513 (4.5 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
...

veth71ec46f8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet6 fe80::549d:a3ff:feb1:e2eb  prefixlen 64  scopeid 0x20<link>
        ether 56:9d:a3:b1:e2:eb  txqueuelen 0  (Ethernet)
        RX packets 105  bytes 10974 (10.9 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 138  bytes 23151 (23.1 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

 

 

도커 컨테이너 내부에서 외부로 통신할 때 트래픽이 어떻게 흐르는지 간단히 그림으로 알아보자.

컨테이너 내부의 eth0 인터페이스는 호스트의 veth... 인터페이스와 연결되어있다. 그리고 docker0 은 브릿지 네트워크이며, docker0 브릿지는 각 veth 인터페이스와 바인딩되어 호스트의 eth0 인터페이스와 이어주는 역할을 한다. 그래서 컨테이너 내의 eth0을 통해 호스트의 eth0과 연결될 수 있으며 외부와 통신 할 수 있다.

 

도커 네트워크 기능

컨테이너를 생성하면 기본적으로 docker0 브릿지를 통해 외부와 통신할 수 있지만 사용자의 선택에 따라 여러가지 네트워크 드라이버를 사용할 수도 있다. 도커가 자체적으로 제공하는 드라이버로는 bridge, host, none, container, overlay가 있다. 그 밖에도 플러그인 솔루션 등이 있는데 대표적으로는 flannel 등이 있다.

먼저 도커에서 기본적으로 쓸 수 있는 네트워크가 어떤 것이 있는지 docker network ls 명령어를 통해 알아보자.

$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
02597a202882   bridge    bridge    local
34421255329b   host      host      local
ea3ff580a2f9   none      null      local

 

여기에는 bridge, host, none이 있다. 네트워크의 자세한 정보를 확인하려면 docker network inspect 명령어를 사용하면 된다.

docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "02597a2028828af84013bb279bca585b8d70751edf0dd8c168f0690c4ae1218a",
        "Created": "2022-05-14T17:53:06.86036271+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

 

브릿지 네트워크

기본적으로 제공하는 docker0 말고 다른 브릿지 네트워크를 구성할 수도 있다. 아래 명령어를 통해 새로운 브릿지 네트워크를 생성해보자.

$ docker network create --driver bridge testbridge
a677c0b5124db5119ec3b10aa82f167306ed0c4616c913705e6250f03e728abc

 

호스트에서 ifconfig를 입력하면 새로운 네트워크 인터페이스가 생긴 것을 알 수 있다.

$ ifconfig
br-a677c0b5124d: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.18.0.1  netmask 255.255.0.0  broadcast 172.18.255.255
        inet6 fe80::42:4cff:fe55:ae5d  prefixlen 64  scopeid 0x20<link>
        ether 02:42:4c:55:ae:5d  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 31  bytes 4426 (4.4 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
...

 

네트워크 인터페이스가 172.18.0.0/16 대역으로 할당되었다. 그리고 생성된 브릿지 네트워크를 사용하는 컨테이너를 하나 생성해보자.

$ docker run -it --name network-test \
--net testbridge \
ubuntu:14.04

 

그리고 ifconfig를 해보자.

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:43 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:6233 (6.2 KB)  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:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

 

이전의 docker0 브릿지 네트워크는 172.17.0.0/16 대역이었는데 새로운 브릿지 네트워크로 생성된 컨테이너의 IP는 172.18.0.0/16 대역으로 할당받았다.

 

 

브릿지 네트워크는 구동 중인 컨테이너에게 유동적으로 네트워크를 붙이거나 뗄 수 있다. (disconnect를 시키고 컨테이너에 접속하여 ifconfig를 치면 네트워크 인터페이스가 사라지는 것을 알 수 있다.)

$ docker network disconnect testbridge network-test
$ docker network connect testbridge network-test

 

호스트 네트워크

네트워크를 호스트로 설정하면 호스트의 네트워크 환경을 그대로 사용할 수 있다.

$ docker run -it --name hostnetwork-test \
--net host \
ubuntu:14.04

호스트 네트워크를 사용하는 컨테이너에서 ifconfig를 치면 호스트와 결과가 같게 나온다.

 

논 네트워크

논(none) 네트워크는 말그대로 아무 네트워크를 사용하지 않는다는 것이다. 해당 네트워크로 컨테이너를 생성하면 외부와 연결이 단절된다.

$ docker run -it --name nonnetwork-test \
--net none \
ubuntu:14.04

 

ifconfig를 치면 lo 인터페이스만 나온다.

root@388e886fabb2:/# 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:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

 

 

컨테이너 네트워크

--net 옵션으로 container를 입력하면 다른 컨테이너의 네트워크 네임스페이스 환경을 공유할 수 있다. 공유되는 속성은 내부 IP, 네트워크 인터페이스와 MAC 주소 등이다. (--net container:{shared-container-id})

먼저 컨테이너를 하나 생성해보자.

$ docker run -it \
--name network-container-1 \
ubuntu:14.04

root@024389b49018:/# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:02
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:19 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:2599 (2.5 KB)  TX bytes:0 (0.0 B)

 

그리고 새로운 터미널창에서 컨테이너를 하나 더 생성해보자.

$ docker run -it \
--name network-container-2 \
--net container:network-container-1 \
ubuntu:14.04

root@024389b49018:/# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:02
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:25 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:3130 (3.1 KB)  TX bytes:0 (0.0 B)

 

위와 같이 다른 컨테이너의 네트워크 환경을 공유하면 공유 받을 컨테이너에게는 내부 IP를 새로 할당하지 않고, 이에 대응되는 veth 인터페이스도 생성되지 않는다. 두 컨테이너 모두 IP(172.17.0.2) 와 MAC 주소(02:42:ac:11:00:02)가 동일한 것을 알 수 있다.

 

 

브릿지 네트워크와 alias

브릿지 타입의 네트워크를 사용하는 컨테이너를 생성할 때 --net-alias 옵션을 함께 사용하면 특정 호스트 이름으로 컨테이너 여러 개에 접근할 수 있다. 예를 들어 같은 이름의 net-alias를 가지는 컨테이너 3개를 먼저 생성해보자.

$ docker run -it -d --name net-alias-test1 \
--net testbridge \
--net-alias test-alias \
ubuntu:14.04

$ docker run -it -d --name net-alias-test2 \
--net testbridge \
--net-alias test-alias \
ubuntu:14.04

$ docker run -it -d --name net-alias-test3 \
--net testbridge \
--net-alias test-alias \
ubuntu:14.04

 

그리고 테스트로 ping을 날릴 컨테이너를 하나 생성하자.

$ docker run -it --name ping-test \
--net testbridge \
ubuntu:14.04
root@01f2a3cd6e14:/# ping test-alias
PING test-alias (172.18.0.4) 56(84) bytes of data.
64 bytes from net-alias-test2.testbridge (172.18.0.4): icmp_seq=1 ttl=64 time=0.084 ms

root@01f2a3cd6e14:/# ping test-alias
PING test-alias (172.18.0.5) 56(84) bytes of data.
64 bytes from net-alias-test3.testbridge (172.18.0.5): icmp_seq=1 ttl=64 time=0.148 ms

root@01f2a3cd6e14:/# ping test-alias
PING test-alias (172.18.0.3) 56(84) bytes of data.
64 bytes from net-alias-test1.testbridge (172.18.0.3): icmp_seq=1 ttl=64 time=0.120 ms

 

ping을 여러 번 날리면 매번 다른 주소로 날리는 것을 확인할 수 있다. 이는 무작위로 IP주소가 변경된다. 내부적으로 보면 도커 엔진에 내장된 DNS가 alias-test라는 호스트 이름을 --net-alias 옵션으로 alias-test 를 설정한 컨테이너로 변환해주기 때문이다. 그림으로 나타내면 다음과 같다.

 

--link 옵션도 마찬가지로 도커 내장 DNS를 사용하여 관리된다. 그래서 --link 옵션을 통해 바라보는 컨테이너가 죽고 다시 살아나서 IP가 변경되도 DNS를 통해 별명으로 컨테이너(IP)를 찾을 수 있다.

실제로 IP 리스트를 확인하기 위해 dig라는 도구를 사용해보자. 이 도구는 컨테이너 내부에 설치하면 된다. dig 명령어를 입력할 때 마다 IP 주소 리스트의 순서가 무작위로 변경된다.

root@9933bf9effd4:/# apt-get update
root@9933bf9effd4:/# apt-get install dnsutils -y
root@9933bf9effd4:/# dig test-alias
...
;; ANSWER SECTION:
test-alias.        600    IN    A    172.18.0.3
test-alias.        600    IN    A    172.18.0.2
test-alias.        600    IN    A    172.18.0.4
...

root@9933bf9effd4:/# dig test-alias
...
;; ANSWER SECTION:
test-alias.        600    IN    A    172.18.0.2
test-alias.        600    IN    A    172.18.0.4
test-alias.        600    IN    A    172.18.0.3
...

 

마무리

이번 장에서는 도커 네트워크에 대하여 알아보았다. 다음 장에서는 도커 이미지와 실제로 도커 이미지를 만드는 방법에 대하여 알아보겠다.

728x90

'DevOps > Docker' 카테고리의 다른 글

6. Dockerfile  (0) 2022.05.14
5. Docker Image  (0) 2022.05.14
3. Docker Volume  (0) 2022.04.24
2. Docker Container  (0) 2022.04.24
1. Docker 소개 및 설치  (0) 2022.04.24

댓글