T-CREATOR

Docker で DNS 解決に失敗する時の原因と対処:overlay2・systemd-resolved・WSL2 対応

Docker で DNS 解決に失敗する時の原因と対処:overlay2・systemd-resolved・WSL2 対応

Docker コンテナ内でインターネットに接続できない、パッケージのインストールが失敗する ── こうした問題の多くは DNS 解決の失敗 が原因です。本記事では、Docker における DNS トラブルの背景から具体的な対処法まで、初心者の方にもわかりやすく解説いたします。

特に overlay2 ストレージドライバーsystemd-resolvedWSL2 環境 という 3 つの要因に焦点を当て、それぞれの仕組みと解決策を段階的にご紹介します。ぜひ最後までお読みいただき、Docker の DNS 問題をスムーズに解決してください。

背景

Docker における DNS の役割

Docker コンテナは、ホストマシンとは独立したネットワーク環境で動作します。コンテナ内からインターネット上のサーバーにアクセスする際、ドメイン名(例:google.com)を IP アドレスに変換する必要があります。

この変換処理を DNS 解決 と呼び、Docker は以下の仕組みで DNS を提供しています。

Docker の内部 DNS サーバー

Docker Engine は、デフォルトで 組み込み DNS サーバー(通常 127.0.0.11)を各コンテナに提供します。このサーバーは、コンテナからの DNS クエリを受け取り、ホストマシンや外部の DNS サーバーに転送する役割を担います。

​/​etc​/​resolv.conf の自動生成

コンテナ起動時、Docker は ​/​etc​/​resolv.conf ファイルを自動生成し、内部 DNS サーバーのアドレスを記載します。Linux システムはこのファイルを参照して DNS クエリの送信先を決定します。

以下の図は、Docker における DNS 解決の基本的なフローを示したものです。

mermaidflowchart LR
  container["コンテナ内<br/>アプリケーション"] -->|DNS クエリ| resolvconf["/etc/resolv.conf"]
  resolvconf -->|nameserver 情報| dockerdns["Docker 内部 DNS<br/>(127.0.0.11)"]
  dockerdns -->|転送| hostdns["ホスト DNS<br/>(systemd-resolved など)"]
  hostdns -->|クエリ| external["外部 DNS サーバー<br/>(8.8.8.8 など)"]
  external -->|応答| hostdns
  hostdns -->|応答| dockerdns
  dockerdns -->|IP アドレス| container

図で理解できる要点

  • コンテナは ​/​etc​/​resolv.conf を参照して DNS サーバーを特定
  • Docker 内部 DNS がホスト DNS と外部 DNS を仲介
  • 応答は逆ルートで返却される

ストレージドライバーと DNS の関係

Docker は、コンテナのファイルシステムを管理するために ストレージドライバー を使用します。中でも overlay2 は、現在最も広く使われているドライバーです。

overlay2 は、複数のレイヤー(層)を重ね合わせて 1 つのファイルシステムを構築する技術で、効率的なストレージ利用が可能になります。しかし、この仕組みが ​/​etc​/​resolv.conf のマウント処理と競合すると、DNS 解決に問題が生じることがあります。

systemd-resolved の影響

Ubuntu 18.04 以降や他の多くの Linux ディストリビューションでは、systemd-resolved というシステムサービスが DNS 解決を一元管理しています。

systemd-resolved は、ローカルの DNS スタブリゾルバーとして 127.0.0.53 をリスニングし、上位の DNS サーバーへクエリを転送します。ホストマシンの ​/​etc​/​resolv.conf は通常、この 127.0.0.53 を参照する設定になっています。

しかし、Docker がこの設定をそのままコンテナにコピーすると、コンテナ内から 127.0.0.53 にアクセスできず、DNS 解決が失敗します。

WSL2 環境の特殊性

Windows Subsystem for Linux 2(WSL2)は、Windows 上で Linux カーネルを実行できる仮想化技術です。Docker Desktop for Windows は、WSL2 を利用して Docker Engine を動作させます。

WSL2 環境では、以下の特殊な挙動があります。

#項目内容
1ネットワーク構成WSL2 は仮想ネットワークアダプター経由でホストと通信
2DNS 自動生成WSL2 が ​/​etc​/​resolv.conf を自動生成し、Windows の DNS 設定を反映
3ファイルパーミッションNTFS と Linux のパーミッション差異により、ファイルマウントに制約

