사용자 정의 브리지 네트워크를 생성하고 사용하여 동일한 Docker 호스트에서 실행 중인 컨테이너를 연결하는 방법을 알아보겠습니다.
사용자 정의 브리지 네트워크는 프로덕션 환경에서 실행 중인 독립 실행형 컨테이너에 권장됩니다.
도커에서 사용자 정의 브리지 네트워크(User-defined Bridge Network)는 사용자가 직접 생성한 가상 네트워크입니다. 기본 브리지 네트워크와는 다르게, 사용자 정의 브리지 네트워크는 컨테이너 간 연결을 위해 생성됩니다.
사용자 정의 브리지 네트워크를 생성하면, 해당 네트워크에 컨테이너를 추가하여 통신할 수 있습니다. 이를 통해, 컨테이너 간에 통신할 때 기본 브리지 네트워크보다 더 안전하고 효율적인 방식으로 통신이 가능해집니다.
사용자 정의 브리지 네트워크는 컨테이너에 IP 주소를 할당합니다. 또한, 사용자가 직접 생성한 네트워크이므로, IP 주소 대역, 게이트웨이, DNS 등을 원하는 대로 설정할 수 있습니다. 이를 통해, 컨테이너들이 독립적인 네트워크를 사용하도록 할 수 있습니다.
사용자 정의 브리지 네트워크는 기본 브리지 네트워크와는 달리, 다른 호스트에서 실행된 컨테이너와도 통신이 가능합니다. 이를 위해서는, 컨테이너를 실행할 때 --publish
옵션을 사용하여 포트를 열어주어야 합니다.
사용자 정의 브리지 네트워크는 보안 측면에서도 강화된 네트워크입니다. 사용자가 직접 생성하므로, 다른 네트워크와 분리되어 있으며, 컨테이너 간의 접근 권한을 자유롭게 제어할 수 있습니다. 따라서, 보안 상 이슈가 있는 애플리케이션을 실행할 때에는 사용자 정의 브리지 네트워크를 사용하는 것이 좋습니다.
alpine-net
네트워크 생성$ docker network create --driver bridge alpine-net
네트워크 목록 확인 명령어 입력
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
021082098ff7 alpine-net bridge local
73d8ecc937bd bridge bridge local
bf0b858cf267 host host local
c0ef89f4261f none null local
alpine-net
네트워크 세부사항 확인네트워크 세부사항 확인을 위한 명령어 입력
$ docker network inspect alpine-net
alpine-net
네트워크의 IP 주소를 보여줍니다.
또한 해당 네트워크에 어떤 컨테이너도 연결되어 있지 않음을 확인할 수 있습니다.
기본 브리지 네트워크의 게이트웨이가 172.17.0.1
인 것과 달리 alpine-net
네트워크의 게이트 웨이는 172.21.0.1
입니다.
[참고] 정확한 IP주소는 시스템에 따라 다를 수 있습니다
[
{
"Name": "alpine-net",
"Id": "021082098ff76787340188e22e34cd2495242f5f84507cffd46d529c378aab8e",
"Created": "2023-04-08T08:34:38.216704343Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.21.0.0/16",
"Gateway": "172.21.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
docker run
명령어에 --network
플래그를 사용하여 컨테이너 생성 및 실행 그리고 네트워크 연결을 동시에 수행합니다.docker run
명령어를 사용하는 경우 한번에 하나의 네트워크에만 연결 가능하기 때문에 alpine4
컨테이너의 경우 docker network connect
명령어를 통해 기본 브리지 네트워크에 추가적으로 연결해줍니다.alpine
컨테이너를 alpine-net
이라는 사용자 정의 네트워크에 연결해봅니다. 이 두 개의 컨테이너들은 기본 브리지 네트워크에는 전혀 연결되지 않습니다.alpine3
컨테이너를 실행하여 기본 브리지 네트워크에 연결해볼 것입니다.alpine4
컨테이너는 두 개의 네트워크 모두에 연결합니다.$ docker run -dit --name apline1 --network alpine-net alpine ash # 컨테이너 생성하여 실행 및 alpine-net에 연결
$ docker run -dit --name alpine2 --network alpine-net alpine ash # 컨테이너 생성하여 실행 및 alpine-net에 연결
$ docker run -dit --name alpine3 alpine ash # 컨테이너 생성하여 실행 및 기본 브리지에 연결
$ docker run -dit --name alpine4 --network alpine-net alpine ash # 컨테이너 생성하여 실행 및 alpine-net에 연결
$ docker network connect bridge alpine4 # alpine4 컨테이너는 기본 브리지 네트워크에 연결
명령어 입력
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c61b8279abda alpine "ash" 25 seconds ago Up 24 seconds alpine4
0d1e4c986468 alpine "ash" 50 seconds ago Up 49 seconds alpine3
079c0aa387ac alpine "ash" About a minute ago Up About a minute alpine2
7f8cbce92ecd alpine "ash" About a minute ago Up About a minute alpine1
네트워크를 조사해보도록 하겠습니다.
$ docker network inspect bridge
alpine3
과 alpine4
컨테이너가 연결된 것을 확인할 수 있습니다.[
{
"Name": "bridge",
"Id": "73d8ecc937bd334b444030e26c9f0e2403ea78fa6461165a220149dfdd7b7636",
"Created": "2023-04-06T11:46:10.8301395Z",
"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": {
"0d1e4c986468aeecc6dad3b0207342bd3587178121a6bc61af46d7fb6f55824f": {
"Name": "alpine3",
"EndpointID": "56348c6a3023cb885c30b8bffa11530710e01ed953cc2760f2352c340753e184",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
},
"c61b8279abda50af91e745b120e037a6ba0fc93431889e9b9b854e4d81f95f18": {
"Name": "alpine4",
"EndpointID": "1b2d9a72a33b40c4b758c31c9f948e8602cc79346c75ccd83ac94b48d240d690",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/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": {}
}
]
alpine-net
네트워크 확인$ docker network inspect alpine-net
alpine1
, alpine2
, alpine4
컨테이너가 alpine-net
네트워크에 연결되어 있는 것을 확인할 수 있습니다.[
{
"Name": "alpine-net",
"Id": "021082098ff76787340188e22e34cd2495242f5f84507cffd46d529c378aab8e",
"Created": "2023-04-08T08:34:38.216704343Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.21.0.0/16",
"Gateway": "172.21.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"079c0aa387ac7d79849bc415ae747eae85a8d127ebd83a7c5a8a393c9b992b47": {
"Name": "alpine2",
"EndpointID": "a50ddd3ec569647271bc3f6b7705cc80b92a45f71342f69ad25aa85fdc6b4d81",
"MacAddress": "02:42:ac:15:00:03",
"IPv4Address": "172.21.0.3/16",
"IPv6Address": ""
},
"7f8cbce92ecd6ec861b0a373fdd270db95f4f9ea7878f836c80bca5bfaaff21c": {
"Name": "alpine1",
"EndpointID": "921cc2b3ea2bc0d915420d5b0fa121cbe7d321651645f7db685040f5d2443451",
"MacAddress": "02:42:ac:15:00:02",
"IPv4Address": "172.21.0.2/16",
"IPv6Address": ""
},
"c61b8279abda50af91e745b120e037a6ba0fc93431889e9b9b854e4d81f95f18": {
"Name": "alpine4",
"EndpointID": "a1d50d276449cf49a064fa0e5e65177fd6fe74686f84e38e1598848456e4b317",
"MacAddress": "02:42:ac:15:00:04",
"IPv4Address": "172.21.0.4/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
자동 서비스 검색( automatic service discovery)
alpine-net
과 같은 사용자 정의 네트워크에서 컨테이너는 IP 주소로 통신할 수 있을 뿐만 아니라 컨테이너 이름을 IP 주소로 확인할 수도 있습니다. 이 기능을 자동 서비스 검색( automatic service discovery)이라고 합니다.
명령어를 통해 alpine1
에 접속해보겠습니다.
$ docker container attach alpine1 # alpine1 접속
alpine2
와 alpine4
(그리고 alpine1
자체)에 대한 연결 확인을 해보겠습니다.
alpine1
은 alpine2
와 alpine4
(그리고 alpine1
자체)를 IP 주소로 확인할 수 있어야 합니다.
alpine2
에 핑
# ping -c 2 alpine2
PING alpine2 (172.21.0.3): 56 data bytes
64 bytes from 172.21.0.3: seq=0 ttl=64 time=2.021 ms
64 bytes from 172.21.0.3: seq=1 ttl=64 time=0.466 ms
--- alpine2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.466/1.243/2.021 ms
alpine4
에 핑
# ping -c 2 alpine4
PING alpine4 (172.21.0.4): 56 data bytes
64 bytes from 172.21.0.4: seq=0 ttl=64 time=0.823 ms
64 bytes from 172.21.0.4: seq=1 ttl=64 time=0.327 ms
--- alpine4 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.327/0.575/0.823 ms
alpine1
즉, 자기 스스로 확인
# ping -c 2 alpine1
PING alpine1 (172.21.0.2): 56 data bytes
64 bytes from 172.21.0.2: seq=0 ttl=64 time=0.145 ms
64 bytes from 172.21.0.2: seq=1 ttl=64 time=0.444 ms
--- alpine1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.145/0.294/0.444 ms
alpine3
에 대한 연결 확인
alpine3
은 alpine-net
네트워크에 연결되어 있지 않기 때문에, alpine1
에서는 alpine3
에 연결되어서는 안됩니다.
# ping -c 2 alpine3
잘못된 주소라는 에러 메세지가 확인됩니다.
ping: bad address 'alpine3'
자동 검색 서비스를 통한 컨테이너 이름 연결 뿐만 아니라 IP 주소를 통한 연결 또한 불가능 해야 합니다.
docker network inspect
를 통해 alpine3
의 IP 주소가 172.17.0.2
인 것을 알아낸 후 ping 을 보내봅시다.
IP 주소 172.17.0.2
에 핑
# ping -c 2 172.17.0.2
2 패킷이 전송되었으나 어떤 패킷도 수신되지 않았으며 100%의 패킷 손실이 발생했음을 확인할 수 있습니다.
/ # ping -c 2 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
--- 172.17.0.2 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss
/ #
이번에는 명령어를 통해alpine4
에 접속해 보겠습니다
alpine4
는 기본 브리지 네트워크와 alpine-net
네트워크 모두에 연결되어있습니다. 따라서 다른 모든 컨테이너에서 연결 가능해야 합니다.
$ docker container attach alpine4
alpine1
, alpine2
, alpine4
의 경우 자동 검색 서비스에 의해 컨테이너명으로 연결 가능apine3
의 경우 IP 주소에 의해서만 연결 가능한 점에 유의해야 합니다./ # ping -c 2 alpine1
PING alpine1 (172.21.0.2): 56 data bytes
64 bytes from 172.21.0.2: seq=0 ttl=64 time=0.276 ms
64 bytes from 172.21.0.2: seq=1 ttl=64 time=0.384 ms
--- alpine1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.276/0.330/0.384 ms
/ # ping -c 2 alpine2
PING alpine2 (172.21.0.3): 56 data bytes
64 bytes from 172.21.0.3: seq=0 ttl=64 time=2.338 ms
64 bytes from 172.21.0.3: seq=1 ttl=64 time=0.377 ms
--- alpine2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.377/1.357/2.338 ms
/ # ping -c 2 alpine3
ping: bad address 'alpine3'
/ # ping -c 2 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=1.651 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.424 ms
--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.424/1.037/1.651 ms
/ # ping -c 2 alpine4
PING alpine4 (172.21.0.4): 56 data bytes
64 bytes from 172.21.0.4: seq=0 ttl=64 time=0.125 ms
64 bytes from 172.21.0.4: seq=1 ttl=64 time=0.375 ms
--- alpine4 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.125/0.250/0.375 ms
# ping -c 2 google.com
PING google.com (172.217.3.174): 56 data bytes
64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.778 ms
64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.634 ms
--- google.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 9.634/9.706/9.778 ms
CTRL+p CTRL+q
docker container attach alpine3
# ping -c 2 google.com
PING google.com (172.217.3.174): 56 data bytes
64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.706 ms
64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.851 ms
--- google.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 9.706/9.778/9.851 ms
CTRL+p CTRL+q
docker container attach alpine1
# ping -c 2 google.com
PING google.com (172.217.3.174): 56 data bytes
64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.606 ms
64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.603 ms
--- google.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 9.603/9.604/9.606 ms
분리 시퀀스인 CTRL + p + q
를 사용하여 컨테이너를 중지하지 않고 분리합니다.
alpine-net
네트워크 중지 후 제거$ docker container stop alpine1 alpine2 alpine3 alpine4
$ docker container rm alpine1 alpine2 alpine3 alpine4
$ docker network rm alpine-net