도커 네트워크

도커 네트워크

도커에서 제공하는 대표적인인 네트워크 드라이버로는 호스트(host), 브리지(bridge), 사용안함(none) 등이 있습니다.

$ docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
d4c7abefb75d        bridge              bridge              local
8c897fb9e7da        host                host                local
9fb15fe19162        none                null                local

도커의 기본 네티워크 모드는 bridge 입니다. 만약 다른 모드를 사용하여 컨테이너를 생성하고 싶다면 --net 을 이용하여 설정할 수 있습니다.

docker run --net=<NETWORK>

도커를 설치하면, 기본적으로 docker0 이라는 가상 브리지(bridge)가 생성 됩니다.

$ ifconfig

...
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:6c:3d:0f:04  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
$ ip addr

...
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:6c:3d:0f:04 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever

이 브리지는 컨테이너를 기본 브리지 모드로 실행할 때 사용되면, CIRD 표기법으로 172.17.0.1/16 의 주소 범위를 가지고 있습니다. 172.17.0.1 부터 172.17.255.254 까지의 아이피를 사용할 수 있습니다. 그래서 컨테이너가 기본 브리지 모드로 실행될 때, 해당 범위에서 아이피를 할당받습니다.

만약 이 범위를 변경하고 싶다면, 도커 설정 파일인 /etc/docker/daemon.json"bip" 항목을 추가 하면 됩니다.


Bridge Mode Networking

Docker는 연결된 다른 네트워크 인터페이스 간에 패킷을 자동으로 전달하는 가상 이더넷 브리지인 docker0을 생성합니다. 기본적으로 호스트의 모든 컨테이너는 이 브리지를 이용하여 내부 네트워크에 연결이 됩니다. 이 모드는 컨테이너를 분리된 네트워크 네임스페이스에 배치하고, 네트워크 주소 변환을 사용하여 여러 컨테이너 간에 호스트의 외부 IP 주소를 공유합니다.

브리지 모드 네트워킹은 동일한 호스트에서 여러 컨테이너를 실행할 때 네트워크 포트 충돌을 일으키지 않습니다. 즉, 동일한 포트를 사용하는 다수의 컨테이너를 하나의 호스트에서 실행할 수 있습니다. 각 컨테이너는 호스트와 분리된 전용 네트워크 네임스페이스를 소유하고 있습니다. 그래서 이 모드는 NAT의 사용으로 인해 네트워크 처리량과 지연 시간에 영향을 미치고, 호스트와 컨테이너 간의 네트워크 포트 매핑을 제어해야하는 단점이 있습니다.

컨테이너가 생성되면, 해당 컨테이너를 위해서 페어 인터페이스(pair interfaces)가 생성됩니다. 이 인터페이스들은 두 개가 한 쌍으로 구성되어 있는데, 마치 직접 연결된 것 처럼 서로 패킷을 주고 받습니다.

컨테이너가 생성되면, 페어 인터페이스의 한쪽은 컨테이너 내부 네임스페이스에 eth0 이라는 이름으로 할당됩니다. 나머자 하나는 vethXXXX 라는 이름으로 docker0 브리지에 바인딩 됩니다.

컨테이너를 실행할 때 브리지 네트워킹 모드를 사용하려면 별다른 설정을 추가할 필요 없습니다. 기본값이 브리지 네트워킹 모드이기 때문입니다.

docker run -i -t --rm --name network_bridge ubuntu:18.04

정상적으로 실행되면, 쉘이 나타나고, 명령어를 입력할 수 있습니다. 우분투 이미지에서 네트워크 관련 도구가 설치되어 있지 않기 때문에, 필요한 도구들을 설치해 줍니다.

