症状は次のとおりです。ホストマシンには適切なネットワークアクセスがありますが、コンテナ内で実行されているプログラムはDNS名を解決できません(詳細を調査する前に「ネットワークにアクセスできない」ように見える場合があります)。
$ Sudo docker run -ti mmoy/ubuntu-netutils /bin/bash
root@082bd4ead733:/# ping www.example.com
... nothing happens (timeout) ... ^C
root@082bd4ead733:/# Host www.example.com
... nothing happens (timeout) ... ^C
(dockerイメージ mmoy/ubuntu-netutils は、ping
およびHost
を含むUbuntuに基づくシンプルなイメージです。ネットワークが壊れているため、ここで便利です。 t apt install
これらのツール)
問題は、Dockerがコンテナ内のDNSサーバーとしてGoogleのパブリックDNSを自動的に構成したという事実に由来します。
root@082bd4ead733:/# cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 8.8.8.8
nameserver 8.8.4.4
これは多くの構成で機能しますが、GoogleのパブリックDNSがいくつかのファイアウォールルールによってフィルターされているネットワークでホストが実行されている場合は明らかに機能しません。
これが起こった理由は:
/etc/resolve.conf
の見かけのDNSサーバーはnameserver 127.0.1.1
、つまりlocalhostです。127.0.1.1
を使用しても機能しないため、DockerはGoogleのパブリックDNSにフォールバックしますが、これも機能しません。Dockerコンテナ内でDNSが破損する理由はいくつかあります。この質問(および回答)は、次の場合を対象としています。
ps -e | grep dnsmasq
を実行します。出力が空の場合、dnsmasqを実行していません。nameserver 127.0.1.1
のようなエントリが含まれています。 nameserver 127.0.0.53
が含まれている場合、おそらくdnsmasqの代わりにsystemd-resolved
を実行しています。その場合、DNS要求をdnsmasq(listen-address=172.17.0.1
を使用するもの)に転送するソリューションを使用できなくなります。 systemd-resolvedは、 'lo'インターフェイスでのみリッスンするという事実をハードコードしているため、このソリューションを適応させる簡単な方法はありません 。以下の他の回答はsystemd-resolvedで動作します。Host www.example.com 8.8.8.8
を実行します。失敗するかタイムアウトになる場合は、この状況にあります。この構成で適切なDNS構成を取得するための解決策は何ですか?
クリーンなソリューションは、docker + dnsmasqを構成して、dockerコンテナーからのDNS要求がホストで実行されているdnsmasqデーモンに転送されるようにすることです。
そのためには、ファイル/etc/NetworkManager/dnsmasq.d/docker-bridge.conf
を追加して、 dockerで使用されるネットワークインターフェイスをリッスンするようにdnsmasqを設定 する必要があります。
$ cat /etc/NetworkManager/dnsmasq.d/docker-bridge.conf
listen-address=172.17.0.1
次に、ネットワークマネージャーを再起動して、構成ファイルを考慮します。
Sudo service network-manager restart
これが完了したら、172.17.0.1
、つまりdocker内からのホストのIPアドレスをDNSサーバーのリストに追加できます。これは、コマンドラインを使用して実行できます。
$ Sudo docker run -ti --dns 172.17.0.1 mmoy/ubuntu-netutils bash
root@7805c7d153cc:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.6 ms
...またはdockerの構成ファイル/etc/docker/daemon.json
を介して(存在しない場合は作成します):
$ cat /etc/docker/daemon.json
{
"dns": [
"172.17.0.1",
"8.8.8.8",
"8.8.4.4"
]
}
(dnsmasqが失敗すると、これはGoogleのパブリックDNSにフォールバックします)
構成ファイルを考慮に入れるには、Dockerを再起動する必要があります。
Sudo service docker restart
その後、通常どおりdockerを使用できます。
$ Sudo docker run -ti mmoy/ubuntu-netutils bash
root@344a983908cb:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.3 ms
ここでは自動DNS検出が有罪であるため、Dockerの構成のデフォルト設定をオーバーライドできます。
まず、dnsmasqが使用しているDNSサーバーのIPを取得します:
$ Sudo kill -USR1 `pidof dnsmasq`
$ Sudo tail /var/log/syslog
[...]
Apr 24 13:20:19 Host dnsmasq[2537]: server xx.yy.zz.tt1#53: queries sent 0, retried or failed 0
Apr 24 13:20:19 Host dnsmasq[2537]: server xx.yy.zz.tt2#53: queries sent 0, retried or failed 0
IPアドレスは、上記のxx.yy.zz.tt
プレースホルダーに対応しています。
docker run
オプションを使用すると、--dns
時にDNSを設定できます。
$ Sudo docker run --dns xx.yy.zz.tt1 --dns xx.yy.zz.tt2 -ti mmoy/ubuntu-netutils bash
root@6c5d08df5dfd:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.6 ms
64 bytes from 93.184.216.34: icmp_seq=2 ttl=54 time=86.6 ms
このソリューションの利点の1つは、構成ファイルが含まれないため、特定の構成が原因で構成を忘れて問題が発生するリスクがないことです。このDNS構成は、--dns
オプション。
または、Dockerの構成ファイル/etc/docker/daemon.json
に永続的に設定することもできます(存在しない場合は、ホスト上で作成します)。
$ cat /etc/docker/daemon.json
{
"dns": ["xx.yy.zz.tt1", "xx.yy.zz.tt2"]
}
daemon.json
ファイルを考慮するには、Dockerデーモンを再起動する必要があります。
Sudo service docker restart
その後、構成を確認できます。
$ Sudo docker run -ti mmoy/ubuntu-netutils bash
root@56c74d3bd94b:/# cat /etc/resolv.conf
nameserver xx.yy.zz.tt1
nameserver xx.yy.zz.tt2
root@56c74d3bd94b:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.5 ms
これにより、構成ファイルのDNS IPがハードコード化されることに注意してください。お使いのマシンが異なるネットワークに接続するラップトップの場合、これは強くお勧めできません。また、インターネットサービスプロバイダーがDNSサーバーのIPを変更すると問題が生じる可能性があります。
残忍で安全でないソリューションは、ネットワークのコンテナ化を回避し、ホストとコンテナで同じネットワークを使用することです。これはコンテナのホストのすべてのネットワークリソースへのアクセスを許可するため安全ではありませんが、この分離が必要ない場合はこれが許容される場合があります。
そのためには、コマンドラインに--network Host
を追加するだけです。
$ Sudo docker run -ti --network Host mmoy/ubuntu-netutils /bin/bash
root@ubuntu1604:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=55 time=86.5 ms
64 bytes from 93.184.216.34: icmp_seq=2 ttl=55 time=86.5 ms
1つの方法は、コンテナに ユーザー定義ネットワーク を使用することです。その場合、コンテナの/etc/resolv.conf
にはネームサーバーがあります127.0.0.11
(別名Dockerの 組み込みDNSサーバー )。ホストのループバックアドレスにDNS要求を適切に転送できます。
$ cat /etc/resolv.conf
nameserver 127.0.0.1
$ docker run --rm Alpine cat /etc/resolv.conf
nameserver 8.8.8.8
nameserver 8.8.4.4
$ docker network create demo
557079c79ddf6be7d6def935fa0c1c3c8290a0db4649c4679b84f6363e3dd9a0
$ docker run --rm --net demo Alpine cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0
docker-compose
、サービスのカスタムネットワークを自動的にセットアップします(ファイル形式 v2 + )。ただし、docker-compose
は、ユーザー定義のネットワークでコンテナを実行しますが、defaultネットワークでコンテナを構築します。ビルドにカスタムネットワークを使用するには、 ビルド構成 でnetwork
パラメーターを指定できます(ファイル形式 v3.4 + が必要です)。
dnsmasq
が問題であるため、1つのオプションはホストで無効にすることです。これは機能しますが、ホストで実行されているすべてのアプリケーションのDNSキャッシュを無効にするため、ホストがdocker以外のアプリケーションに使用されている場合は非常に悪い考えです。
この方法で実行する場合は、dnsmasq
をアンインストールしてください。 UbuntuのようなDebianベースのシステムでは、apt remove dnsmasq
。
その後、/etc/resolv.conf
コンテナ内は、ホストが使用するDNSサーバーを指します。