Docker Composeで「dial tcp: lookup db on 127.0.0.1:53: no such host」を修正する

intermediate🐳 Docker2026-04-22| Docker 20.10+、Docker Compose v2、Linux/macOS/Windows WSL2

Error Message

dial tcp: lookup db on 127.0.0.1:53: no such host
#docker-compose#networking#dns#localhost

状況

深夜2時、アプリコンテナが数秒おきにこのエラーを吐き続けている:

dial tcp: lookup db on 127.0.0.1:53: no such host

docker-compose.yml には db という名前のサービスがある。アプリが明らかにそこへ接続しようとしている。DBコンテナは起動中だ — 確認済みだ。では何が起きているのか?

端的に言うと、アプリコンテナが 127.0.0.1:53 をDNSサーバーとして使っている。これはホストマシンのループバックリゾルバーであり、DockerのインターナルDNSではない。Dockerのサービス名前解決は、127.0.0.11 にある独自の組み込みDNSを経由する。ホストのリゾルバーは db というホスト名を知らないため、即座に失敗する。

これはコンテナがDockerマネージドネットワークに属していない場合、またはDNS設定が壊れた場合に発生する。いずれにしてもシステムリゾルバーにフォールバックするが、システム側は db が何を意味するか一切知らない。

デバッグ手順

ステップ1:両コンテナが同じネットワーク上にいるか確認する

十中八九、これが原因だ。以下を実行する:

docker network ls
docker inspect <your_container_name> | grep -A 20 '"Networks"'

Networks セクションを確認する。アプリコンテナが bridge(デフォルトのレガシーネットワーク)で、DBが myapp_default にいる場合、両者は互いに隔離されている — 異なるネットワーク間ではサービス名は解決できない。

ステップ2:DockerのインターナルDNSが使われているか検証する

アプリコンテナの中に入って確認する:

docker exec -it <app_container> cat /etc/resolv.conf

正常なDockerコンテナは以下を表示するはずだ:

nameserver 127.0.0.11
options ndots:0

nameserver 127.0.0.18.8.8.8 のようなパブリックリゾルバーが表示される場合、DockerのDNSが機能していない。これはコンテナが --network host で実行されているか、ユーザー定義ネットワークにアタッチされていない場合に発生する。

ステップ3:名前解決を手動でテストする

docker exec -it <app_container> nslookup db
docker exec -it <app_container> ping db

nslookup が失敗するがDBコンテナは起動中?ネットワークのアタッチ問題だ。アプリの設定問題ではない。

解決策

解決策1:両サービスを同じ名前付きネットワークに配置する(Docker Compose)

まずここから始める — これでケースの90%が解決する。docker-compose.yml に記述する:

services:
  app:
    build: .
    networks:
      - backend
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/mydb

  db:
    image: postgres:15
    networks:
      - backend

networks:
  backend:
    driver: bridge

両サービスが同じComposeファイルに存在し、明示的なネットワーク設定がない場合、Docker Composeは自動的に <project>_default という共有ネットワークを作成し、全てのサービスをそこに配置する。サービス名は自動的に解決される。追加設定は不要だ。

このエラーが発生するのは以下のケースだ:

  • 一方のサービスには networks: を設定したが、もう一方を忘れた場合
  • 一方のコンテナをComposeではなく docker run で手動起動した場合
  • 異なるプロジェクトネットワーク上のサービスを持つ複数のComposeファイルがある場合

解決策2:手動起動コンテナをComposeネットワークに接続する

DBがComposeスタックに存在する中、アプリを docker run で起動した場合は接続する:

# ネットワーク名を確認する
docker network ls

# スタンドアロンコンテナを接続する
docker network connect myproject_default <app_container_name>

再起動は不要だ。接続直後からサービス名の解決が機能し始める。

解決策3:--network host をやめる

--network host はコンテナにホストのネットワークスタック全体を共有させる。DockerのインターナルDNSは適用されない。サービス名は一切解決できなくなる。

ホストネットワーキングが本当に必要な場合(rawソケット、ハードウェアアクセス、非常に特殊なポートバインドのシナリオ)を除いて、削除する:

# 誤り
docker run --network host myapp

# 正解 — 名前付きネットワークを使う
docker run --network myproject_default myapp

解決策4:複数のComposeファイル — 共有外部ネットワークを作成する

相互通信が必要な別々のComposeスタックを実行している場合は、共有ネットワークを明示的に定義する:

# DBスタック側(docker-compose.db.yml)
networks:
  shared:
    name: shared_backend
    driver: bridge
# アプリスタック側(docker-compose.app.yml)
networks:
  shared:
    external: true
    name: shared_backend

これで両スタックが同じネットワークを共有する。追加のトリックなしでスタック間のサービス名が解決される。

確認

修正が反映されたか確認するために以下を実行する:

# コンテナが正しいネットワーク上にいるか確認する
docker inspect <app_container> | grep -A 5 '"Networks"'

# Docker DNSがアクティブか確認する
docker exec -it <app_container> cat /etc/resolv.conf
# 表示されるべき内容: nameserver 127.0.0.11

# 名前解決をテストする
docker exec -it <app_container> nslookup db
# 172.18.0.x のような内部IPに解決されるはずだ

nslookup db がIPを返すなら問題ない。アプリでまだエラーが出る場合はアプリコンテナを再起動する — 一部のランタイム(特にGoやJavaのアプリ)はDNS失敗をメモリにキャッシュするため、プロセスが再起動するまで再試行しない。

ヒント:サブネットの衝突をデバッグする

DNSは解決できたが接続がまだ失敗する場合は、サブネットの衝突を確認する。DockerはCIDRレンジを自動的に選択するが、VPNやオフィスネットワークと重複してルーティングが完全に壊れることがある。ネットワークのサブネットを確認する:

docker network inspect <network_name> | grep Subnet

よくある原因:Dockerが 172.17.0.0/16 をデフォルトに選ぶ一方、VPNが同じレンジを使っている場合だ。Composeファイルでカスタムサブネットを固定して衝突を回避する:

networks:
  backend:
    driver: bridge
    ipam:
      config:
        - subnet: 10.50.0.0/24

どのアドレスがどのサブネットに属するかを調べる際は、ToolCraftのサブネット計算機を使っている — ブラウザベースで、ブロードキャストアドレス、使用可能なレンジ、ワイルドカードマスクを外部通信なしで表示してくれる。

得られた教訓

  • サービス名のDNSはユーザー定義ネットワーク上でのみ機能する。 デフォルトの bridge ネットワークはサービスディスカバリーをサポートしない。Composeでは必ずネットワークに名前を付けること。
  • docker rundocker compose の混用は、気づかないうちにこの問題を引き起こす。 手動で起動したコンテナは自動的にComposeネットワークに参加しない。docker network connect で手動接続する必要がある。
  • --network host は大ハンマーだ。 Docker DNSを完全にバイパスする。ポートバインドの問題の応急処置としてではなく、本当に必要な場合にのみ使うこと。
  • /etc/resolv.conf のnameserver行が全てを語る。 127.0.0.11 はDocker DNSがアクティブでサービス名が機能することを意味する。それ以外はDocker外で解決しようとしており、db はそこでは無意味だ。

Related Error Notes