VPNは接続中で、ブラウザーは社内サイトに到達できるのに、コンテナは同じ名前を解決できません。パッケージのインストールはEAI_AGAINのような名前解決エラーで落ち、アプリケーションはホスト機が何事もなく解決するデータベースのホストを見つけられません。コンテナはVPNが導入したリゾルバーを使っていません。Dockerはコンテナ作成時にホストのリゾルバー設定をコピーし、その後は何もコピーし直していません。

一台のマシンにある二つのリゾルバーの見え方

Linuxでは、Dockerはコンテナ作成時にホストのリゾルバー設定のコピーを各コンテナに渡し、ループバックアドレスを除外して、127.0.0.11で埋め込みDNSサーバーを動かし、クエリを外へ転送します。コンテナ起動後に/etc/resolv.confを書き換えるVPNクライアントは、内部の何も変えません。コンテナの再起動が効くのは、その時点でホストのリゾルバーがたまたま正しい場合だけです。

macOSやWindowsのDocker Desktopは層を一つ増やします。デーモンが仮想マシンの中で動いているからです。ホストのVPNリゾルバーがそのVMから見えないこともあり、再起動しても何も変わりません。修正を選ぶ前に二つの見え方を比べてください。ホストのリゾルバー一覧の隣でdocker exec mycontainer cat /etc/resolv.confを実行します。

ホストが内部リゾルバーを挙げているのにコンテナが公開リゾルバーを挙げていると、公開名は解決できて内部名で失敗します。この分岐がこの問題の特徴です。

選択肢A: コンテナごとにトンネルのリゾルバーを渡す

DockerはコンテナごとのDNS設定を受け付けます。これが機能する最小の変更です。まずVPNのリゾルバーアドレスを読み取ります。macOSではscutil --dns、Linuxではresolvectl statusまたはクライアント自身の状態出力です。そのうえでコンテナをそのアドレス付きで起動します。たとえばdocker run --dns 192.168.2.1 --dns 192.168.123.1 myimageです。Composeでは同じ設定がサービスの下のリストになり、誰かのシェル履歴ではなくバージョン管理に残ります。

/etc/docker/daemon.jsonのdns配列は新しいコンテナすべてに適用され、整って見えますが実際はそうではありません。トンネルが落ちているときにも適用され、VPN経由でしか届かないリゾルバーが通常のイメージ取得を壊します。コンテナごとの設定のほうが説明しやすく、取り消しやすくなります。

選択肢B: コンテナにホストのネットワークを共有させる

ホストネットワークはコピーを完全に回避します。コンテナがホストのリゾルバーとホストのトンネルを使うからです。ただし本来欲しかったネットワーク分離も失われ、Docker Desktopでは同じようには振る舞いません。Linuxでは、内部名を解決する必要がある一回限りのツールには現実的な選択です。

ビルドにはどちらの選択肢も当てはまりません。ビルド手順は実行時のフラグを引き継がないからです。プラットフォームが許す場所ではホストネットワークでビルドするか、依存関係のインストールをトンネル不要の段階に置いてください。

どちらの選択肢でも直らないもの

コンテナに経路がなければDNSアドレスは役に立ちません。VPNのリゾルバーは通常トンネルのアドレス空間の内側にあるため、コンテナにはそのプレフィックスへの経路が必要です。Dockerの既定ブリッジは通常ホスト経由で外へルーティングし、ホストにトンネルの経路があり転送が有効ならそれで足ります。独自のアドレスプールを持つカスタムブリッジネットワークはVPNのサブネットと衝突することがあり、その場合クエリはまったく別の場所へ行きます。

リゾルバー自体をデバッグする前に、DockerネットワークのサブネットをVPNのサブネットと突き合わせてください。重なると、壊れたDNSサーバーとまったく同じに見える障害になります。

コンテナの内部で確認する

ブラウザーや言語ランタイムではなく、コンテナの内部でgetent hosts db.internalを使って試してください。それらは独自のDNSポリシーと独自のキャッシュを適用するからです。getentが名前を解決し、それでもアプリケーションが失敗するなら、リゾルバーは正しくなっており、残る問題はアプリケーション側です。解決しないなら、DNSの段階は終わっていません。

DNS設定を変えたらコンテナを作り直してください。実行中のコンテナの中で/etc/resolv.confを編集しても、コンテナと一緒に消え、再起動にかかる時間だけ設定の問題を隠すことになります。

関連記事