複数のDocker Compose間で通信したい

四角ズボン
2024-06-03
2024-06-03

Dockerのコンテナ間で通信したいとき、1つのComposeの場合は何もしなくてもお互いに通信が可能です。

デフォルトで Compose はアプリに対して1つの ネットワーク を作成します。サービス用の各コンテナはデフォルトのネットワークに接続し、そのネットワーク上で他のコンテナと相互に「 接続可能reachable 」になります。そして、コンテナ名と同じホスト名として、お互いが「 発見可能discoverable 」になります。
https://docs.docker.jp/compose/networking.html

例えば次のようなディレクトリ構成で、 

└─ myapp
       └─  docker-compose.yml

次のようなdocker-compose.yml の場合、web と mysql は「myapp_default」という同じネットワークに属するので、お互いに接続が可能です。

services:
  web:
    build: .
    ports:
      - "8000:8000"
  db:
    image: mysql:5.7
    ports:
      - "3306:3306"

では、別々に起動した Compose を通信したいときにはどうすればよいのでしょうか?

例えば、DBのコンテナを複数の アプリケーションのコンテナで共有したいとして、次のようなディレクトリ構成を考えます。

├─ db
│     └─  docker-compose.yml
├─ myapp1
│     └─  docker-compose.yml
└─ myapp2
     └─  docker-compose.yml

それぞれの docker-compose.yml をいったん、次の通りに設定して実行してみます。

▼db/docker-compose.yml

services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: password
    ports:
        - "3306:3306"

▼myapp1/docker-compose.yml

services:
  web:
    build: .
    ports:
      - "8000:8000"

▼myapp2/docker-compose.yml

services:
  web:
    build: .
    ports:
      - "8001:8000"

この状態で、それぞれの Compose を起動するとそれぞれが別々のネットワークを作成してお互いを認識できないため、通信できません。
作成されたネットワークは「docker network ls」で確認できます。

$ docker network ls
NETWORK ID      NAME                        DRIVER    SCOPE
a4c505e8f4e3    bridge                       bridge      local
bbe260c9a89d   db_default              bridge      local → db のネットワーク
b15d22a5646c   host                           host           local
bbaf91ef68b0    myapp1_default    bridge       local → myapp1 のネットワーク
16beae3cd6ef    myapp2_default    bridge       local → myapp2 のネットワーク
7f8dd4f9431b    none                           null            local

では、myapp1 と myapp2 を db のネットワークに追加して、お互いに通信できるようにします。
myapp1 と myapp2 の docker-compose.yml に networks の設定を追加します。

▼myapp1/docker-compose.yml

services:
  web:
    build: .
    ports:
      - "8000:8000"
    networks:
      - db_default
networks:
  db_default:
    external: true

▼myapp2/docker-compose.yml

services:
  web:
    build: .
    ports:
      - "8001:8000"
    networks:
      - db_default
networks:
  db_default:
    external: true

この状態でそれぞれのディレクトリの下で「docker-compose up -d」を実行してコンテナを更新します。
ネットワークコマンドを実行すると、myapp1_default、myapp2_default は使われていないネットワークとしてが削除されました。

$ docker network prune → 使用していないネットワークを削除
$ docker network ls
NETWORK ID     NAME               DRIVER    SCOPE
a4c505e8f4e3    bridge             bridge      local
6047fe4ba911    db_default    bridge      local 
b15d22a5646c   host                 host          local
7f8dd4f9431b    none                null            local

docker inspect コマンドでネットワークが共有されていることを確認します。
db_default ネットワークに myapp1-web-1、myapp1-web-2 コンテナも含まれていることがわかります。
これでmyapp1 と myapp2 から db への接続が可能になりました。

$ docker network inspect db_default
[
    {
        "Name": "db_default",
        "Id": "bbe260c9a89d48f0243144a82512f01be8026cf2b6c37d7024687ab41480cc30",
        "Created": "2024-03-27T07:23:14.507556133Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "192.168.80.0/20",
                    "Gateway": "192.168.80.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "1fff739dbf386a72e623a3013e73e94d59cc6b4385c813d196d814c08e009732": {
                "Name": "myapp2-web-1",
                "EndpointID": "83d3472fdf744b071adad15b9dcc07cfef250945937445011ffdd7930cd96639",
                "MacAddress": "02:42:c0:a8:50:04",
                "IPv4Address": "192.168.80.4/20",
                "IPv6Address": ""
            },
            "98fe5931d98a32810abdecbb914441b97c3c7ab28dc95ae388b170721f15a4b5": {
                "Name": "myapp1-web-1",
                "EndpointID": "a98a7fee0d91ba111661b70138e245a99e473a337744912665ba847fa885c85e",
                "MacAddress": "02:42:c0:a8:50:03",
                "IPv4Address": "192.168.80.3/20",
                "IPv6Address": ""
            },
            "b302d3d674ec68ff2c643cbcd485131eac1e050a0caa850973050bb3bd82dcfd": {
                "Name": "db-db-1",
                "EndpointID": "3c0c05727fd9aeb519f737cb3c64a680fa9ae8d4ee8c1ad18226ed9f49ba29d5",
                "MacAddress": "02:42:c0:a8:50:02",
                "IPv4Address": "192.168.80.2/20",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "default",
            "com.docker.compose.project": "db",
            "com.docker.compose.version": "2.23.3"
        }
    }
]

おしまい。