WSL に ミラー(mirrored)ネットワークモードが導入されましたが、このモードは構造的には特殊なため大多数が利用する使い方から外れると問題に遭遇することがあります。WSLで最も自然なネットワークモードはブリッジです。しかし、ブリッジネットワークモードは将来削除されるとして2.4.5(24年12月リリース)から非推奨になりました。そもそも、ブリッジは一度も公式には認められていない隠し機能扱いです。
ブリッジモードが使えなくなったときに備えて、現在ブリッジや通常の Linux インスタンスで使用している使い方を評価していると一点問題に遭遇しました。
Dockerコンテナで IPv6 が使えない
コンテナネットワークで IPv6 を有効にした場合、外部と通信できません。具体的にはコンテナを起動させた直後は通信できるのですが、しばらくすると外部に対して通信できなくなります。
Docker で IPv6 を利用する人はまだまだ少ないでしょうし、ましてや外部から IPv6 の到達性というわけでもなく、コンテナネットワーク自体のIPv6化ですからあまり話題にもあがらないですね。
では、再現環境を作ってみましょう。
IPv6 が利用可能な Windows11 に WSL、さらに Docker 実行環境が既に構築されていることを想定しています。
networks:
v6:
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 2001:0db8::/64
services:
v6:
image: alpine
tty: true
container_name: v6
networks:
v6:
この compose.yaml でコンテナを起動します。
$ docker compose up -d
コンテナから google.com へアクセスしてみます。
$ docker exec v6 ping google.com
しばらくすると レスポンスが受け取れなくなって止まってしまいます。
原因は?
コンテナの内外でパケットをキャプチャすると、WSL側からコンテナを見失ってNATが働かなくなります。
WSLのネットワークインタフェースを見ると
8: br-a1e4d2105746: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 3e:a4:5b:29:a9:bf brd ff:ff:ff:ff:ff:ff
inet 172.20.0.1/16 brd 172.20.255.255 scope global br-a1e4d2105746
valid_lft forever preferred_lft forever
inet6 2001:db8::1/64 scope global nodad
valid_lft forever preferred_lft forever
何か足りません。
そう、リンクローカルアドレスがありません。このため、近隣探索に失敗するようです。
犯人は以下の設定でした。
$ sysctl -a | grep addr_gen_mode
net.ipv6.conf.all.addr_gen_mode = 1
net.ipv6.conf.br-1ba8605633f7.addr_gen_mode = 1
net.ipv6.conf.br-24ab74862219.addr_gen_mode = 1
net.ipv6.conf.br-a1e4d2105746.addr_gen_mode = 1
net.ipv6.conf.default.addr_gen_mode = 1
net.ipv6.conf.docker0.addr_gen_mode = 1
net.ipv6.conf.eth0.addr_gen_mode = 1
net.ipv6.conf.lo.addr_gen_mode = 1
net.ipv6.conf.loopback0.addr_gen_mode = 1
net.ipv6.conf.vethb52625e.addr_gen_mode = 1
ミラーモードでは、Windowsのネットワーク設定を射影するので独自にリンクローカルアドレスをつけないように addr_gen_mode を 1 に設定しているようです。
解決するには?
addr_gen_mode = 0 (=デフォルト値)を設定するだけです。addr_gen_mode を 1にしないといけないのは eth0など Windowsから写し取ったインタフェースだけなのでデフォルトを 0 に戻しておけばよさそうです。
systemdを有効にしている場合には以下の設定を作っておけばよいでしょう。
net.ipv6.conf.default.addr_gen_mode = 0
こうすることで、dockerd が生成したネットワークは addr_gen_mode=0 になり、リンクローカルアドレスが生成されるようになります。上記設定ではパラメータの変更ができない場合には起動時に以下のコマンドを実行すれば良いでしょう。
sudo sysctl net.ipv6.conf.default.addr_gen_mode=0
副作用の確認
default.addr_gen_mode を変えてしまって副作用はないか?
WSL起動中に Windowsのネットワークに変化があった場合どうなるでしょう?
そこで、USB-LANアダプタをさしてみました。eth1 が生えてきて、eth1.addr_gen_mode は 1 になっていました。WSL(/init?) が操作するインタフェースはすべて addr_gen_mode=1になるようですから、デフォルトを変更しても問題なさそうです。