Docker Composeで既存のDockerネットワークにアプリケーションを追加する
今回はちょっとした小ネタです。
最近お仕事でKubernetesよりDockerを多く使っている私です(KubernetesもDockerも好きです)。 これまで、普段Dockerは決めた構成で動かすということしかやってきていませんでした。
具体的にいうと「こういう構成で動かす」と決まってから、そのマニフェストを作って環境作成という感じです。 その場合は必要最低限のマニフェストを記述してdocker compose up -d
を実行すれば、足りない情報はDockerが補って環境を構築してくれるので特にハマることはないです。
一方、もうすでに動いているものに新しいアプリを追加するときはそうはいきません。 ちょっとだけハマったので、その時の話をシェアしたいと思います。
まずはアプリセットを作成
例えば、マニフェストは次のようなディレクトリー構成であると仮定します。
% tree ~/test /Users/ytooyama/test ├── add │ └── docker-compose.yml ├── docker-compose.yml └── web ├── Dockerfile └── nginx.conf
そして、まずはこんなマニフェストでアプリケーションを展開したとします。
services:
web:
build: ./web
ports:
- “80:80”
networks:
- app-network
depends_on:
- db
db:
image: postgres:16.6
environment:
POSTGRES_USER: pguser01
POSTGRES_PASSWORD: strongpg5656#
ports:
- “5432:5432”
networks:
- app-network
volumes:
- postgres-data:/var/lib/postgresql/data
volumes: postgres-data: networks: app-network:
起動してみます。問題なく起動しました。
% docker compose up -d % docker compose ps NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS test-db-1 postgres:16.6 “docker-entrypoint.s…” db 18 seconds ago Up 17 seconds 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp test-web-1 test-web “/docker-entrypoint.…” web 18 seconds ago Up 17 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp
Docker Composeでは書かなかった内容は、適当なランダム名で新規作成されます。今回はボリュームとネットワークの名前は指定したので、その名前でDockerボリュームとDockerネットワークが作成されます。
アプリを既存のネットワークに追加
いよいよ本題です。
前に構築済みのアプリケーションと同じネットワークに、別のアプリケーションをデプロイすることを考えてみます。先ほど何も指定しなかった場合は「ランダム名で新規作成されます」と説明しましたが、もうすでに存在するネットワークに参加させるには、Dockerのドキュメントによるとnetworksに同じネットワークを記述して、external: true
を書けばいいそうです。
このexternal: true
が重要で、これが書かれていないと新しいネットワークを作ろうとします。結果的に指定したネットワークがすでに存在する場合は「ネットワークがすでにある」ようなエラーを吐いて、デプロイに失敗します。
services: yugabyte: image: docker.io/yugabytedb/yugabyte:2024.1.4.0-b108 restart: always command: bin/yugabyted start –background=false ports: - “7000:7000” - “9000:9000” - “15433:15433” - “5433:5433” - “9042:9042” volumes: - yugabyte-store:/root/var/ networks: - app-network
volumes: yugabyte-store: networks: app-network: external: true
マニフェストを実行してみましょう。すると失敗するはずです。
% docker-compose -f ‘add/docker-compose.yml’ up -d –build network app-network declared as external, but could not be found
同じネットワークを指定したのになぜ? まず手元の環境にどのようなネットワークが存在するか確認してみましょう。
test_app-network
というネットワークが作成されています。
% docker network ls NETWORK ID NAME DRIVER SCOPE 2f1483868536 bridge bridge local 0c8447d22df8 host host local ecd7dc18f74b none null local ff09beaaf7ba test_app-network bridge local
ネットワークをinspectしてみます。 実行すると、このネットワークを利用しているコンテナの情報が確認できます。
そのほかにもコンテナをinspectして利用しているネットワークとかネットワークIDから識別する方法もありますが、今回は以下の出力だけでわかるので詳細は割愛します。
% docker network inspect test_app-network … “Containers”: { “c6c79f16c581a94b771124f4252eea637ba614a9073185f46a1b98da2492336e”: { “Name”: “test-db-1”, “EndpointID”: “e56db74a71d7fcb3e3b861db638ef339428432f1b97388a6206c60e48b5bcfba”, “MacAddress”: “02:42:ac:16:00:02”, “IPv4Address”: “172.22.0.2/16”, “IPv6Address”: "" }, “ef31624288fe2688da7c1f393cb36d4bb1339c5e6cf4ad18d32f36e854729494”: { “Name”: “test-web-1”, “EndpointID”: “cec18c9182dc6991916e9c1eecf5a5f59965c91b7ef0a7b11b291c317f154f1d”, “MacAddress”: “02:42:ac:16:00:03”, “IPv4Address”: “172.22.0.3/16”, “IPv6Address”: "" } }, …
コンテナ一覧を見ると、ここにも頭にtest
が。
% docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ef31624288fe test-web “/docker-entrypoint.…” 13 minutes ago Up 13 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp test-web-1 c6c79f16c581 postgres:16.6 “docker-entrypoint.s…” 13 minutes ago Up 13 minutes 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp test-db-1
そうなんです。頭のtestはプロジェクトの上位ディレクトリー名が勝手につきます。 したがって、今回の場合はこう書かないとデプロイに失敗するということです。
services: yugabyte: image: docker.io/yugabytedb/yugabyte:2024.1.4.0-b108 restart: always command: bin/yugabyted start –background=false ports: - “7000:7000” - “9000:9000” - “15433:15433” - “5433:5433” - “9042:9042” volumes: - yugabyte-store:/root/var/ networks: - test_app-network
volumes: yugabyte-store: networks: test_app-network: external: true
実行してみます。add-yugabyte-1
というコンテナーが作られましたね。 頭のaddは上位のディレクトリー名がaddだからです。
% docker-compose -f ‘add/docker-compose.yml’ up -d –build % docker network inspect test_app-network … “Containers”: { “2a9bc7cf4a03d7a73dd9a9480fca0dc75496ea19a4bfd9e219c80b523f6fdfac”: { “Name”: “add-yugabyte-1”, “EndpointID”: “7c8a2b576d5809b867b30fc6d67a387fad34a47b41ce9c0686c30cd30a0d628f”, “MacAddress”: “02:42:ac:16:00:04”, “IPv4Address”: “172.22.0.4/16”, “IPv6Address”: "" }, “c6c79f16c581a94b771124f4252eea637ba614a9073185f46a1b98da2492336e”: { “Name”: “test-db-1”, “EndpointID”: “e56db74a71d7fcb3e3b861db638ef339428432f1b97388a6206c60e48b5bcfba”, “MacAddress”: “02:42:ac:16:00:02”, “IPv4Address”: “172.22.0.2/16”, “IPv6Address”: "" }, “ef31624288fe2688da7c1f393cb36d4bb1339c5e6cf4ad18d32f36e854729494”: { “Name”: “test-web-1”, “EndpointID”: “cec18c9182dc6991916e9c1eecf5a5f59965c91b7ef0a7b11b291c317f154f1d”, “MacAddress”: “02:42:ac:16:00:03”, “IPv4Address”: “172.22.0.3/16”, “IPv6Address”: "" } }, …
というわけでまとめると、
- Docker composeでは、ネットワークの設定を記述していないと適当な名前で新規作成される
- 既存のネットワーク名はアプリケーションの
docker-compose.yml
を参考にするのではなく、docker network ls
で確認しよう - できたら
docker network inspect
で該当のネットワークをどのコンテナが使っているか確認しよう - ディレクトリー名は適当につけるとハマったり恥ずかしい思いをするので注意
- ちなみにこれはDev Containerでも起きるので注意
ということですね。勉強になりました。
ちなみに今回主にGoogleのGeminiに助けられました。
また、external: true
の話はDockerのドキュメントの有志による翻訳サイト様のおかげで理解が深まりました。
ありがとうございます。