도커 네트워크 아키텍처와 컨테이너 간 통신 구성 가이드

Docker0와 가상 네트워크 인터페이스(veth-pair)

리눅스 호스트에 도커를 설치하면 docker0라는 이름의 가상 브리지 네트워크 인터페이스가 자동으로 생성됩니다. 호스트의 네트워크 구성을 확인해 보겠습니다.

$ ip addr show
# 호스트의 루프백 및 물리/가상 네트워크 인터페이스 확인
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 ...
    inet 127.0.0.1/8 scope host lo
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
    inet 10.0.1.15/24 brd 10.0.1.255 scope global eth0
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 ...
    inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0

이제 새로운 컨테이너를 실행하여 네트워크 할당 과정을 관찰해 봅시다.

$ docker run -d --name web-node-1 -P nginx

실행된 컨테이너 내부의 네트워크 인터페이스를 확인합니다.

$ docker exec web-node-1 ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 ...
    inet 127.0.0.1/8 scope host lo
12: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
    inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0

컨테이너에 할당된 IP(172.18.0.2)는 호스트의 docker0 브리지(172.18.0.1)와 동일한 서브넷에 속하므로 서로 ICMP 핑(Ping) 테스트가 가능합니다.

$ ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.065 ms

호스트에서 다시 ip addr을 실행하면 veth로 시작하는 새로운 인터페이스(예: 13: vetha1b2c3d@if12)가 추가된 것을 볼 수 있습니다. 이는 veth-pair(Virtual Ethernet Pair) 기술로, 컨테이너가 생성될 때마다 호스트와 컨테이너를 연결하는 가상 네트워크 케이블 쌍이 자동으로 구성됨을 의미합니다.

레거시 방식: --link 옵션의 한계

과거에는 컨테이너 간 통신 시 IP 주소 대신 이름을 사용하기 위해 --link 옵션을 사용했습니다.

$ docker run -d --name api-server --link web-node-1 nginx
$ docker exec api-server ping web-node-1
PING web-node-1 (172.18.0.2) 56(84) bytes of data.
64 bytes from web-node-1 (172.18.0.2): icmp_seq=1 ttl=64 time=0.088 ms

이 방식은 api-server/etc/hosts 파일에 대상 컨테이너의 IP와 호스트명을 강제로 주입하는 방식입니다. 하지만 역방향 통신(web-node-1에서 api-server로 ping)은 불가능하며, 컨테이너 재시작 시 IP가 변경되면 연결이 끊기는 단점이 있습니다. 현재 도커 공식 문서에서는 이 옵션을 사용하지 말 것을 권고하며, 커스텀 네트워크 사용을 권장합니다.

커스텀 네트워크(Custom Network) 구성

도커는 기본적으로 bridge, host, none 네트워크를 제공합니다. 기본 브리지 네트워크(docker0) 대신 격리된 사용자 정의 네트워크를 생성하면 더 유연한 DNS 이름 확인 기능을 활용할 수 있습니다.

네트워크 생성 및 컨테이너 할당

# 서브넷과 게이트웨이를 지정하여 app-network 생성
$ docker network create --driver bridge --subnet 192.168.100.0/24 --gateway 192.168.100.1 app-network

$ docker network ls
NETWORK ID     NAME           DRIVER    SCOPE
a1b2c3d4e5f6   bridge         bridge    local
f6e5d4c3b2a1   host           host      local
1a2b3c4d5e6f   app-network    bridge    local
9f8e7d6c5b4a   none           null      local

생성한 네트워크에 두 개의 컨테이너를 연결합니다.

$ docker run -d --name frontend-app --network app-network nginx
$ docker run -d --name backend-app --network app-network nginx

양방향 DNS 이름 확인

커스텀 네트워크에 속한 컨테이너들은 내장 DNS 서버를 통해 서로의 이름을 양방향으로 해석할 수 있습니다.

# frontend-app에서 backend-app으로 ping
$ docker exec frontend-app ping backend-app
PING backend-app (192.168.100.3) 56(84) bytes of data.
64 bytes from backend-app.app-network (192.168.100.3): icmp_seq=1 ttl=64 time=0.092 ms

# backend-app에서 frontend-app으로 ping
$ docker exec backend-app ping frontend-app
PING frontend-app (192.168.100.2) 56(84) bytes of data.
64 bytes from frontend-app.app-network (192.168.100.2): icmp_seq=1 ttl=64 time=0.075 ms

서로 다른 네트워크 간 연결(Network Connect)

서로 다른 네트워크에 속한 컨테이너는 기본적으로 통신할 수 없습니다. 예를 들어, app-network에 있는 frontend-app은 기본 bridge 네트워크에 새로 생성된 db-server와 직접 통신할 수 없습니다.

$ docker run -d --name db-server redis
$ docker exec frontend-app ping db-server
ping: db-server: Name or service not known

이를 해결하기 위해 docker network connect 명령어를 사용하여 특정 컨테이너를 다른 네트워크에 추가할 수 있습니다.

# frontend-app을 기본 bridge 네트워크에 추가
$ docker network connect bridge frontend-app

이제 frontend-app은 두 개의 네트워크 인터페이스를 갖게 되며, bridge 네트워크의 IP도 할당받습니다. 하지만 기본 bridge 네트워크는 로컬 DNS 이름 확인을 지원하지 않으므로 IP 주소를 사용해야만 db-server와 통신할 수 있습니다.

$ docker exec frontend-app ping 172.18.0.4
PING 172.18.0.4 (172.18.0.4) 56(84) bytes of data.
64 bytes from 172.18.0.4: icmp_seq=1 ttl=64 time=0.110 ms

반대로, db-serverapp-network에 연결하면 커스텀 네트워크의 DNS 기능을 통해 이름으로 통신이 가능해집니다.

$ docker network connect app-network db-server
$ docker exec db-server ping frontend-app
PING frontend-app (192.168.100.2) 56(84) bytes of data.
64 bytes from frontend-app.app-network (192.168.100.2): icmp_seq=1 ttl=64 time=0.088 ms

docker network connect 명령어를 통해 컨테이너를 다중 네트워크에 참여시키면, 기본 브리지 네트워크의 IP 기반 통신 한계를 넘어 커스텀 네트워크의 내장 DNS를 활용한 이름 기반 라우팅을 구성할 수 있습니다.

태그: docker Networking docker-network veth-pair container-communication

8월 11일 09:08에 게시됨