これらの要因により、通常の Linux 環境とは異なる DNS トラブルが発生することがあります。

課題

DNS 解決失敗時の典型的なエラー

Docker コンテナ内で DNS 解決が失敗すると、以下のようなエラーメッセージが表示されます。

ケース 1:パッケージインストール時のエラー

bash# apt update 実行時
Err:1 http://archive.ubuntu.com/ubuntu focal InRelease
  Temporary failure resolving 'archive.ubuntu.com'

このエラーは、apt コマンドがパッケージリポジトリのドメイン名を IP アドレスに変換できないことを示しています。

エラーコード: 該当なし(DNS 解決失敗)

発生条件

  • コンテナ内の ​/​etc​/​resolv.conf が不正な DNS サーバーを参照
  • Docker 内部 DNS サーバーが正しく動作していない
  • ホスト側の DNS 設定に問題がある

ケース 2:curl や wget でのエラー

bash# curl 実行時
curl: (6) Could not resolve host: example.com

エラーコード: curl: (6)(ホスト名解決エラー)

発生条件

  • DNS サーバーが応答しない
  • ​/​etc​/​resolv.conf に記載された nameserver にアクセスできない

ケース 3:Python や Node.js アプリケーションでのエラー

python# Python の requests ライブラリ使用時
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.example.com', port=443):
Max retries exceeded with url: /endpoint
(Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f8b9c>:
Failed to establish a new connection: [Errno -3] Temporary failure in name resolution'))

エラーコード: [Errno -3] Temporary failure in name resolution

このエラーは、プログラム実行時に DNS 解決が失敗していることを明確に示しています。

以下の図は、DNS 解決失敗がどこで発生しうるかを示したものです。

mermaidstateDiagram-v2
  [*] --> QueryStart: アプリケーションが<br/>ドメイン名を指定
  QueryStart --> CheckResolv: /etc/resolv.conf<br/>を確認
  CheckResolv --> DNSQuery: nameserver へ<br/>クエリ送信
  DNSQuery --> Success: 応答あり
  DNSQuery --> Fail1: nameserver が<br/>無効・不在
  DNSQuery --> Fail2: ネットワーク<br/>到達不可
  CheckResolv --> Fail3: resolv.conf が<br/>存在しない・空
  Success --> [*]: IP アドレス取得
  Fail1 --> [*]: エラー
  Fail2 --> [*]: エラー
  Fail3 --> [*]: エラー

図で理解できる要点

  • DNS 解決は複数のステップで構成される
  • 各ステップで異なる原因により失敗する可能性がある
  • エラーの種類により対処法が異なる

overlay2 ストレージドライバーによる問題

overlay2 ドライバーは、コンテナのファイルシステムを複数のレイヤーで管理します。Docker は ​/​etc​/​resolv.conf をホストからコンテナにバインドマウントしますが、overlay2 のレイヤー構造がこのマウント処理と競合することがあります。

具体的な問題

#問題影響
1マウント順序の競合​/​etc​/​resolv.conf が正しくマウントされず、古い内容や空ファイルになる
2レイヤーキャッシュの不整合イメージビルド時とコンテナ実行時で ​/​etc​/​resolv.conf の内容が異なる
3ファイルロック問題複数コンテナが同じファイルを参照し、書き込み競合が発生

systemd-resolved による問題

systemd-resolved を使用しているホストでは、​/​etc​/​resolv.conf が通常、シンボリックリンクとして ​/​run​/​systemd​/​resolve​/​stub-resolv.conf を参照しています。

このファイルの内容は以下のようになります。

bash# /etc/resolv.conf の内容例
nameserver 127.0.0.53
options edns0 trust-ad
search .

127.0.0.53 はローカルホストのアドレスであり、コンテナの独立したネットワーク空間からはアクセスできません。Docker がこの設定をコンテナにコピーすると、コンテナ内からの DNS クエリが失敗します。

WSL2 環境による問題

WSL2 では、Windows が DNS サーバーを管理し、WSL2 がその設定を ​/​etc​/​resolv.conf に自動反映します。しかし、この自動生成プロセスと Docker のマウント処理が競合すると、以下の問題が発生します。

WSL2 特有の問題

#問題原因
1​/​etc​/​resolv.conf が頻繁に上書きされるWSL2 が Windows のネットワーク設定変更を検知し、ファイルを再生成
2Docker がマウントに失敗ファイルが動的に変更されるため、バインドマウントが不安定
3パーミッションエラーWindows ファイルシステムとの差異により、適切な権限が設定できない

また、WSL2 ディストリビューションの再起動やネットワーク設定の変更により、Docker コンテナの DNS 設定が無効化されることもあります。

解決策

overlay2 問題への対処法

overlay2 ストレージドライバーに起因する DNS 問題は、Docker の設定変更により解決できます。

対処法 1:Docker デーモンの DNS 設定を明示

Docker デーモンの設定ファイルに、使用する DNS サーバーを直接指定します。

まず、Docker デーモンの設定ファイルを開きます。

bash# 設定ファイルを編集(root 権限が必要)
sudo vi /etc/docker/daemon.json

以下の内容を追加します。Google の公開 DNS サーバー 8.8.8.88.8.4.4 を使用する例です。

json{
  "dns": ["8.8.8.8", "8.8.4.4"]
}

設定を保存した後、Docker サービスを再起動します。

bash# Docker サービスを再起動
sudo systemctl restart docker

この設定により、すべてのコンテナがデフォルトで指定した DNS サーバーを使用するようになります。

ポイント

  • daemon.json に記載した DNS 設定は、すべてのコンテナに適用される
  • 既存のコンテナは再起動が必要
  • 企業ネットワークでは、内部 DNS サーバーのアドレスを指定することもできる

対処法 2:コンテナ起動時に DNS を指定

特定のコンテナのみ DNS 設定を変更したい場合は、docker run コマンドで --dns オプションを使用します。

bash# コンテナ起動時に DNS サーバーを指定
docker run --dns 8.8.8.8 --dns 8.8.4.4 ubuntu:20.04 bash

この方法は、一時的なテストや特定のコンテナだけ異なる DNS を使いたい場合に便利です。

対処法 3:docker-compose での DNS 設定

docker-compose を使用している場合は、docker-compose.yml ファイルに DNS 設定を記載します。

yaml# docker-compose.yml
version: '3.8'
services:
  web:
    image: nginx:latest
    dns:
      - 8.8.8.8
      - 8.8.4.4

この設定により、web サービスのコンテナが起動時に指定した DNS サーバーを使用します。

複数のサービスがある場合は、共通設定として記載することもできます。

yaml# 複数サービスでの共通 DNS 設定例
version: '3.8'

x-dns-config: &dns-config
  dns:
    - 8.8.8.8
    - 8.8.4.4

services:
  web:
    image: nginx:latest
    <<: *dns-config

  app:
    image: node:16
    <<: *dns-config

ポイント

  • YAML のアンカー(&)とエイリアス(*)を使うことで、設定の重複を避けられる
  • 各サービスで異なる DNS を設定することも可能

systemd-resolved 問題への対処法

systemd-resolved による DNS 問題は、Docker が参照する resolv.conf を変更することで解決します。

対処法 1:実際の DNS サーバー情報を使用

systemd-resolved は、実際の上位 DNS サーバー情報を ​/​run​/​systemd​/​resolve​/​resolv.conf に保存しています。このファイルを Docker に使用させます。

まず、現在の設定を確認します。

bash# 実際の DNS サーバー情報を確認
cat /run/systemd/resolve/resolv.conf

出力例は以下のようになります。

bash# This file is managed by man:systemd-resolved(8).
nameserver 192.168.1.1
nameserver 8.8.8.8
search local

ここに記載されている nameserver が、実際の DNS サーバーのアドレスです。

次に、Docker デーモンの設定でこれらの DNS サーバーを指定します。

bash# Docker 設定ファイルを編集
sudo vi /etc/docker/daemon.json

確認した DNS サーバーアドレスを記載します。

json{
  "dns": ["192.168.1.1", "8.8.8.8"]
}

Docker を再起動して設定を反映します。

bash# Docker サービス再起動
sudo systemctl restart docker

対処法 2:systemd-resolved の設定変更

別のアプローチとして、systemd-resolved 自体の設定を変更する方法もあります。

systemd-resolved の設定ファイルを編集します。

bash# resolved の設定ファイルを編集
sudo vi /etc/systemd/resolved.conf

以下の設定を追加または変更します。

ini[Resolve]
DNS=8.8.8.8 8.8.4.4
DNSStubListener=no

DNSStubListener=no により、127.0.0.53 でのリスニングを無効化します。

設定を保存した後、systemd-resolved を再起動します。

bash# systemd-resolved を再起動
sudo systemctl restart systemd-resolved

​/​etc​/​resolv.conf のシンボリックリンクを変更します。

bash# 既存のシンボリックリンクを削除
sudo rm /etc/resolv.conf

# 新しいリンクを作成
sudo ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf

この変更により、ホストとコンテナの両方が実際の DNS サーバーを参照するようになります。

注意点

  • この方法はホストシステム全体に影響する
  • 企業ネットワークなど、特定の DNS 設定が必要な環境では慎重に実施する
  • 変更前に現在の設定をバックアップしておく

対処法 3:NetworkManager の設定変更

NetworkManager を使用している環境では、以下の設定で systemd-resolved を経由しないようにできます。

NetworkManager の設定ファイルを編集します。

bash# NetworkManager 設定ファイルを編集
sudo vi /etc/NetworkManager/NetworkManager.conf

以下の設定を追加します。

ini[main]
dns=default

NetworkManager を再起動します。

bash# NetworkManager を再起動
sudo systemctl restart NetworkManager

この設定により、NetworkManager が ​/​etc​/​resolv.conf を直接管理し、systemd-resolved を経由しなくなります。

WSL2 環境への対処法

WSL2 環境特有の DNS 問題には、以下の対処法が有効です。

対処法 1:WSL2 の自動 DNS 生成を無効化

WSL2 が ​/​etc​/​resolv.conf を自動生成する機能を無効化します。

WSL2 の設定ファイルを作成または編集します。

bash# WSL2 設定ファイルを編集
sudo vi /etc/wsl.conf

以下の内容を追加します。

ini[network]
generateResolvConf = false

この設定により、WSL2 は ​/​etc​/​resolv.conf を自動生成しなくなります。

WSL2 ディストリビューションを再起動します。Windows のコマンドプロンプトまたは PowerShell で以下を実行します。

powershell# PowerShell で WSL2 をシャットダウン
wsl --shutdown

その後、WSL2 を再度起動し、​/​etc​/​resolv.conf を手動で作成します。

bash# 既存の resolv.conf を削除(シンボリックリンクの場合)
sudo rm /etc/resolv.conf

# 新規作成
sudo vi /etc/resolv.conf

以下の内容を記載します。

bash# 手動で DNS サーバーを指定
nameserver 8.8.8.8
nameserver 8.8.4.4

ファイルを保存した後、Docker を再起動します。

bash# Docker サービス再起動
sudo systemctl restart docker

ポイント

  • ​/​etc​/​wsl.conf の設定は WSL2 ディストリビューション再起動後に有効化される
  • Windows のネットワーク設定が変更されても、WSL2 の ​/​etc​/​resolv.conf は自動更新されない
  • ネットワーク環境が変わる場合は、手動で ​/​etc​/​resolv.conf を更新する必要がある

対処法 2:Docker Desktop for Windows の DNS 設定

Docker Desktop for Windows には、GUI で DNS 設定を変更する機能があります。

以下の手順で設定します。

#手順操作
1Docker Desktop を開くタスクバーの Docker アイコンをクリック
2Settings を選択メニューから「Settings」を選択
3Docker Engine を選択左メニューから「Docker Engine」をクリック
4JSON 設定を編集エディタに表示された JSON に DNS 設定を追加

JSON 設定の例は以下の通りです。

json{
  "dns": ["8.8.8.8", "8.8.4.4"],
  "debug": false,
  "experimental": false
}

設定を保存し、「Apply & Restart」ボタンをクリックします。Docker Desktop が再起動し、新しい設定が適用されます。

対処法 3:Windows の DNS 設定を確認

WSL2 は Windows のネットワーク設定を参照するため、Windows 側の DNS 設定を確認することも重要です。

Windows の DNS 設定を確認する手順です。

powershell# PowerShell で DNS サーバーを確認
Get-DnsClientServerAddress

出力例は以下のようになります。

powershellInterfaceAlias               Interface Address ServerAddresses
                             Index     Family
--------------               --------- ------- ---------------
Ethernet                     12        IPv4    {192.168.1.1}
Wi-Fi                        8         IPv4    {192.168.0.1}

ここで表示された DNS サーバーが、WSL2 および Docker コンテナが使用する DNS です。

Windows の DNS 設定を変更する場合は、以下の手順で行います。

#手順操作
1ネットワーク設定を開く設定 > ネットワークとインターネット
2アダプターオプションを変更「アダプターのオプションを変更する」をクリック
3該当アダプターを選択使用中のネットワークアダプターを右クリック > プロパティ
4IPv4 設定を開く「インターネット プロトコル バージョン 4 (TCP/IPv4)」を選択 > プロパティ
5DNS を設定「次の DNS サーバーのアドレスを使う」を選択し、アドレスを入力

この設定により、Windows と WSL2 の両方で同じ DNS サーバーが使用されます。

以下の図は、WSL2 環境における DNS 設定の流れを示しています。

mermaidflowchart TD
  windows["Windows の<br/>ネットワーク設定"] -->|DNS 情報| wsl2["WSL2<br/>(/etc/resolv.conf)"]
  wsl2 -->|自動生成<br/>有効時| auto["WSL2 が自動生成"]
  wsl2 -->|自動生成<br/>無効時| manual["手動で設定"]
  auto --> docker1["Docker コンテナ<br/>(自動設定)"]
  manual --> docker2["Docker コンテナ<br/>(手動設定)"]
  docker1 -->|DNS クエリ| dns_result["DNS 解決"]
  docker2 -->|DNS クエリ| dns_result

図で理解できる要点

  • Windows の DNS 設定が WSL2 に影響する
  • WSL2 の自動生成設定により、resolv.conf の管理方法が変わる
  • どちらの方法でも、最終的に Docker コンテナが DNS 解決できることが重要

具体例

ケーススタディ 1:Ubuntu 20.04 + systemd-resolved 環境

あるプロジェクトで、Ubuntu 20.04 上で Docker を使用していたところ、コンテナ内から外部 API にアクセスできない問題が発生しました。

問題の確認

まず、コンテナ内で DNS 解決をテストします。

bash# コンテナを起動して DNS テスト
docker run -it ubuntu:20.04 bash

コンテナ内で nslookup コマンドを実行します(事前に dnsutils をインストール)。

bash# dnsutils をインストール
apt update && apt install -y dnsutils

# DNS 解決をテスト
nslookup google.com

エラーが発生しました。

bash;; connection timed out; no servers could be reached

エラーコード: 該当なし(DNS サーバー到達不可)

次に、​/​etc​/​resolv.conf の内容を確認します。

bash# resolv.conf の内容を確認
cat /etc/resolv.conf

出力結果です。

bashnameserver 127.0.0.53
options edns0 trust-ad

127.0.0.53 が設定されているため、コンテナ内からアクセスできないことがわかりました。

解決手順

ホスト側で実際の DNS サーバーを確認します。

bash# ホストで実際の DNS サーバーを確認
cat /run/systemd/resolve/resolv.conf

出力例です。

bashnameserver 192.168.1.1
nameserver 8.8.8.8

Docker デーモンの設定ファイルを編集します。

bash# daemon.json を編集
sudo vi /etc/docker/daemon.json

以下の内容を追加します。

json{
  "dns": ["192.168.1.1", "8.8.8.8"]
}

Docker サービスを再起動します。

bash# Docker を再起動
sudo systemctl restart docker

再度コンテナを起動し、DNS 解決をテストします。

bash# 新しいコンテナを起動
docker run -it ubuntu:20.04 bash

コンテナ内で再度 nslookup を実行します。

bash# nslookup のために dnsutils をインストール
apt update && apt install -y dnsutils

# DNS 解決をテスト
nslookup google.com

今度は正常に応答が返ってきました。

bashServer:		192.168.1.1
Address:	192.168.1.1#53

Non-authoritative answer:
Name:	google.com
Address: 172.217.161.46

問題が解決されました。

結果と学び

#項目内容
1問題の原因systemd-resolved のローカルアドレス(127.0.0.53)をコンテナが参照
2解決方法Docker デーモンに実際の DNS サーバーを明示的に設定
3確認手順コンテナ内での nslookup テストと /etc/resolv.conf の確認

ケーススタディ 2:WSL2 + Docker Desktop 環境

Windows 10 の WSL2 上で Docker Desktop を使用していたところ、コンテナビルド時にパッケージのダウンロードが失敗する問題が発生しました。

問題の確認

Dockerfile でイメージをビルドする際、以下のエラーが発生しました。

dockerfile# Dockerfile
FROM node:16

# パッケージをインストール
RUN apt-get update && apt-get install -y \
    curl \
    git

ビルドコマンドを実行します。

bash# イメージをビルド
docker build -t myapp .

エラーメッセージです。

bashErr:1 http://deb.debian.org/debian bullseye InRelease
  Temporary failure resolving 'deb.debian.org'
Err:2 http://security.debian.org/debian-security bullseye-security InRelease
  Temporary failure resolving 'security.debian.org'
Reading package lists...
W: Failed to fetch http://deb.debian.org/debian/dists/bullseye/InRelease
   Temporary failure resolving 'deb.debian.org'

エラーコード: 該当なし(DNS 解決失敗)

WSL2 内で ​/​etc​/​resolv.conf を確認します。

bash# WSL2 の resolv.conf を確認
cat /etc/resolv.conf

出力内容です。

bash# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 172.24.80.1

172.24.80.1 は WSL2 の仮想ネットワークアダプターのアドレスですが、何らかの理由で DNS クエリが失敗しています。

解決手順(方法 1:WSL2 の自動生成を無効化)

WSL2 の設定ファイルを作成します。

bash# wsl.conf を編集
sudo vi /etc/wsl.conf

以下の内容を追加します。

ini[network]
generateResolvConf = false

ファイルを保存し、WSL2 をシャットダウンします。Windows の PowerShell で実行します。

powershell# WSL2 をシャットダウン
wsl --shutdown

WSL2 を再起動し、​/​etc​/​resolv.conf を手動で作成します。

bash# 既存ファイルを削除
sudo rm /etc/resolv.conf

# 新規作成
sudo vi /etc/resolv.conf

以下の内容を記載します。Google の公開 DNS を使用する例です。

bashnameserver 8.8.8.8
nameserver 8.8.4.4

Docker Desktop を再起動します(Windows のタスクバーから Docker アイコンを右クリック > Restart)。

再度、イメージのビルドを試みます。

bash# イメージを再ビルド
docker build -t myapp .

今度は正常にビルドが完了しました。

bashSuccessfully built 3f8a9c2e1d4b
Successfully tagged myapp:latest

解決手順(方法 2:Docker Desktop の DNS 設定)

別の方法として、Docker Desktop の設定で DNS を指定することもできます。

Docker Desktop を開き、設定画面に移動します。

#手順操作
1Docker Desktop を開くタスクバーの Docker アイコンをクリック
2Settings を選択歯車アイコンをクリック
3Docker Engine を選択左メニューから「Docker Engine」をクリック

JSON エディタに以下の設定を追加します。

json{
  "dns": ["8.8.8.8", "8.8.4.4"],
  "registry-mirrors": [],
  "insecure-registries": [],
  "debug": false,
  "experimental": false
}

「Apply & Restart」ボタンをクリックし、Docker を再起動します。

再度ビルドを実行すると、正常に完了します。

結果と学び

#項目内容
1問題の原因WSL2 が自動生成する DNS 設定が不安定
2解決方法 1WSL2 の自動生成を無効化し、手動で DNS を設定
3解決方法 2Docker Desktop の設定で DNS を明示的に指定
4推奨方法環境が固定されている場合は方法 1、複数環境で作業する場合は方法 2 が便利

ケーススタディ 3:docker-compose での DNS 設定

マイクロサービス構成のプロジェクトで、複数のコンテナを docker-compose で管理していました。一部のコンテナだけ DNS 解決が失敗する問題が発生しました。

問題の確認

docker-compose.yml の内容です。

yamlversion: '3.8'

services:
  web:
    image: nginx:latest
    ports:
      - '80:80'

  api:
    build: ./api
    environment:
      - DATABASE_URL=postgres://db:5432/mydb

  db:
    image: postgres:13
    environment:
      - POSTGRES_PASSWORD=secret

api サービスのビルド時に DNS エラーが発生しました。

bash# docker-compose でビルド
docker-compose build

エラーメッセージです。

bashBuilding api
Step 3/8 : RUN apt-get update && apt-get install -y curl
 ---> Running in 2f8a3c1b4d5e
Err:1 http://deb.debian.org/debian buster InRelease
  Temporary failure resolving 'deb.debian.org'

エラーコード: 該当なし(DNS 解決失敗)

解決手順

docker-compose.yml に DNS 設定を追加します。

yaml# docker-compose.yml(修正版)
version: '3.8'

# 共通 DNS 設定を定義
x-dns-config: &dns-config
  dns:
    - 8.8.8.8
    - 8.8.4.4

services:
  web:
    image: nginx:latest
    ports:
      - '80:80'
    <<: *dns-config

  api:
    build: ./api
    environment:
      - DATABASE_URL=postgres://db:5432/mydb
    <<: *dns-config

  db:
    image: postgres:13
    environment:
      - POSTGRES_PASSWORD=secret
    <<: *dns-config

YAML のアンカー(&dns-config)とエイリアス(<<: *dns-config)を使用することで、すべてのサービスに同じ DNS 設定を適用しています。

既存のコンテナを削除し、再ビルドします。

bash# 既存コンテナを削除
docker-compose down

# 再ビルドして起動
docker-compose up --build

今度は正常にビルドが完了し、すべてのサービスが起動しました。

応用:環境変数での DNS 指定

環境ごとに異なる DNS を使用したい場合は、.env ファイルと組み合わせることができます。

.env ファイルを作成します。

bash# .env ファイル
DNS_PRIMARY=8.8.8.8
DNS_SECONDARY=8.8.4.4

docker-compose.yml で環境変数を参照します。

yaml# docker-compose.yml(環境変数対応版)
version: '3.8'

services:
  api:
    build: ./api
    dns:
      - ${DNS_PRIMARY}
      - ${DNS_SECONDARY}

この方法により、開発環境と本番環境で異なる DNS 設定を簡単に切り替えられます。

結果と学び

#項目内容
1問題の原因docker-compose で起動したコンテナが適切な DNS 設定を持っていない
2解決方法docker-compose.yml に DNS 設定を追加
3YAML アンカー活用共通設定を 1 箇所で定義し、重複を避ける
4環境変数活用環境ごとに異なる DNS を柔軟に設定できる

以下の図は、docker-compose における DNS 設定の適用フローを示しています。

mermaidflowchart TD
  compose_file["docker-compose.yml"] -->|定義| dns_anchor["DNS アンカー<br/>&dns-config"]
  dns_anchor -->|参照| service1["web サービス"]
  dns_anchor -->|参照| service2["api サービス"]
  dns_anchor -->|参照| service3["db サービス"]
  service1 --> container1["web コンテナ<br/>DNS: 8.8.8.8"]
  service2 --> container2["api コンテナ<br/>DNS: 8.8.8.8"]
  service3 --> container3["db コンテナ<br/>DNS: 8.8.8.8"]
  container1 --> query["外部 DNS クエリ"]
  container2 --> query
  container3 --> query

図で理解できる要点

  • 1 つのアンカー定義を複数のサービスで共有
  • 各コンテナに同じ DNS 設定が適用される
  • すべてのコンテナが統一された DNS サーバーにアクセス

まとめ

Docker における DNS 解決の失敗は、多くの開発者が直面する問題です。本記事では、overlay2 ストレージドライバーsystemd-resolvedWSL2 環境 という 3 つの主要な原因と、それぞれに対応した解決策をご紹介しました。

重要なポイントをまとめます

#原因対処法
1overlay2 ストレージドライバーDocker デーモンまたはコンテナ起動時に明示的に DNS を指定
2systemd-resolved実際の DNS サーバー情報を Docker に設定、または resolved の設定を変更
3WSL2 環境自動生成を無効化して手動設定、または Docker Desktop で DNS を指定

トラブルシューティングの基本手順

  1. コンテナ内の ​/​etc​/​resolv.conf を確認し、DNS サーバーアドレスを特定する
  2. nslookupdig コマンドで DNS 解決をテストする
  3. ホスト側の DNS 設定(​/​run​/​systemd​/​resolve​/​resolv.conf など)を確認する
  4. Docker デーモンまたは docker-compose.yml に適切な DNS 設定を追加する
  5. Docker を再起動し、コンテナを再ビルド・再起動する

DNS 問題は環境によって原因が異なりますが、本記事で紹介した方法を順番に試していただければ、ほとんどのケースで解決できるはずです。

特に WSL2 環境では、ネットワーク設定の変更や Windows Update により DNS 設定が変わることがあります。問題が再発した場合は、本記事の手順を参考に再度設定を確認してください。

Docker のネットワーク機能を正しく理解し、DNS 設定を適切に管理することで、快適な開発環境を構築できます。ぜひ本記事を参考に、DNS トラブルをスムーズに解決していただければ幸いです。

関連リンク