takaha.siの技術メモ

勉強したことをお伝えします。ちょっとでも誰かの役に立てればいいな…

docker-composeで作ったコンテナ同士をネットワークでつなげる

github.com

ファイルはここに。

f:id:tkh86:20220325011310p:plain
複数Docker間で通信

図のようにdockerコンテナを2つ(図中のmy_clientとmy_server)つくって、それらコンテナ間で通信したい。

単一のdocker-compose.ymlの中に2つ以上のコンテナが定義されてる場合は別に問題ない。同一ymlファイル内部でコンテナの名前がホスト名として使えるので、それを指定して通信できる。単一のymlファイルに定義されたDockerコンテナはすべて同一ネットワーク(Bridge)に所属できるのでコンテナ間通信ができるわけ。

問題はこれら2つのdockerコンテナが別々のdocker-compose.ymlファイルで定義されてるとき。この場合は、自分で独自のネットワーク(図中のmy_network)を構築した上で、接続したいコンテナをその独自ネットワーク(my_network)に所属させる必要があります。それで、コンテナ同士が接続がコンテナ名をホスト名として相互に通信できます。

(ちなみにBridgeとは、コンテナ内部のみで通信できるNATみたいなものが生成されて、そのNATネットワーク内部でコンテナが動く。BridgeなのにNATとはこれ如何に?)

ネットワークはdocker-compose upする前に自分で生成しときましょう。以下のように:

#!/bin/sh

# make a network
docker network create --driver bridge my_network

cd ./client && docker-compose -f docker-compose.yml up -d
cd -
cd ./server && docker-compose -f docker-compose.yml up -d

こんな感じで。docker-compose.ymlファイルは以下の2つ。

version: '3.8'
services:
  my_client:
    build:
      context: ./
      dockerfile: Dockerfile
    networks:
      - my_network

networks:
  my_network:
    external: true
version: '3.8'
services:
  my_server:
    build:
      context: ./
      dockerfile: Dockerfile
    networks:
      - my_network

networks:
  my_network:
    external: true

これでmy_clientコンテナに入って通信してみましょう。

kazushi@dev2:~$ docker ps
CONTAINER ID   IMAGE              COMMAND                  CREATED          STATUS          PORTS     NAMES
62af57565a5a   server_my_server   "/bin/sh -c 'while :…"   35 minutes ago   Up 35 minutes             server-my_server-1
7adf566c7103   client_my_client   "/bin/sh -c 'while :…"   35 minutes ago   Up 35 minutes             client-my_client-1
kazushi@dev2:~$ docker exec -it 7adf566c7103 /bin/bash
root@7adf566c7103:/client#
root@7adf566c7103:/client# ping my_server
PING my_server (172.25.0.3) 56(84) bytes of data.
64 bytes from server-my_server-1.my_network (172.25.0.3): icmp_seq=1 ttl=64 time=0.043 ms
64 bytes from server-my_server-1.my_network (172.25.0.3): icmp_seq=2 ttl=64 time=0.048 ms
64 bytes from server-my_server-1.my_network (172.25.0.3): icmp_seq=3 ttl=64 time=0.047 ms
64 bytes from server-my_server-1.my_network (172.25.0.3): icmp_seq=4 ttl=64 time=0.047 ms
64 bytes from server-my_server-1.my_network (172.25.0.3): icmp_seq=5 ttl=64 time=0.048 ms
64 bytes from server-my_server-1.my_network (172.25.0.3): icmp_seq=6 ttl=64 time=0.037 ms
64 bytes from server-my_server-1.my_network (172.25.0.3): icmp_seq=7 ttl=64 time=0.047 ms
64 bytes from server-my_server-1.my_network (172.25.0.3): icmp_seq=8 ttl=64 time=0.047 ms

--- my_server ping statistics ---
8 packets transmitted, 8 received, 0% packet loss, time 7162ms
rtt min/avg/max/mdev = 0.037/0.045/0.048/0.003 ms
root@7adf566c7103:/client#

通信できてますねping my_serverで通信できます。

external: trueの意味

ちなみのymlファイル内に記述されてるexternal: trueの意味ですが、docker-composeですでに作成済みのnetworkを再利用するときはtrueを指定します。するとdocker-compose -f docker-compose.yml upのときに通常生成される独自ネットワーク(Bridge)が生成されず、あり物のmy_networkを探して使用するようになります。逆言うと、my_networkが作られてない場合はエラーが出てコンテナが起動しません。上述したように事前にdocker network create --driver bridge my_networkで作っておきましょう。