仮想マシン
 Computer >> コンピューター >  >> ソフトウェア >> 仮想マシン

Dockerコンテナで名前解決が失敗する問題の原因と解決方法【徹底解説】

この記事を読む必要に迫られないことを願っています。もしあなたがここにいるなら、暇つぶしに検索でたどり着いたか、あるいは実際に「最近まで正常に動いていたDockerコンテナが、環境を何も変更していないのに突然インターネットにアクセスできなくなった」という問題に直面しているのかもしれません。

漠然とした症状の説明に聞こえるかもしれませんが、筆者自身がまさにこの状況に遭遇しました。コンテナ内でネットワークにアクセスしようとすると、「Temporary failure resolving URL(URLの一時的な名前解決失敗)」のようなエラーが表示されるのです。名前解決の問題に見えましたが、本来起こるはずのない現象だったため、余計に頭を悩ませました。それでは、順を追って見ていきましょう。なお、本記事の検証環境はsystemdを採用したUbuntuです。後半で重要になってきます。

問題の詳細

システムにDockerをセットアップ済みで、複数のイメージやコンテナを運用しており、高度なネットワークルールまで設定して、すべてが完璧に動作していたとします。ところがある日、コンテナ内でパッケージの更新やインストールなどができなくなったことに気づきました。

デバッグの最善策は、稼働中のコンテナにシェルをアタッチすることです。コンテナ内部で以下のような出力を目にするはずです。

# apt-get update
Err:1 https://archive.ubuntu.com/ubuntu bionic InRelease
Temporary failure resolving 'archive.ubuntu.com'
0% [Connecting to security.ubuntu.com]

これは典型的なDNS(名前解決)の問題です。コンテナがドメイン名をIPアドレスに変換できず、その結果、更新データなどを取得するサーバーに接続できない状態になっています。ここには2つの課題があります。1つ目は「なぜ突然この問題が発生したのか」、2つ目は「どうやってネットワークを修復するか」です。以下では、エレガントなトラブルシューティングの手順を紹介します。

解決方法

まず、なぜこの問題が発生したのかを理解しましょう。即答できる答えはありませんが、確認すべきポイントは自分の環境だけにとどまりません。ホストマシン自体は変更していなくても、ルーターやネットワークポリシー、DNSサーバー側の設定が変わっている可能性があります。自分の管理範囲外で何が起きているかを制御することは通常できないため、問題の所在を特定する最良の方法は、段階的に切り分けを行うことです。

  • ホストシステムにネットワーク接続があり、かつURLを解決できない場合:まずホスト側の問題を解決する必要があります。ホストと宛先の間にあるネットワークインフラ(ルーター、DNSサーバーなど)に問題がある可能性が高いです。
  • ホストシステムにネットワーク接続があり、URLも正しく解決できる場合:問題はDockerコンテナ特有の名前解決の仕組みにあります。ここからが焦点となります。
  • Dockerのネットワークインターフェースが起動しているか確認します(ipコマンドやifconfigコマンドを使用)。起動していなければ、先にそちらを修正しましょう。

ifconfig docker0

  • コンテナインスタンスがIPアドレスを持っているか確認します。持っていなければ、まずその問題を解決します。

docker inspect <コンテナ名またはID> | grep -i "ipaddr"

  • 可能であれば、コンテナ内部でも同じ確認を行います(ipまたはifconfig)。前のコマンドの結果と一致しない場合は、その不一致を解消する必要があります。
  • 外部からコンテナへpingを実行できるか確認します(逆方向も、pingコマンドが利用可能なら試します)。pingが通れば、ネットワーク設定は正しく、ファイアウォールのルールによって通信がブロックされていない可能性が高いと言えます。

名前解決の調査

これらのチェックで異常が見つからなければ、次はDNS解決に焦点を移します。その設定は/etc/resolv.confファイルに記述されています。これは物理的なLinuxマシンでも、仮想マシンやコンテナでも同様です。コンテナの中身を見ると、おそらく次のようになっています。

...
# See man:systemd-resolved.service(8) for details about the supported modes
# of operation for /etc/resolv.conf.

search xyz

nameserver X.Y.Z.W
...

nameserverのIPアドレスは、外部のIPアドレス(ISPが提供するものなど)か、ローカルホスト(127.0.0.X)であることがほとんどです。ここで重要な質問があります。これらはホストの/etc/resolv.confファイルの内容と一致していますか?

答えは、おそらくホスト側の/etc/resolv.confにはlocalhostが定義されているでしょう。そこで、コンテナ側でも試してみてください。resolv.confファイルを編集し、nameserver行のIPアドレスをホストと同じ値=localhostに置き換えます。これで問題が解決すれば万々歳ですが、残念ながら大抵の場合、うまくいきません。

