注意書き

本サイトでは、アフィリエイト広告およびGoogleアドセンスを利用しています。

Docker Desktop (Windows) のネットワーク

インフラストラクチャ

Docker Desktop for Windows のネットワークの仕組みがとても気になったので、自分なりに調べてみました。一般的に説明されている Docker のネットワーク構造はある程度知っている前提で記載しています。

記載していることは個人で調べたものであり、正しさを保証するものではありません。また執筆時点の Docker Desktop for Windowsのバージョンではこうだったというものです。実装によって変化してしまうものと考えられるのでご注意ください。

もしより詳細な内容を知っていたり、本記事の間違いに気付いたりなどがあれば、コメントで記載頂けると助かります。あるいは全貌を明かした記事を別に作って頂けると嬉しいです。

スポンサーリンク

Docker Desktop が便利

Docker Desktop for Windows は、 WSL2上のUbuntu環境にDocker (CE)をインストールして使うものに比べて、大変便利です。コンテナやイメージの管理をGUIでできるダッシュボードがありますし、インストーラーがあるので最初のセットアップも楽です。

そして何より、コンテナで動かしたサービスが他のPCからもアクセスが可能になっている点が便利です。開発環境であれ、ちょっとした運用環境であれ、コンテナでサービスを作って提供したいことがあります。 Docker on Ubuntu + WSL2 という状況では、このようなものを実現する際に Windowsのポート転送を使う必要があります。またWSL2上に割り当てられるIPアドレスがPCの起動ごとに変化してしまうので、ポート転送の設定は起動ごとに更新する必要があります。これは少々手間が掛かります。

Docker Desktop for Windows ではこれらの設定が不要です。では、Docker Desktopはこれをどのようにして実装・実現しているのかが気になりました。本記事はそれを調べてみた内容を記載しています。

環境情報

  • Windows11 23H2
  • Hyper-V 有効 (管理者コンソール閲覧のため)
  • WSL2 有効で、 Ubuntu 22.04.03 が同居
  • Docker Desktop for Windows
    • 執筆時点では 4.31.1 を使用
    • WSL2 Integration を有効

Windows + WSL2 のネットワーク構造

WSL2を使っている場合、論理的なネットワーク構造は次のような形をとるそうです。ここでは Hyper-Vで仮想マシンが存在するときも含めた構造を記しています。

この状態で Ubuntuの環境にDockerをセットアップし、コンテナを稼働させると以下のような状態になります。Ubuntu上にもう1つネットワークが構築されるイメージです。

このような構造となっているため、コンテナで稼働させているサービスに他のPCからアクセスさせるというのが手間になっています。WSL2 Ubuntu上で素直に動いているサービスについては、wslhost というプロセスが仲介し、Windowsの物理NIC側でのポート待ち受けとWSL2へのパケット転送を行ってくれるため、非Dockerなものを使っているときには不便を感じにくくなっているようです

Windows Subsystem for Linuxガイド 第10回 WSLネットワーク編
WSLは、ネットワーク機能を持ち、WSLディストリビューション上でネットワークを利用するアプリケーションを動作させることができる。基本的には、通常のLinuxと同じ環境だが、ディストリビューション上でサーバーを動作させネットワークを介してサービスを提供することは、WSLの用途としては想定されていない。このため、Win3...

Docker Desktop のネットワーク

ここでのDocker Desktop の場合、WSL2を使用して1種の仮想環境が動作します。WSL2上Ubuntuと同レベルでDocker Desktop専用のものが動作しています。 wsl --list としたときに、”docker-desktop” というデストリビューションが確認できますが、それです。

このとき、docker-desktop と ubuntu 22.04 の環境では、eth0としてどちらも同じIPが割り当てられています。WSL2上の各インスタンスはIPを共用するようですね。

