사용자 정의 브리지 네트워크

 

도커 네트워크의 기본 브리지 네트워크 외에 사용자 정의 브리지 네트워크를 만들 수 있어요. 사용자 정의 브리지 네트워크는 어떻게 만들고 어떻게 사용하는지, 기본 브리지 네트워크도 있는데 사용자 정의 브리지 네트워크는 왜 필요한지에 대해서 알아봐요.

➜  ~ docker network create xodwknet0 
384b97f3858e56d6d95107b339499c4bc20163bd6f7fdd30fee11ccc37c6ed66

➜  ~ docker network ls 
NETWORK ID     NAME        DRIVER    SCOPE
8d3458727d03   bridge      bridge    local
3bec2ba8f217   host        host      local
3ace32da71f8   none        null      local
384b97f3858e   xodwknet0   bridge    local

➜  ~ docker network inspect xodwknet0 
[
    {
        "Name": "xodwknet0",
        "Id": "384b97f3858e56d6d95107b339499c4bc20163bd6f7fdd30fee11ccc37c6ed66",
        "Created": "2021-08-04T14:35:33.77076691+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.19.0.0/16",
                    "Gateway": "172.19.0.1"
                }
            ]
        },
...
    }
]

docker network create xodwknet0이라는 명령으로 새로운 도커 네트워크를 하나 생성했어요.

docker network ls 명령으로 확인해보니 bridge 모드인 걸 확인했어요. 그리고 서브넷과 게이트웨이도 확인이 가능하네요.

그럼 이제 이번에 생성한 네트워크를 사용해서 컨테이너를 몇 개 만들어볼게요.

➜  ~ docker run -d -it --name showmexodwk0 --network xodwknet0 xodwkx2/show-me-host:2.0.0
a745d1513e863020d2a3e480716557cf187985fad0239d82a24a4e28f9a31475
➜  ~ docker run -d -it --name xodpine0 --network xodwknet0 alpine 
0677c4de5ff7a5445cf6c0420dbcf1e10d72a74978c4bff5112e033460d209ff
➜  ~ docker run -d -it --name xodwkx0 --network xodwknet0 nginx:1.14
8d3e8f60d118f6cd0ab2e7045a6cd007f9394c9941fb10ec26b8cf65540c88db

위와 같이 3개의 컨테이너를 생성하고 다시 네트워크의 상세 사항을 볼게요.

...
"Containers": {
            "77306b7ef7069dca5025ac061bf64c178ddb300bbdcb3627e5d91c3658bc5520": {
                "Name": "xodpine0",
                "EndpointID": "00b425c8f3560769a20575829126c21a8e341d5f9f9f08f349bca09dc3111efe",
                "MacAddress": "02:42:ac:13:00:04",
                "IPv4Address": "172.19.0.4/16",
                "IPv6Address": ""
            },
            "8d3e8f60d118f6cd0ab2e7045a6cd007f9394c9941fb10ec26b8cf65540c88db": {
                "Name": "xodwkx0",
                "EndpointID": "db6db94d7d79a32d1e19f52545f944b0681a4e8b10a723c125517fe149893e3b",
                "MacAddress": "02:42:ac:13:00:03",
                "IPv4Address": "172.19.0.3/16",
                "IPv6Address": ""
            },
            "a745d1513e863020d2a3e480716557cf187985fad0239d82a24a4e28f9a31475": {
                "Name": "showmexodwk0",
                "EndpointID": "fc2f578614fd4c40445287525d1151c88dbcd9bb7ffa158d6d4f7b969ea56abf",
                "MacAddress": "02:42:ac:13:00:02",
                "IPv4Address": "172.19.0.2/16",
                "IPv6Address": ""
            }
        },
...

Containers에 위와 같이 생성한 컨테이너들이 잘 들어간 게 확인되네요.

이제 alpine 컨테이너에 접속해볼게요.

그리고 curl 명령어가 없으니까 설치할게요.

➜  ~ docker exec -it xodpine0 sh      
/ # apk add curl
OK: 8 MiB in 19 packages
/ #

위에서 보는 것과 같이 각각 컨테이너의 IP를 확인했으니 정상적으로 응답을 잘 주는지 확인해볼게요.

