できない.dev

docker compose のサービス名で DNS 解決できない

compose ではサービス名がそのまま DNS 名として解決されるが、別 compose ファイルや depends_on の起動タイミング、network 設定のミスで名前解決が失敗する。
同一ネットワーク所属と起動完了待ちを揃える。

#compose#network#dns#service-name#healthcheck

要約

docker compose 内のサービスは 同じ bridge ネットワークに参加していれば、サービス名がそのまま DNS 名 として解決される。db などに繋がらない場合は、まず 同じ network にいるか依存先がもう起動済みか を確認する。
host ネットワーク利用時はそもそも compose の DNS が効かない点にも注意。

よくある原因

  1. 別ネットワークに居る: 別 compose.yaml で起動したコンテナ同士は、明示しない限り別ネットワークになり名前解決できない
  2. 起動順の油断: depends_on は起動順を保証するが、プロセスが listen を始めるまで は待ってくれない
  3. host ネットワーク: network_mode: host 配下のコンテナは bridge の DNS テーブルに載らず、サービス名解決ができない
  4. サービス名のアンダースコア: my_db は DNS のラベル仕様(RFC 1035)的にグレーで、クライアントによっては解決失敗扱いになる

解決策

1. 同一ネットワークか確認

docker compose ps
docker network inspect <project>_default

Containers 配下に両方のサービスが居れば 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_healthy

condition: 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]

この記事は役立ちましたか?