apt-get update
apt-get install net-tools
apt-get install iproute2
root@6a5f6efd7f52:/# ifconfig

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 3899  bytes 19574414 (19.5 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3318  bytes 224386 (224.3 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
root@6a5f6efd7f52:/# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

컨테이너 내부의 eth0 인터페이스의 번호가 4번인것을 확인 할 수 있습니다.

새로운 터미널을 열어서, 호스트에서 인터페이스를 조회해 보겠습니다.

root@magi:~# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:15:5d:15:0e:00 brd ff:ff:ff:ff:ff:ff
    inet 192.168.21.39/24 brd 192.168.21.255 scope global dynamic eth0
       valid_lft 4714sec preferred_lft 4714sec
    inet6 fe80::215:5dff:fe15:e00/64 scope link
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:6c:3d:0f:04 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:6cff:fe3d:f04/64 scope link
       valid_lft forever preferred_lft forever
5: vethab05419@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether 96:0e:66:36:cd:d0 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::940e:66ff:fe36:cdd0/64 scope link
       valid_lft forever preferred_lft forever

vethab05419 라는 새로운 인터페이스 생성된 것을 확인할 수 있습니다. vethab05419 와 컨테이너안의 eth0 인터페이스가 맺어져 있다는 것을 ethtool 을 이용하여 확인할 수 있습니다.

root@magi:~# ethtool -S vethab05419

NIC statistics:
     peer_ifindex: 4

peer_ifindex 가 4로 설정되어 있습니다. 앞서 컨테이너 안에서 확인한 eth0 인터페이스의 번호인 것을 알 수 있습니다.

컨테이너 게이트웨이

컨테이너의 게이트웨이를 확인해 보겠습니다. 컨테이너 안에서 route 명령어를 실행합니다.

root@6a5f6efd7f52:/# route

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

출력된 결과처럼 컨테이너 내부의 모든 패킷은 default 인 172.17.0.1 로 가게 됩니다. 이 주소는 docker0 의 IP 입니다.

브리지 모드에 대한 자세한 정보를 얻고 싶다면, 다음과 같이 확인할 수 있습니다.

docker network inspect bridge

[
    {
        "Name": "bridge",
        "Id": "022cf8e85d00a623504732098d6c99f3a6bf74fbd632787b4d3bf70a1ad03256",
        "Created": "2020-07-28T11:56:57.739214Z",
        "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": {
            "6a5f6efd7f5235d46d1ae332b003566494bb0e0255bf5edc05899b2e7c71191b": {
                "Name": "network_bridge",
                "EndpointID": "53666d16b8a932aaef1f241535ae2944758ad40cbbddb923d1a1621a286b3e2e",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "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": {}
    }
]

브리지 생성하기

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

docker network create --driver bridge <브리지 이름>

다음은 mybridge 라는 이름의 브리지를 생성하는 예제입니다.

docker network create --driver bridge mybridge 

생성한 브리지는 컨테이너를 실행할 때 --net 설정을 통해 사용할 수 있습니다.

docker run -i -t --name mybridge_container --net mybrdige ubuntu:18.04

Host Mode Networking

호스트 모드는 컨테이너가 호스트의 네트워킹 네임스페이스를 공유하고 있으며, 외부 네트워크에 직접 노출됩니다. 호스트의 IP 주소와 호스트의 TCP 포트 공간을 사용하여, 컨테이너 내부에서 실행 중인 서비스를 노출합니다.

컨테이너를 실행할 때 호스트 네트워킹 모드를 사용하려면 다음과 같이 --net=host 라고 설정하면 됩니다.

$ docker run -i -t --rm --net=host --name network_host ubuntu:18.04

이 네트워킹 모드는 간단하기 때문에, 개발자가 이해하기 쉽고, 사용하기 쉽습니다. 하지만 호스트 네트워크를 그대로 사용하기 때문에 동일한 네트워크 포트를 사용할 경우 충돌이 발생합니다. 동일한 포트를 사용하는 다수의 컨테이너를 하나의 호스트에서 실행할 경우, 포트 충돌이 발생하여 서비스가 시작되지 않을 수 있습니다.

apt-get update
apt-get install net-tools
apt-get install iproute2
root@docker-desktop:/# 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:e3ff:fe89:ac76  prefixlen 64  scopeid 0x20<link>
        ether 02:42:e3:89:ac:76  txqueuelen 0  (Ethernet)
        RX packets 6303  bytes 257694 (257.6 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 13671  bytes 20016034 (20.0 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.65.3  netmask 255.255.255.0  broadcast 192.168.65.255
        inet6 fe80::50:ff:fe00:1  prefixlen 64  scopeid 0x20<link>
        ether 02:50:00:00:00:01  txqueuelen 1000  (Ethernet)
        RX packets 146158  bytes 147055882 (147.0 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 77952  bytes 6736462 (6.7 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 2  bytes 140 (140.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2  bytes 140 (140.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

호스트 모드에 대한 자세한 정보를 얻고 싶다면, 다음과 같이 확인할 수 있습니다.

docker network inspect host

[
    {
        "Name": "host",
        "Id": "8c897fb9e7da39ec5c0cbceaf25935d9fd32cd9cca5eea5a665085eb7a793070",
        "Created": "2019-01-04T16:21:19.013894618Z",
        "Scope": "local",
        "Driver": "host",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": []
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

None Mode Networking

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

docker run -i -t --rm --name network_none --net none ubuntu:18.04


Container Mode Networking

컨테이너 네트워크를 사용하면, 다른 컨테이너의 네트워크 환경을 공유할 수 있습니다.

--net container:<다른 컨테이너 이름 또는 아이디>
docker run -i -t --rm --name network_container_1 ubuntu:18.04

root@1fae52d25cbd:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 26111  bytes 38303216 (38.3 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 9567  bytes 526098 (526.0 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

다음과 같이 ifconfig 명령을 실행해보면, 동일한 네트워크를 사용하고 있다는 것을 확인할 수 있습니다.

docker run -i -t --rm --name network_container_2 --net container:network_container_1  ubuntu:18.04

root@1fae52d25cbd:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 13034  bytes 19150595 (19.1 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 4542  bytes 250008 (250.0 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다