web-dev-qa-db-ja.com

ホストがdnsmasqを使用し、GoogleのDNSサーバーがファイアウォールで保護されている場合、DNSはdockerコンテナ内で機能しませんか?

症状は次のとおりです。ホストマシンには適切なネットワークアクセスがありますが、コンテナ内で実行されているプログラムは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がいくつかのファイアウォールルールによってフィルターされているネットワークでホストが実行されている場合は明らかに機能しません。

これが起こった理由は:

  • Dockerは最初に、ホストとコンテナー内で同じDNSサーバーを構成しようとします。
  • ホストは、DNSキャッシュサービスである dnsmasq を実行します。 dnsmasqはDNS要求のプロキシとして機能するため、ホストの/etc/resolve.confの見かけのDNSサーバーはnameserver 127.0.1.1、つまりlocalhostです。
  • ホストのdnsmasqは、localhostからのリクエストのみをリッスンし、Dockerコンテナからのリクエストをブロックします。
  • Docker内で127.0.1.1を使用しても機能しないため、DockerはGoogleのパブリックDNSにフォールバックしますが、これも機能しません。

Dockerコンテナ内でDNSが破損する理由はいくつかあります。この質問(および回答)は、次の場合を対象としています。

  • dnsmasqが使用されます。これが当てはまるかどうかを確認するには:
  • GoogleのパブリックDNSはフィルタリングされます。 Host www.example.com 8.8.8.8を実行します。失敗するかタイムアウトになる場合は、この状況にあります。

この構成で適切なDNS構成を取得するための解決策は何ですか?

18
Matthieu Moy

クリーンなソリューションは、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
19
Matthieu Moy

ここでは自動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を変更すると問題が生じる可能性があります。

1
Matthieu Moy

残忍で安全でないソリューションは、ネットワークのコンテナ化を回避し、ホストとコンテナで同じネットワークを使用することです。これはコンテナのホストのすべてのネットワークリソースへのアクセスを許可するため安全ではありませんが、この分離が必要ない場合はこれが許容される場合があります。

そのためには、コマンドラインに--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
Matthieu Moy

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 + が必要です)。

1
Eugene Yarmash

dnsmasqが問題であるため、1つのオプションはホストで無効にすることです。これは機能しますが、ホストで実行されているすべてのアプリケーションのDNSキャッシュを無効にするため、ホストがdocker以外のアプリケーションに使用されている場合は非常に悪い考えです。

この方法で実行する場合は、dnsmasqをアンインストールしてください。 UbuntuのようなDebianベースのシステムでは、apt remove dnsmasq

その後、/etc/resolv.confコンテナ内は、ホストが使用するDNSサーバーを指します。

0
Matthieu Moy