Docker Compose 네트워크
Docker Compose는 여러 개의 컨테이너(container)로 구성된 애플리케이션을 관리하기 위한 간단한 오케스트레이션(Orchestration) 도구입니다. 여러 개의 컨테이너로 구성된 Docker Compose 애플리케이션 내에서 컨테이너 간의 통신은 어떻게 이루어질까요?
Docker 네트워크에 대해서 생소하신 분들은 관련 포스팅를 통해 먼저 기본 개념을 파악하시기를 권장드립니다.
Docker Compose 설정법이나 커맨드가 생소하신 분들은 아래 포스팅를 먼저 읽고 돌아오시기를 추천드립니다.
디폴트 네트워크
기본적으로 Docker Compose는 하나의 디폴트 네트워크에 모든 컨테이너를 연결합니다.
디폴트 네트워크의 이름은 docker-compose.yml
가 위치한 디렉토리 이름 뒤에 _default
가 붙습니다.
예를 들어, 디렉토리 이름이 our_app
라면 디폴트 네트워크 이름은 our_app_default
가 됩니다.
디폴트 네트워크의 이름은 Docker Compose로 애플리케이션을 올릴 때 어렵지 않게 확인할 수 있습니다. 왜냐하면 Compose는 먼저 네트워크를 생성해놓고 각 컨테이너를 구동한 후 네트워크에 연결시키기 때문입니다.
$ cd our_app
$ docker-compose up -d
Creating network "our_app_default" with the default driver
Creating our_app_db_1 ... done
Creating our_app_web_1 ... done
Docker Compose로 애플리케이션을 내릴 때는 반대 순서로 먼저 컨테이너를 종료/제거해놓고 제일 마지막에 네트워크를 제거합니다.
$ docker-compose down
Stopping our_app_web_1 ... done
Stopping our_app_db_1 ... done
Removing our_app_web_1 ... done
Removing our_app_db_1 ... done
Removing network our_app_default
애플리케이션이 돌아가고 있는 중에도 Docker 네트워크 목록을 조회하면 디폴트 네트워크가 확인됩니다.
➜ docker network ls
NETWORK ID NAME DRIVER SCOPE
f1859120a0c3 bridge bridge local
95b00551745b host host local
1f7202baa40a none null local
2539640ca106 our_app_default bridge local
컨테이너 간 통신
디폴트 네트워크 안에서 컨테이너 간의 통신에서는 서비스의 이름이 호스트명으로 사용됩니다.
예를 들어, web
서비스의 컨테이너에서 db
서비스의 컨테이너를 대상으로 ping
명령어를 날릴 수 있습니다.
디폴트 네트워크 상에서 db
서비스 컨테이너의 IP가 192.168.48.2
인 것으로 확인이되네요.
$ docker-compose exec web ping db
PING db (192.168.48.2) 56(84) bytes of data.
64 bytes from our_app_db_1.our_app_default (192.168.48.2): icmp_seq=1 ttl=64 time=0.094 ms
64 bytes from our_app_db_1.our_app_default (192.168.48.2): icmp_seq=2 ttl=64 time=0.162 ms
64 bytes from our_app_db_1.our_app_default (192.168.48.2): icmp_seq=3 ttl=64 time=0.080 ms
64 bytes from our_app_db_1.our_app_default (192.168.48.2): icmp_seq=4 ttl=64 time=0.348 ms
64 bytes from our_app_db_1.our_app_default (192.168.48.2): icmp_seq=5 ttl=64 time=0.195 ms
64 bytes from our_app_db_1.our_app_default (192.168.48.2): icmp_seq=6 ttl=64 time=0.187 ms
컨테이넌 간 통신에서 주의할 점은 접속하는 위치가 디폴트 네트워크 내부냐 외부냐에 따라서 포트(port)가 달라질 수 있다는 것입니다.
예를 들어, docker-compose.yml
에 web
서비스의 ports
설정이 아래와 같다면,
services:
web:
build: .
ports:
- "8001:8000"
호스트 컴퓨터에서 접속할 때는 8001
포트를 사용해야 하고, 같은 디폴트 네트워크 내의 다른 컨테이너에서 접속할 때는 포트 8000
을 사용해야 합니다.
- 호스트 컴퓨터에서
web
서비스 컨테이너 접속
$ curl -I localhost:8001
HTTP/1.1 200 OK
Date: Fri, 05 Jun 2020 02:05:10 GMT
Server: WSGIServer/0.2 CPython/3.8.2
Content-Type: text/html
X-Frame-Options: DENY
Content-Length: 16351
X-Content-Type-Options: nosniff
- 같은 네트워크 내의 다른 컨테이너에서
web
서비스 컨테이너 접속
$ docker-compose exec alpine curl -I web:8000
HTTP/1.1 200 OK
Date: Fri, 05 Jun 2020 02:13:46 GMT
Server: WSGIServer/0.2 CPython/3.8.2
Content-Type: text/html
X-Frame-Options: DENY
Content-Length: 16351
X-Content-Type-Options: nosniff
커스텀 네트워크 추가
Docker Compose는 디플트 네트워크 뿐만 아니라 다른 네트워크도 필요에 따라 추가해줄 수 있습니다.
docker-compose.yml
의 networks
항목 아래에 our_net
이라는 네트워크를 추가하고, web
서비스의 networks
항목 아래에 our_net
네트워크를 추가하겠습니다.
이렇게 설정을 하게되면 db
서비스는 디폴트 네트워크에만 연결되지만, web
서비스는 디폴트 네트워크 뿐만 아니라 our_net
네트워크에도 연결되게 됩니다.
services:
web:
build: .
ports:
- "8000:8000"
networks:
- default
- our_net
db:
image: postgres
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
networks:
our_net:
driver: bridge
Docker Compose로 애플리케이션을 올려보면 두 개의 네트워크가 생성되는 것을 알 수 있습니다.
$ docker-compose up -d
Creating network "our_app_default" with the default driver
Creating network "our_app_our_net" with driver "bridge"
Creating our_app_db_1 ... done
Creating our_app_web_1 ... done
$ our_app docker network ls
NETWORK ID NAME DRIVER SCOPE
f1859120a0c3 bridge bridge local
95b00551745b host host local
1f7202baa40a none null local
2682634e6535 our_app_default bridge local
525403b38bbe our_app_our_net bridge local
our_net
은 Docker Compose 내부에서 정의된 네트워크 이므로 애플리케이션을 내릴 때 디폴트 네트워크와 함께 삭제됩니다.
$ docker-compose down
Stopping our_app_web_1 ... done
Stopping our_app_db_1 ... done
Removing our_app_web_1 ... done
Removing our_app_db_1 ... done
Removing network our_app_default
Removing network our_app_our_net
외부 네트워크 사용
Docker Compose가 제공하는 디폴트 네트워크 대신에 외부에서 미리 생성해놓은 다른 네트워크를 사용할 수도 있습니다.
먼저 our_net
이라는 네트워크를 별도로 생성하겠습니다.
$ docker network create our_net
6d791b927c8c151c45a10ac13c62f3571ecf38a90756fd2ca1c62b7d3de804e8
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
f1859120a0c3 bridge bridge local
95b00551745b host host local
1f7202baa40a none null local
6d791b927c8c our_net bridge local
그 다음, docker-compose.yml
에서 default
네트워크의 external
옵션에 our_net
을 설정합니다.
networks:
default:
external:
name: our_net
이제 Docker Compose로 애프리케이션을 올리고, our_net
네트워크의 상세 정보를 확인해보면 Containers
항목에 두 개의 컨테이너가 연결된 것을 볼 수 있습니다.
$ docker-compose up -d
Creating our_app_db_1 ... done
Creating our_app_web_1 ... done
$ docker network inspect our_net
[
{
"Name": "our_net",
"Id": "6d791b927c8c151c45a10ac13c62f3571ecf38a90756fd2ca1c62b7d3de804e8",
"Created": "2020-06-06T15:55:05.3384403Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.208.0/20",
"Gateway": "192.168.208.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"7bcc8194e4018fa48328c6a1aa95a47829c77b850091bebaf1dd6661f5c79df9": {
"Name": "our_app_db_1",
"EndpointID": "4f3ffce8c6afc8d3de543859c1671bfe38b897c6e492a1be891de56ec2dfbf90",
"MacAddress": "02:42:c0:a8:d0:02",
"IPv4Address": "192.168.208.2/20",
"IPv6Address": ""
},
"dda9d355041adc8f90063e8876fe20a2c804b84b55ece3b6860e3dfb139099c7": {
"Name": "our_app_web_1",
"EndpointID": "b0f93bbb39c9eb83d4f286250b90239632667c6b89954d57c9593f32a44c3033",
"MacAddress": "02:42:c0:a8:d0:03",
"IPv4Address": "192.168.208.3/20",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
외부에서 생성된 네트워크이므로 Docker Compose 애플리케이션을 내릴 때 해당 네트워크가 함께 삭제되지 않습니다.
$ docker-compose down
Stopping our_app_web_1 ... done
Stopping our_app_db_1 ... done
Removing our_app_web_1 ... done
Removing our_app_db_1 ... done
Network our_net is external, skipping
외부 네트워크를 잘 활용하면 서로 다른 Docker Compose에서 돌아가고 있는 컨테이너 간에도 연결도 가능하게 됩니다. 예를 들어, 첫 번째 Docker Compose의 디폴트 네트워크를 두 번째 Docker Compose의 커스텀 네트워크로 추가해주면, 두 번째 Docker Compose 내의 컨테이너도 첫 번째 Docker Compose의 디폴트 네트워크에 연결될 수 있습니다.
마치면서
Docker Compose는 디폴트 네트워크를 제공하기 때문에 별도 네트워크 관련 설정 없이도 모든 컨테이너가 연결되어 편리하게 사용할 수 있습니다. 약간의 설정을 통해서 다른 네트워크를 추가하거나 외부 네트워크를 사용하는 것도 가능합니다.