WSL 2 複数インスタンス同一 IP アドレス
WSL 2 で複数の distribution (ここではこれを WSL の「インスタンス」と呼ぶことにします…

コンテナから見えるネットワーク

仮に nginx のコンテナを素の状態で起動して、環境に入ってみました。調査のためのツールをインストールしましたが、そのときに見えたネットワークは以下の状態でした。

  • eth0: 172.17.0.2
  • デフォルトゲートウエイは 172.17.0.1

これらはよく見る docker0 のブリッジネットワークに近いものです。Windowsでは docker0 のブリッジネットワークが使えないと見かけますが、Linux の環境と同じようには使えないという意味かと思います。docker networkコマンドで確認してみると bridge, host, none のネットワークは Windows でもちゃんと存在します。

次に、別のコンテナを観察してみました。そちらは素の状態ではなく、 docker-compose.yml によってサービスが定義されたものです。この場合、ネットワークが別に作られるパターンとなります。このとき、コンテナ内から見えたネットワークは以下の状態でした。

  • eth0: 172.18.0.2
  • デフォルトゲートウエイ: 172.18.0.1

最初のものもこちらのものも、コンテナ内部から googleや yahooなどの Webアクセスができます。デフォルトゲートウエイがそれぞれ別ですが、どうやって外へアクセスしているのかが謎です。ネットワークセグメントも別ですが、それがどのようにルーティングされて物理ネットワークから出て行くのか謎に包まれています。

通信の流れを追う旅を開始

素直に考えれば、WSL2側のネットワーク経路を使って外部へアクセスしているはずです。イメージとしては次のような経路となります。

コンテナの内部から、vEthernet に割り当てられているIPアドレスにpingも通るので、この経路っぽくみえます。また以下のコマンドで Web へアクセスをしても問題なく動きます。

このとき気になる点が、 docker-desktop VM(便宜上VMと付けておきます)で、各コンテナ向けのネットワークが用意されていません。 eth0 と lo のネットワークインタフェースが見えていますが、docker0やbr0 などのデバイスがいないのです。

WSL2上のネットワークアクセスでは、Windowsのインターネット共有の仕組みを使って実現しているという記述があるので、それを手がかりにして調べていきます。

またこの経路の場合、WindowsのデフォルトスイッチやNATが使われてアクセスが可能になっているという記述を見かけました。そこで、通信のときに以下のコマンドを叩いて確認を行いました。PowerShell を管理者権限付きで実行して、このコマンドを実行すると NAT 処理されたものを見ることができます

Get-NetNatSession

コンテナ内から curl コマンドでアクセスした場合、コマンドの実行結果はカラで、何も出力しません。一方で、docker-decktop VMから同じように curl コマンドを実行すると、このGet-NetNatSession コマンドは状態を出力します。この docker-desktop VMからアクセスした直後で実行したものが以下の通りです。

ということで、最初に予想した経路は違う、という結論になりました。どうやら docker-desktop VMを経由していないようです。あらためて、docker-desktop VMからコンテナに向けてpingを実行しても通りませんし、ここからは繋がっていない気配があります。

ブリッジでもされている?

ブリッジされている可能性がどこかにある?ということで、PowerShell でブリッジ状態を確認してみました。

netsh bridge show adapter

ブリッジされているようなものはなく、ここには情報なしでした。

パケットキャプチャを使用してみる

さすがに WSL2向けに用意されている vEthernet は経由しているよね、というチェックをすることにしました。WireShark を使用して、 vEthernet 宛てのパケットを全部キャプチャしてみることにしました。

結論としては、コンテナ内からの外アクセスでは vEthernet を通過していませんでした! もちろん、物理 Ethernet の側でキャプチャを試行してみると、そちらではデータがとれたので別の経路が存在しているということは確認できています。

仲介者の発見

ここまでの情報から「普通のアプリケーションから外向けの通信を発行しているように見える」という助言をもらうことができ、この線から調べてみることにしました。

コンテナ内から定期的に外向きの通信をしつつ、仲介者となるプロセスを調べていくことにしました。手始めに、名前からバックエンドを担当しそうな com.docker.backend.exe 周辺を見ていったのですが、このあたりではありませんでした。

もう少し他にいないか調べてみると、/usr/bin/vpnkit-bridge というプロセスが動いていました。これを停止すると、コンテナ内から外への通信が止まり、プロセス再開すると通信が復帰するという挙動を示しました。おそらくこれが普段の通信をバイパスする役割を担っていると結論づけました。

この仲介役のプロセスに関する詳細は、公式のブログでも語られているようです。私は最初にこの記事も見かけたことがありましたが、VPNの話題と読んでしまいスルーしてしまいました。重要なヒント(というかほぼ答え)が含まれているのに気付きませんでした。

Just a moment...

まとめ

vpnkit-bridge の詳細については追いませんでしたが、このプロセスがコンテナ内からの通信をバイパスする役割を持っていることがわかりました。もしかするとさらにバイパスに関わる他のプロセスがいるかもしれませんが、ひとまずはここまでとしました。

今回の結果を図に示すと次のようになると考えています。docker-desktop (WSL2)は、コンテナとの通信経路をLinuxの場合とは異なる方法で提供します。

Docker Desktop for Windowsがどのようにしてネットワークをコンテナへ提供するか、どうして外からのネットワークを受け付けられるのか、という謎について調べてきました。意外とこの話題について記事を見かけることがなく、本記事をきっかけに追加調査や同様の記事が増えることを願っています。

参考

基礎的な話題も含め、参考にした記事などを以下にリンクします。勉強になったところも多く、感謝申し上げます。

とくに、「Windows内のネットワークを整理:②WSL2編」については図解されたものが少ない情報なので、よい情報でした。

Dockerのネットワーク、基礎理解は万全ですか?【Dockerコンテナ・グレートジャーニー④】 - Qiita
DockerコンテナグレートジャーニーDockerコンテナを0から理解する旅、Dockerコンテナ・グレートジャーニー第4回です。今回はDockerのネットワークについて、少しだけ深い部分に踏み…
Windows内のネットワークを整理:②WSL2編 - Qiita
前回の記事はこちら今回は引き続き、WSL2のネットワークの世界を紹介しようと思います!!今…
ひでみのアイデア帳
Hidemi's Idea Note

コメント

タイトルとURLをコピーしました