とはいえ、この時点でホスト側のネットワーク接続に問題はないことが分かっています。次に必要なのは、あなたの環境におけるDNSサーバーの実際のアドレスを特定することです。そして、ここで話を複雑にしているのが、多くの最新Linuxディストリビューションがsystemdを採用しているという事実です。話はさらに深みへと進みます。

systemd環境でDNSサーバーを特定する方法

そう、nameserverが何であるかを突き止める必要があり、そのためにはsystemdのコマンドを使います。systemdを採用しているシステムであれば、ネットワーク名前解決マネージャーであるsystemd-resolvedも使っている可能性が高いでしょう。設定は/etc/systemd/resolved.confに保存されていますが、コマンドラインからも結果を取得できます。

systemd-resolve --status

Link 3 (wlp59s0)
      Current Scopes: DNS
       LLMNR setting: yes
MulticastDNS setting: no
         DNSSEC setting: no
    DNSSEC supported: no
            DNS Servers: 10.50.34.1
                                   2001:64c:1462:b023::1
             DNS Domain: dedoimedo

興味深い情報がたくさん表示されますが、本当に重要なのは「DNS Servers」の行です。これこそが求めていた情報です。このIPアドレスをコンテナの/etc/resolv.confファイルに記入し、再度試してみてください。ネットワークが復活するはずです。

なぜこの問題が発生するのか?

ここで改めて「なぜ」について考察しましょう。systemd-resolveのドキュメントによると、システムに何らかの変更(場合によっては通常のアップデートによるもの)が加わった結果、選択された動作モードが名前解決と競合を引き起こす可能性があります。特に、/etc/resolv.confの扱われ方に注目すると、最初のモードには次のように記載されています。

「systemd-resolvedは、従来のLinuxプログラムとの互換性のために/run/systemd/resolve/stub-resolv.confファイルを維持します。このファイルは/etc/resolv.confからシンボリックリンクされる場合があります。このファイルは、127.0.0.53のDNSスタブ(上記参照)を唯一のDNSサーバーとして列挙し、systemd-resolvedが使用する検索ドメインのリストも含んでいます。検索ドメインのリストは常に最新の状態に保たれます。/run/systemd/resolve/stub-resolv.confはアプリケーションから直接使用すべきではなく、/etc/resolv.confからのシンボリックリンクを通じてのみ使用してください。この動作モードが推奨されています。」

この連鎖の中でどこか1つのリンクが壊れたり、何かが変更されたりすると、Dockerサービスが状況を正しく判断できなくなり、名前解決が機能しなくなることがあります。つまり解決策は、コンテナが理解して使用できる実際のネットワークDNSアドレスを明示的に指定することです。筆者の推測の部分もありますが、かなり正確な説明だと思います。

まとめ

というわけで、また一つ謎が解けました。ハーフマジック的な解決策は好きではありませんが、非常に複雑で多層化されたシステムインフラにおいては、解決策が問題と同じくらい厄介になることもあります。問題が直らないという意味ではなく、本来あるべき可視性と制御性が失われるという意味です。しかしそれこそが、LinuxそしてIT全体の未来——果てしない抽象化なのです。

本題に戻ると、この小さなガイドが、コンテナ運用における比較的迅速で痛みのない修正方法を提供できたなら幸いです。Dockerを使用していて、コンテナインスタンス内で名前解決が機能しなくなった場合は、上記のヒントやテクニックを試してみてください。そして、正しい修正を組み込んだ独自のイメージを構築すれば、同じ問題と再び格闘する必要がなくなります。以上で終わりです。

  1. KVMのストレージ管理を徹底解説!ストレージプールとボリュームの作成チュートリアル

    さて、先日、Kernel-based Virtual Machine(KVM)という技術をご紹介しました。KVMは無料かつオープンソースの仮想化ソリューションで、VirtualBoxやVMware製品の代わりとして、あるいはそれらと併用して使うこともできます。前回は基本的な管理操作を扱いましたが、ストレージとネットワークについては別のチュートリアルに回すことにしました。 今回は、KVMにおけるストレージ管理について、より踏み込んだガイドをお届けします。内容はVirtualBoxで行ったものと似ており、仮想ディスクの追加・縮小・拡張などが含まれます。さらに、NFSストレージやNTFSフォーマット

  2. VirtualBoxでディスクをクローンする方法【VBoxManage活用チュートリアル】

    仮想化を業務でも趣味でも利用している方なら、VirtualBoxという強力かつ多用途な無料ソリューションを目にしたことがあるかもしれません。VirtualBoxは、デスクトップユーザーに対して、あらゆる形でOSを展開できる大きな柔軟性を提供してくれます。さらに、単なる趣味として仮想化を楽しんでいるだけでなく、仮想化を通じて新しいOSを学ぼうとする熱心なソフトウェア愛好家の方であれば、次のような場面に必ず直面することでしょう。それは「大量の仮想マシンを展開する必要がある」というシナリオです。一台ずつインストール作業を行う時間的な余裕はないはずです。実際、大規模に環境を展開する際に手動で一つずつマ