docker compose のサービス名で DNS 解決できない
compose ではサービス名がそのまま DNS 名として解決されるが、別 compose ファイルや depends_on の起動タイミング、network 設定のミスで名前解決が失敗する。
同一ネットワーク所属と起動完了待ちを揃える。
#compose#network#dns#service-name#healthcheck
要約
docker compose 内のサービスは 同じ bridge ネットワークに参加していれば、サービス名がそのまま DNS 名 として解決される。db などに繋がらない場合は、まず 同じ network にいるか と 依存先がもう起動済みか を確認する。
host ネットワーク利用時はそもそも compose の DNS が効かない点にも注意。
よくある原因
- 別ネットワークに居る: 別
compose.yamlで起動したコンテナ同士は、明示しない限り別ネットワークになり名前解決できない - 起動順の油断:
depends_onは起動順を保証するが、プロセスが listen を始めるまで は待ってくれない - host ネットワーク:
network_mode: host配下のコンテナは bridge の DNS テーブルに載らず、サービス名解決ができない - サービス名のアンダースコア:
my_dbは DNS のラベル仕様(RFC 1035)的にグレーで、クライアントによっては解決失敗扱いになる
解決策
1. 同一ネットワークか確認
docker compose ps
docker network inspect <project>_defaultContainers 配下に両方のサービスが居れば OK。
別ファイル間で繋ぐ場合は片方を external ネットワークに参加させる:
networks:
shared:
external: true
services:
api:
networks: [shared]公式のネットワーキングガイド に external network の使い方が記載されている。
2. depends_on で起動完了まで待つ
services:
db:
image: postgres
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 2s
retries: 10
api:
depends_on:
db:
condition: service_healthycondition: service_healthy を指定すると、healthcheck が成功するまで api が起動しない。
3. host ネットワークを避ける
network_mode: host を使うと bridge の DNS が無効になる。
どうしても必要な場合は IP アドレスや host.docker.internal を使うが、原則 bridge を使う方が compose の旨味(サービス名解決)を保てる。
4. サービス名は小文字ハイフン
services:
user-db:
image: postgresアンダースコアを避け、ハイフン区切りか単一単語で命名する。
既存名を変えにくいなら、aliases で別名を付けてクライアントから使う:
services:
my_db:
networks:
default:
aliases: [mydb]