/ # curl -I 172.19.0.3
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Wed, 04 Aug 2021 05:50:08 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 04 Dec 2018 14:44:49 GMT
Connection: keep-alive
ETag: "5c0692e1-264"
Accept-Ranges: bytes

/ # curl 172.19.0.2:8080
Your app is running on Host: a745d1513e86
/ #

 

이렇게 기본 브리지 네트워크처럼 사용할 수 있어요.

그러면 왜 기본 브리지 네트워크를 두고 사용자 정의 브리지 네트워크를 만들어서 써야 할까요?

어떤 이점이 있을까요?

 

이번에는 위에서 컨테이너를 만들 때 넣어준 이름 --name 값을 가지고 curl 명령을 실행해볼게요.

/ # curl -I xodwkx0
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Wed, 04 Aug 2021 05:57:49 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 04 Dec 2018 14:44:49 GMT
Connection: keep-alive
ETag: "5c0692e1-264"
Accept-Ranges: bytes

/ # curl showmexodwk0:8080
Your app is running on Host: a745d1513e86
/ #

워메. nginx로 만든 xodwkx0에서도 200 OK가 잘 떨어지고

show-me-host로 만든 showmexodwk0에서도 8080 포트로 서비스가 잘 되네요.

 

도커가 몰래 /etc/hosts에 넣어놨는지 확인해봐요.

/ # cat /etc/hosts 
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.19.0.4      77306b7ef706
/ #

없어요. 그럼 dns 한 번 체크해볼까요?

/ # nslookup xodwkx0
Server:         127.0.0.11
Address:        127.0.0.11:53

Non-authoritative answer:
*** Can't find xodwkx0: No answer

Non-authoritative answer:
Name:   xodwkx0
Address: 172.19.0.3

/ # nslookup showmexodwk0 
Server:         127.0.0.11
Address:        127.0.0.11:53

Non-authoritative answer:
*** Can't find showmexodwk0: No answer

Non-authoritative answer:
Name:   showmexodwk0
Address: 172.19.0.2

/ #

공식문서에서는 default bridge network와 user-defined bridge network의 차이점 중 하나로

사용자 정의 브리지 네트워크에서는 컨테이너들 간에 automatic DNS resolution을 지원한다고 나오네요.

 

이제 도커 HOST에서 ip a 명령어를 실행해보면 새로운 브리지 인터페이스가 하나 생성된 것을 확인할 수 있어요.

..
158: br-384b97f3858e: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:63:8f:69:6f brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.1/16 brd 172.19.255.255 scope global br-384b97f3858e
       valid_lft forever preferred_lft forever
    inet6 fe80::42:63ff:fe8f:696f/64 scope link 
       valid_lft forever preferred_lft forever
...

iptables에서도 새로 추가된 PREROUTE 정책을 확인할 수 있어요.

...
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.19.0.0/16        0.0.0.0/0           
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0           
...

 

사용자 정의 브리지 네트워크는 만들 때 여러 가지 옵션을 줄 수 있어요.

계속 /16만 쓰다 보면 언젠가는 쓸 대역대가 모자랄 수 있겠어요. 소박하게 /24 네트워크를 하나 더 만들고 확인해봐요.

➜  ~ docker network create --subnet 172.20.10.0/24 --ip-range 172.20.10.0/24 --gateway 172.20.10.1 xodwknet10
06c96cf0b3c5fa49e0e2c7dfdaeca7e29038a65fe13f546c20781d110a777f32
➜  ~ docker network ls 
NETWORK ID     NAME         DRIVER    SCOPE
8d3458727d03   bridge       bridge    local
3bec2ba8f217   host         host      local
3ace32da71f8   none         null      local
384b97f3858e   xodwknet0    bridge    local
06c96cf0b3c5   xodwknet10   bridge    local

➜  ~ docker network inspect xodwknet10 
[
    {
        "Name": "xodwknet10",
        "Id": "06c96cf0b3c5fa49e0e2c7dfdaeca7e29038a65fe13f546c20781d110a777f32",
        "Created": "2021-08-04T15:33:47.301296048+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.20.10.0/24",
                    "IPRange": "172.20.10.0/24",
                    "Gateway": "172.20.10.1"
                }
            ]
        },
...
    }
]

소박하게 24비트짜리 네트워크를 하나 생성해봤어요.

