web-dev-qa-db-ja.com

Dockerコンテナーにホスト上のdnsmasqローカルDNSリゾルバーへのアクセスを許可するにはどうすればよいですか?

DockerコンテナがDNS設定について混乱する方法はたくさんあります(SOまたは "Docker DNS"のインターネット全体を検索して、意味を確認してください)。一般的な回避策の1つです。推奨されるのは:

  1. ホストシステムでローカルDNSリゾルバーとしてdnsmasqをセットアップします。
  2. docker0ネットワークインターフェイスにバインドします
  3. DNS解決にdocker0 IPアドレスを使用するようにDockerを構成します

ただし、この回避策を多くの最新のLinuxシステムに単純に適用しようとすると、systemdがdnsmasqが実行されていないことを保証しますが、netstatそれがあり、実際にdnsmasqを開始しようとすると、ポート53がすでに使用されているという不満で失敗します。

では、システムがデフォルトですでに実行されている場合でも、ホスト上で実行されているローカルリゾルバーにコンテナーを確実にアクセスさせるにはどうすればよいでしょうか?

16
ncoghlan

ここでの問題は、多くの最新のLinuxシステムが暗黙的にdnsmasqを実行することです。そのため、あなたが現在目指しているのは、使用するDocker専用のsecondインスタンスを設定することです。実際にそれを正しく行うには、3つの設定が必要です。

  • _--interface=docker0_は、デフォルトのDockerネットワークインターフェイスでリッスンします
  • _--except-interface=lo_は、ループバックインターフェイスの暗黙的な追加をスキップします
  • _--bind-interfaces_は、dnsmasq機能をオフにします。この機能では、いずれかのインターフェイスのトラフィックのみを処理する場合でも、デフォルトですべてのインターフェイスをリッスンします。

専用のdnsmasqインスタンスのセットアップ

デフォルトのシステム全体のdnsmasqインスタンスの設定を変更するのではなく、これらの手順は、デフォルトのdnsmasqサービスを既に定義しているシステムでsystemdを使用して専用のdnsmasqインスタンスを設定する方法を示しています。

_$ Sudo cp /usr/lib/systemd/system/dnsmasq.service /etc/systemd/system/dnsmasq-docker.service
$ sudoedit /etc/systemd/system/dnsmasq-docker.service
_

最初に、デフォルトのサービス設定を専用のサービスファイルにコピーします。次に、そのサービスファイルを編集し、次のようなサービス定義セクションを探します。

_[Service]
ExecStart=/usr/sbin/dnsmasq -k
_

そのセクションを編集して、追加オプションを定義します。

_[Service]
ExecStart=/usr/sbin/dnsmasq -k --interface=docker0 --except-interface=lo --bind-interfaces
_

ファイル全体 は実際にはかなり短いです:

_[Unit]
Description=DNS caching server.
After=network.target
After=docker.service
Wants=docker.service

[Service]
ExecStart=/usr/sbin/dnsmasq -k --interface=docker0 --except-interface=lo --bind-interfaces

[Install]
WantedBy=multi-user.target
_

_[Unit]_セクションは、ネットワークスタックとメインDockerデーモンの両方がこのサービスを開始できるようになるまで待つようにsystemdに指示しますが、_[Install]_は、サービスを有効にするときにサービスを追加するシステム状態ターゲットを示します。

次に、システムの起動時に開始するように新しいサービスを構成し、すぐに使用できるように明示的に開始します。

_$ Sudo systemctl enable dnsmasq-docker
$ Sudo systemctl start dnsmasq-docker
_

サービスを実行するための最終ステップとして、期待どおりに実際に開始されたことを確認します。

_$ Sudo systemctl status dnsmasq-docker
_

その出力で探している2つの重要な行は次のとおりです。

_Loaded: loaded (/etc/systemd/system/dnsmasq-docker.service; enabled; vendor preset: disabled)
Active: active (running) since <date & time>
_

最初の行で「有効」ステータスを確認し、2行目で「アクティブ(実行中)」ステータスを確認します。サービスが正しく開始されていない場合は、追加の診断情報がその理由を説明することを期待します(ただし、残念なことに、時々この記事ではわかりにくいかもしれません)。

注:この構成は、_dnsmasq-docker_インターフェースが定義されていないというエラーで、システムの再始動時に_docker0_の開始に失敗する場合があります。 _docker.service_を待つ間、システムの再起動後にdockerコンテナからの名前解決が機能しない場合は、その問題を回避するのにかなり信頼できるようです。

_$ Sudo systemctl start dnsmasq-docker
_

