Docker で DNS 解決に失敗する時の原因と対処:overlay2・systemd-resolved・WSL2 対応
Docker コンテナ内でインターネットに接続できない、パッケージのインストールが失敗する ── こうした問題の多くは DNS 解決の失敗 が原因です。本記事では、Docker における DNS トラブルの背景から具体的な対処法まで、初心者の方にもわかりやすく解説いたします。
特に overlay2 ストレージドライバー、systemd-resolved、WSL2 環境 という 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 は仮想ネットワークアダプター経由でホストと通信 |
| 2 | DNS 自動生成 | 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 のネットワーク設定変更を検知し、ファイルを再生成 |
| 2 | Docker がマウントに失敗 | ファイルが動的に変更されるため、バインドマウントが不安定 |
| 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.8 と 8.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 設定を変更する機能があります。
以下の手順で設定します。
| # | 手順 | 操作 |
|---|---|---|
| 1 | Docker Desktop を開く | タスクバーの Docker アイコンをクリック |
| 2 | Settings を選択 | メニューから「Settings」を選択 |
| 3 | Docker Engine を選択 | 左メニューから「Docker Engine」をクリック |
| 4 | JSON 設定を編集 | エディタに表示された 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 | 該当アダプターを選択 | 使用中のネットワークアダプターを右クリック > プロパティ |
| 4 | IPv4 設定を開く | 「インターネット プロトコル バージョン 4 (TCP/IPv4)」を選択 > プロパティ |
| 5 | DNS を設定 | 「次の 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 を開き、設定画面に移動します。
| # | 手順 | 操作 |
|---|---|---|
| 1 | Docker Desktop を開く | タスクバーの Docker アイコンをクリック |
| 2 | Settings を選択 | 歯車アイコンをクリック |
| 3 | Docker 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 | 解決方法 1 | WSL2 の自動生成を無効化し、手動で DNS を設定 |
| 3 | 解決方法 2 | Docker 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 設定を追加 |
| 3 | YAML アンカー活用 | 共通設定を 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-resolved、WSL2 環境 という 3 つの主要な原因と、それぞれに対応した解決策をご紹介しました。
重要なポイントをまとめます
| # | 原因 | 対処法 |
|---|---|---|
| 1 | overlay2 ストレージドライバー | Docker デーモンまたはコンテナ起動時に明示的に DNS を指定 |
| 2 | systemd-resolved | 実際の DNS サーバー情報を Docker に設定、または resolved の設定を変更 |
| 3 | WSL2 環境 | 自動生成を無効化して手動設定、または Docker Desktop で DNS を指定 |
トラブルシューティングの基本手順
- コンテナ内の
/etc/resolv.confを確認し、DNS サーバーアドレスを特定する nslookupやdigコマンドで DNS 解決をテストする- ホスト側の DNS 設定(
/run/systemd/resolve/resolv.confなど)を確認する - Docker デーモンまたは docker-compose.yml に適切な DNS 設定を追加する
- Docker を再起動し、コンテナを再ビルド・再起動する
DNS 問題は環境によって原因が異なりますが、本記事で紹介した方法を順番に試していただければ、ほとんどのケースで解決できるはずです。
特に WSL2 環境では、ネットワーク設定の変更や Windows Update により DNS 設定が変わることがあります。問題が再発した場合は、本記事の手順を参考に再度設定を確認してください。
Docker のネットワーク機能を正しく理解し、DNS 設定を適切に管理することで、快適な開発環境を構築できます。ぜひ本記事を参考に、DNS トラブルをスムーズに解決していただければ幸いです。
関連リンク
articleDocker で DNS 解決に失敗する時の原因と対処:overlay2・systemd-resolved・WSL2 対応
articleDocker を用いた統一ローカル環境:新人オンボーディングを 1 日 → 1 時間へ
articleDocker で Dev Container を構築:VS Code/Codespaces で即戦力環境を配布
articleDocker マルチステージビルド設計大全:テスト分離・依存最小化・キャッシュ戦略
articleDocker コマンド早見表:build/run/exec/logs/prune を 1 枚で網羅
articleWindows WSL2 に Docker を最適導入:I/O 最適化・メモリ配分・互換性チェック
articleGrok プロンプト・テンプレ 100 連発:要約/翻訳/コード/分析 早見表
articleGitHub Copilot Workspace と Cursor/Cline の比較検証:仕様駆動の自動化能力はどこまで?
articleGitHub Actions 署名戦略を比べる:SHA ピン留め vs タグ参照 vs バージョン範囲
articlegpt-oss が OOM/VRAM 枯渇で落ちる:モデル分割・ページング・バッチ制御の解決策
articleGPT-5 ツール呼び出しが暴走する時の診断フロー:関数設計/停止条件/リトライ制御
articleGit の index.lock 残留問題を解決:並行実行・クラッシュ後の正しい対処法
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来