사용자 정의 브리지 네트워크
도커 네트워크의 기본 브리지 네트워크 외에 사용자 정의 브리지 네트워크를 만들 수 있어요. 사용자 정의 브리지 네트워크는 어떻게 만들고 어떻게 사용하는지, 기본 브리지 네트워크도 있는데 사용자 정의 브리지 네트워크는 왜 필요한지에 대해서 알아봐요.
➜ ~ 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의 인터페이스와 라우팅 테이블도 확인을 해봤어요.
이상.
끝.