今回は、前回の続きで、docker engineをWSLにインストールした場合、コンテナとネットワーク通信を行う場合を考える。基本的な事項などに関しては、前回記事「第37回 WSL2でDockerを使う その3」を参照していただきたい。
この連載では、WSL上にdocker engineをインストールして利用することを「Dockerエンジン」と表記し、docker desktopの利用(Dockerデスクトップ)と区別している。Dockerデスクトップの場合については上記の前回記事を参照してほしい。
評価は、WSL バージョン2.1.5.0(Linuxカーネル バージョン5.15.146.1-2)、をWindows 11 Ver.23H2(OSビルド10.0.22631.3737)の上で行った。docker desktopのバージョンは4.30.0(149282)、dockerエンジンのバージョンは、26.1.1である。
ここでは、話を単純にするため、WSLのファイアウォール機能は無効にしてある(詳細は前掲の前回記事を参照のこと)。
WSLのネットワークには、networkingモードがあり、NATモードとMirroredモードを切り替えることができる。両者の違いを簡単にまとめた表(表01)を再掲しておく。
Dockerには、コンテナのネットワーク接続は「コンテナ用ネットワーク(bridge)」、「ホストネットワーク(host)」および、「ネットワークなし(none)」の3つがある。これらはdocker runコマンドの起動オプション(--net)で指定できる。また、デフォルトでは、コンテナを管理するdockerデーモン(dockerd)は、IPv4でのみ動作し、IPv6を使うには、別途Dockerエンジンの設定が必要になる。
結論からいうとDockerエンジンの場合、NATモードでWin32側からのアクセスを可能にするには、Win32側のIPアドレスを使う。あるいは、localhostForwardingを有効にする。これにより、WSL側へのlocalhostおよび127.0.0.1でのアクセスが可能になる。可搬性があることがコンテナの特徴であり、そのためのスクリプトなども可搬性があることが望ましい。この点から言えば、Win32側でスクリプトやURLショートカットなどを使う場合には、localhostForwardingを使う。これで、コンテナで動作するネットワークサービスにlocalhostでアクセスが可能になり、スクリプトやURLショートカットにも可搬性ができる。
LAN側からのアクセスを行わせたい場合、WSLのネットワークモードをMirroredにする必要がある。WSLがMirroredネットワークの場合、Win32側からコンテナにアクセスする場合、コンテナをホストネットワーク(host)で起動する。
NATモードの場合
WSLでDockerエンジンを使うのは、例えていえば、仮想マシンの中で動作しているLinuxでDockerを使うのと似ている。つまり、コンテナのホストは物理マシンではなく、直接ネットワークに接続しているわけでもない。このため、一般的な物理マシン上で動作しているLinuxでDockerを使うのとは環境が少し異なることに注意する必要がある。
それでは、NATモードの場合を具体的に見ていくことにしよう。(表02)は、NATモード時に、Dockerエンジンのコンテナで動作しているサービス(ここでは前回同様nginxを使った)のネットワーク接続を調べたものだ。ここでは、Win32側、同一マシン上のWSLディストリビューション側、LAN側からアクセスを試みた。ホストアドレスとしてlocalhost、127.0.0.1、Win32側IPv4アドレス、WSL側IPv4アドレスを試した。
NATモードの場合、WSLとWin32側は異なるIPアドレスを持ち、かつ、WSL側ではIPv6を利用できないため、URL指定ではIPv6アドレスを使うものは含めていない。
前述のように.wslconfigでlocalhostForwardingを有効にする。具体的には、ユーザーのホームディレクトリ(C:\User\<ユーザー名>)にある.wslconfigの[WSL2]セクションに以下の記述を入れる。
[wsl2]
localhostForwarding=true
この.wslconfigファイルに関しては、過去記事「Windows Subsystem for Linuxガイド 第3回 WSL2動作設定編」を参照されたい。
このlocalhostForwardingは、WSLディストリビューション側でListenしているTCPサービスに関しては、Win32側でlocalhostまたは127.0.0.1でのアクセスを可能にするもの。コンテナであるかどうかには直接関係ない。通常、これを有効にしておいても、特に問題になることはない。
ただし、Win32側とWSL側で、同一ポート番号を使うことはできない。基本的には、ポート番号の利用は、早い者勝ちである。コンテナの場合、ポート番号は簡単に変更できるので、万一衝突するような場合には、変更した方がいいだろう。もちろん、Win32側のサービスを止めるというやり方でも可能だ。
NATモードでは、DockerエンジンのコンテナをLAN側からアクセスすることができない。これは、WSLディストリビューション上のプロセスでも同じである。Dockerデスクトップの場合、Win32側に、LAN側からのネットワークアクセスを受け付け、コンテナ側にルーティングする機能があり、何もしなくてもLAN側からのアクセスが可能になる。この機能と、WSLの標準状態やDockerエンジンの場合を混同しないように注意されたい。
Win32側でPortProxyを設定することで、NATモードでも、LAN側からWSL側へのネットワーク接続が可能になる。ただし、設定は、再起動ごとに行う必要があり、スクリプトを作成し、システムの起動時に実行させるなど、結構面倒な作業が必要になる。このため、LAN側からDockerエンジンのコンテナへのアクセスを行わせたい場合には、Mirroredモードの利用をお勧めする。
PortProxyに関しては、Microsoftのドキュメント「WSL を使用したネットワーク アプリケーションへのアクセス」を参照されたい。
Mirroredモードの場合
Mirroredモードの場合のWin32、WSL、LAN側からアクセスをまとめたのが表03である。
WSLがMirroredネットワークの場合、WSLは、ホスト側Win32と同じIPアドレスを使う。しかし、このとき、WSLでのコンテナの待ち受けがワイルドカード(0.0.0.0。ホスト上のすべてのネットワーク・インターフェースを表す)だと、パケットがコンテナへ転送されない。
この問題を解決するには、コンテナの起動オプションに「--net=host」を追加し、ホストネットワーク(host)で動作させる。これにより、Win32側からLocalhost/127.0.0.1や、Win32側ホストアドレスでのアクセスが可能になる。
Dockerエンジンでは、標準設定でIPv6に対応していないため、Mirroredネットワークにしただけでは、コンテナにIPv6ではアクセスできない。DockerエンジンでのIPv6利用(デュアルスタック)の設定に関しては、本稿の範囲を超えるため、Dockerのドキュメントなどを参照してほしい。
WSLのMirroredモードの特徴として、LAN側からWSL上のサービスへのアクセスが可能になる。これは、Dockerコンテナでも有効。また、このとき、コンテナのネットワークは、bridgeでもhostでも同じである。このため、Dockerエンジンの場合、コンテナを常にホストネットワーク(host)で動作させることができる。利用方法によってコンテナ起動オプションを使い分けるよりも、Mirroredモードでは、常にホストネットワーク(host)を使うとする方が覚えやすい。
ネットワークモードをMirroredにすると、.wslconfigのlocalhostForwarding設定が無効になる。WSLの起動時にメッセージが表示されるが、そのままにしておいても問題はない。
Dockerエンジンの場合にLAN側を含めて、サービスを行わせるには、Mirroredモードを利用する方がよさそうだ。なお、Win32側、WSL側からだけアクセスできればよい、というのであれば、NATモードのままでもよい。
> Windows Subsystem for Linuxガイド 連載バックナンバー
https://news.mynavi.jp/tag/winsubsystem/