Docker環境で名前解決がズレる理由

  • URLをコピーしました!

Docker環境で以下のような「名前解決のズレ」に悩まされたことはないでしょうか。

  • ホストでは引けるが、コンテナ内では引けない
  • dig は成功するが、アプリは失敗する
  • VPN接続時だけ名前解決がおかしくなる
  • 再起動すると直るが再発する

これらはDocker特有の名前解決設計を理解していないと、 原因特定に時間がかかりがちです。

本記事では、

  • Dockerの名前解決フロー
  • ホストとの違い
  • ズレが発生する典型パターン
  • 実務的な切り分け・対策

を体系的に解説します。

目次

結論:Dockerはホストの名前解決を「そのまま」使っていない

まず結論です。

  • Dockerコンテナは 独立した名前解決空間 を持つ
  • ホストの /etc/resolv.conf を単純コピーしているだけではない
  • systemd-resolved / VPN / NetworkManager の影響を受けやすい

この前提を理解していないと、調査が迷走します。

Dockerコンテナの名前解決の仕組み

Dockerコンテナ内では、基本的に以下が使用されます。

  • /etc/resolv.conf(Dockerが生成)
  • /etc/hosts(Dockerが管理)
  • glibc(通常のLinuxアプリと同じ)

重要なのは、/etc/resolv.conf はホストのコピーではない点です。

コンテナ内 /etc/resolv.conf の実態

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

よくある内容は以下です。

nameserver 127.0.0.11
options ndots:0

この 127.0.0.11 は、

  • ホストのDNSではない
  • systemd-resolved でもない

Docker内蔵DNSです。

Docker内蔵DNS(127.0.0.11)の役割

Dockerは以下の役割を持つDNSを内部に持っています。

  • コンテナ名解決(docker-compose / bridge)
  • ホストDNSへのフォワード

つまり、

  • アプリ → glibc
  • glibc → 127.0.0.11
  • 127.0.0.11 → ホストDNS

という1段階多い構造になっています。

ズレが発生する典型パターン① systemd-resolved 使用時

ホストで systemd-resolved が有効な場合、

  • ホスト:127.0.0.53
  • コンテナ:127.0.0.11

という二重スタブ構成になります。

結果として、

  • ホストでは解決できる
  • コンテナからはフォワード失敗

が発生します。

ズレが発生する典型パターン② VPN接続

VPN接続時、ホストのDNSが動的に変わるケースがあります。

しかし Docker は、

  • 起動時のDNS情報を保持
  • VPN接続後に自動追従しない

ため、

  • ホスト:新DNS
  • コンテナ:古いDNS

というズレが発生します。

ズレが発生する典型パターン③ ndots 設定

Dockerでは以下が設定されがちです。

options ndots:0

これにより、

  • searchドメインが使われない
  • FQDN前提の挙動になる

社内DNSなどでは名前解決失敗につながります。

切り分け手順(実務)

① コンテナ内 glibc 経路確認

docker exec -it <container> getent hosts example.com
  • 成功 → DNSフォワードOK
  • 失敗 → Docker DNS or ホストDNS疑い

② Docker DNS動作確認

docker exec -it <container> dig example.com

dig が成功してもアプリNGなら glibc設定を疑います。

③ ホストDNS確認

resolvectl status

VPN・NIC別DNSの影響を確認します。

対策① 明示的にDNSを指定する

docker run

docker run --dns 8.8.8.8 nginx

docker-compose

services:
  app:
    dns:
      - 8.8.8.8

期待される結果

  • VPNやsystemd-resolvedの影響を受けない
  • 名前解決が安定

対策② systemd-resolved を使わない設計

ホスト側で以下を選択するのも有効です。

  • systemd-resolved 無効化
  • 静的 /etc/resolv.conf

Dockerとの相性が良くなります。

対策③ Docker再起動

VPN接続後は必須です。

systemctl restart docker

期待される結果

  • 最新のDNS設定が反映
  • ズレが解消

やってはいけない対策

  • コンテナ内で resolv.conf を手動編集
  • 毎回 dig だけで判断
  • 原因不明のまま再起動で逃げる

再発します。

まとめ

  • Dockerは独立した名前解決構造を持つ
  • 127.0.0.11 はDocker内蔵DNS
  • systemd-resolved / VPNと相性問題あり
  • getent が最重要切り分け手段

Dockerの名前解決トラブルは、 構造を理解すれば再現性を持って解決できます

目次