기념으로 여기에 show-me-host 컨테이너 하나 생성하고 할당받는 IP를 한 번 확인해볼게요.

➜  ~ docker run -d -it --name showmexodwk10 --network xodwknet10 xodwkx2/show-me-host:1.0.0
5f47ac12b23211eb73bd10391d93c79c0976ec4acfdc4ba41c8b2eecf3366221

➜  ~ docker exec showmexodwk10 ip a 
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
169: eth0@if170: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:14:0a:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.20.10.2/24 brd 172.20.10.255 scope global eth0
       valid_lft forever preferred_lft forever
       
➜  ~ curl showmexodwk10:8080        
curl: (6) Could not resolve host: showmexodwk10; Unknown error

➜  ~ curl 172.20.10.2:8080
5f47ac12b232

아... 저 컨테이넌 이름은 같은 네트워크 안에 있는 호스트끼리만 사용할 수 있나 봐요.

그러면 저 위에서 만들었던 xodwknet0에서는 어떨까요?

➜  ~ docker exec xodpine0 ping -c 4 showmexodwk10 
ping: bad address 'showmexodwk10'

➜  ~ docker exec xodpine0 nslookup showmexodwk10 
Server:         127.0.0.11
Address:        127.0.0.11:53

** server can't find showmexodwk10: NXDOMAIN

** server can't find showmexodwk10: NXDOMAIN

➜  ~ docker exec xodpine0 ping 172.20.10.2  
PING 172.20.10.2 (172.20.10.2): 56 data bytes
^C

각각의 사용자 정의 브리지 네트워크는 완벽하게 분리되어있네요.

그런데 alpine 컨테이너에서는 xodwknet10 네트워크와도 통신했으면 좋겠어요. xodwknet10 네트워크에 xodpine0 컨테이너를 붙여보도록 할게요.

➜  ~ docker network connect xodwknet10 xodpine0

➜  ~ docker network inspect xodwknet10 
...
        "Containers": {
            "5f47ac12b23211eb73bd10391d93c79c0976ec4acfdc4ba41c8b2eecf3366221": {
                "Name": "showmexodwk10",
                "EndpointID": "f52ae56d4ec941c8c675d31aac0613c26f2c59adf53997fea2f48994f2f5e6a4",
                "MacAddress": "02:42:ac:14:0a:02",
                "IPv4Address": "172.20.10.2/24",
                "IPv6Address": ""
            },
            "77306b7ef7069dca5025ac061bf64c178ddb300bbdcb3627e5d91c3658bc5520": {
                "Name": "xodpine0",
                "EndpointID": "ac76c1c38a121e5a10e2bec20d2c7e8eac7c5c9bc95f9832476d0a24ef33ca22",
                "MacAddress": "02:42:ac:14:0a:03",
                "IPv4Address": "172.20.10.3/24",
                "IPv6Address": ""
            }
        },
...
    }
]

 

그럼 확인을 다시 해볼게요.

➜  ~ docker exec xodpine0 ping showmexodwk0 -c 4 
PING showmexodwk0 (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.144 ms
64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.139 ms
64 bytes from 172.19.0.2: seq=2 ttl=64 time=0.113 ms
64 bytes from 172.19.0.2: seq=3 ttl=64 time=0.098 ms

--- showmexodwk0 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.098/0.123/0.144 ms

➜  ~ docker exec xodpine0 ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
165: eth0@if166: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:13:00:04 brd ff:ff:ff:ff:ff:ff
    inet 172.19.0.4/16 brd 172.19.255.255 scope global eth0
       valid_lft forever preferred_lft forever
171: eth1@if172: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:14:0a:03 brd ff:ff:ff:ff:ff:ff
    inet 172.20.10.3/24 brd 172.20.10.255 scope global eth1
       valid_lft forever preferred_lft forever
       
➜  ~ docker exec xodpine0 ip route
default via 172.19.0.1 dev eth0 
172.19.0.0/16 dev eth0 scope link  src 172.19.0.4 
172.20.10.0/24 dev eth1 scope link  src 172.20.10.3

dns resolve도 잘 동작하는 것 같아요. xodpine0의 인터페이스와 라우팅 테이블도 확인을 해봤어요.

 

이상.

 

끝.