ホストファイアウォールの設定

ローカルDockerコンテナーからリゾルバーを使用できるようにするには、ホストとコンテナーで実行されているシステム間のネットワークファイアウォールを削除する必要もあります。

_Sudo firewall-cmd --permanent --zone=trusted --change-interface=docker0
Sudo firewall-cmd --reload
_

(これは、実稼働コンテナーホストでは絶対にひどい考えですが、開発者のワークステーションでは、リスクと利便性のトレードオフに役立ちます)

systemd環境ファイルを使用したDockerの設定

ローカルリゾルバが実行されたので、Dockerをデフォルトで使用するように設定する必要があります。 Dockerには、インターフェイス名ではなく_docker0_インターフェイスのIPアドレスが必要なので、ifconfigを使用してそれを取得します。

_$ ifconfig docker0 | grep inet
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 0.0.0.0
_

したがって、私のシステムでは、デフォルトの_docker0_ブリッジ上のホストのインターフェースは_172.17.0.1_としてアクセス可能です(そのコマンドに_| cut -f 10 -d ' '_を追加すると、出力がIPアドレスのみにフィルターされるはずです)

システム提供のDockerパッケージを備えたsystemdベースのLinuxを想定しているため、システムパッケージのサービスファイルを照会して、サービスの開始方法を確認します。

_$ cat /usr/lib/systemd/system/docker.service
_

最初に探しているのは、デーモンを起動するために使用される正確なコマンドで、次のようになります。

_ExecStart=/usr/bin/docker daemon \
          $OPTIONS \
          $DOCKER_STORAGE_OPTIONS \
          $DOCKER_NETWORK_OPTIONS \
          $INSECURE_REGISTRY
_

探している2番目の部分は、次のような行の1つで示されるように、環境ファイルを使用するようにサービスが構成されているかどうかです。

_EnvironmentFile=-/etc/sysconfig/docker
_

環境ファイルが使用されている場合(Fedora 23の場合)、Dockerデーモンの設定を変更する方法は、そのファイルを編集し、関連する環境変数を更新することです。

_$ sudoedit /etc/sysconfig/docker
_

Fedora 23の既存のOPTIONSエントリは次のようになります。

_OPTIONS='--selinux-enabled --log-driver=journald'
_

デフォルトのDNS解決設定を変更するには、次のように修正します。

_OPTIONS='--selinux-enabled --log-driver=journald --dns=172.17.0.1'
_

そして、Dockerデーモンを再起動します。

_$ Sudo systemctl restart docker
_

この変更を実装すると、Dockerコンテナーは、ホストシステムがアクセスできるシステムに確実にアクセスできるようになります(VPNトンネルを含む、これを理解する必要がある私自身の理由)

コンテナ内でcurlを実行して、名前解決が正しく機能していることを確認できます。

_docker run -it centos curl google.com
_

_google.com_を、問題を引き起こしているホスト名に置き換えます(Dockerコンテナー内でプロセスを実行しているときに名前解決の問題が発生した場合にのみ、この回答が見つかるはずです)

systemdドロップインファイルを使用したDockerの構成

(警告:私のシステムは環境ファイルを使用しているため、以下のドロップインファイルベースのアプローチをテストすることはできませんでしたが、動作するはずです-Dockerのドキュメントがそうであるように私はそれを含めました環境ファイルの使用よりもsystemdドロップインファイルの使用を好むようになりました)

システムサービスファイルEnvironmentFileを使用しない場合、ドロップイン構成ファイルを使用してExecStartエントリ全体を置き換えることができます。

_$ Sudo mkdir -p /etc/systemd/system/docker.service.d
$ sudoedit /etc/systemd/system/docker.service.d/daemon.conf
_

次に、Dockerに既存のExecStartエントリをクリアし、追加の設定で新しいエントリに置き換えるように指示します。

_[Service]
ExecStart=
ExecStart=/usr/bin/docker daemon \
          $OPTIONS \
          --dns 172.17.0.1 \
          $DOCKER_STORAGE_OPTIONS \
          $DOCKER_NETWORK_OPTIONS \
          $INSECURE_REGISTRY
_

次に、systemdにその構成変更をロードしてDockerを再起動するように指示します。

_$ Sudo systemctl daemon-reload
$ Sudo systemctl restart docker
_

参照:

24
ncoghlan

ユーザー定義ネットワーク 上にある場合、DockerコンテナからホストのローカルDNSリゾルバ(dnsmasqなど)を使用できます。その場合、コンテナの/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 + が必要です)。

3
Eugene Yarmash