前回の記事はこちら
今回は引き続き、WSL2のネットワークの世界を紹介しようと思います!!今回のアジェンダは以下です。
- WSL2は仮想マシンのNetwork設定のやり方
- WSL2は仮想マシン全てに同じIPを割り当てているが、こう回避しているのだ
この2点をお話しようと思います。
WSL2の仮想マシンのNetwork設定のやり方
何から話しますかね。まずはWSL2で名前解決出来なくてそもそも通信できない話をよく聞くので、そのトラブルシューティングをしながら話を進めましょう。
名前解決ができない!
$ curl -I google.com
curl: (6) Couldn't resolve host 'google.com'
このエラーメッセージ見たら、確認すべきは/etc/resolv.conf
です。
そんな事知ってるんですけど? って方もいるでしょうが落ち着いてください。
WSL2で気を付けなくてはいけないのは、/etc/resolv.conf
が毎回生成されてしまうという事です。
解決方法
/etc/resolv.confを編集する
標準的には以下を定義すれば問題ありません。
nameserver 8.8.8.8
nameserver 8.8.4.4
ただ、社内でDNSサーバ持ってる場合とかはWindows側のDNS設定を確認して、同じIPにしちゃってくださいね!
次に、この設定が消されないように設定する方法です。
/etc/resolv.confを再生成しなくする
まずは、WSLの設定を変更するために以下を記述します。
[network]
generateResolvConf = false # /etc/resolv.confを再生成しなくする
と、ここまではよく説明見かけるのですが、更に以下もやっておかないとなぜか消されます...
$ chattr +i /etc/resolv.conf
一応上記はファイルシステム(ext2とか3のあれ)に対して変更禁止を促す命令になります。つまり、
私:wsl.confに書いたけど、再生成しないでね!
WSL:わかった!再生成はしないね!(変更しちゃうけどな!)
って事でしょうか?そんなバカな...
ともあれ、これで名前解決の問題解決ですね!
ではWSL2を2台用意して、更に通信がどうなっているのか調べてみましょう!
ここでは、UbuntuとCentOS7を用意して確認を進めました。
WSL2は仮想マシン全てに同じIPを割り当てている!通信はどう流れるのか
いや、「同じIPが同じ仮想Switch上で振られているとか動くわけないじゃないですか」と思うなかれ。
oh..ほんまに同じIP振られとる... じゃこれどう通信が振り分けられてるのでしょうか?
※画像ではIPアドレスが172.18.100.50
となってますが、後続の説明は前回の記事と同じIP想定で資料作ってます。
試しにUbuntu側でWebServerを立ててみよう!
まずServerを立てる前にPowerShellで以下のコマンドを実行して、80ポート使われてないかを確認。
> netstat -ano | findstr :80
# 何も出ない
次にUbuntu側でWebServer立てるわけですが、今回はSimpleにPythonで以下のように起動させました。
$ sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
じゃもう一度PowerShellでPort80を使ってる人いないかを確認してみましょう!
> netstat -ano | findstr :80
TCP 127.0.0.1:80 0.0.0.0:0 LISTENING 19024
TCP 172.19.17.152:42892 163.139.173.139:80 ESTABLISHED 22936
> tasklist /FI "PID eq 19024"
イメージ名 PID セッション名 セッション# メモリ使用量
========================= ======== ================ =========== ============
wslhost.exe 19024 Console 3 4,740 K
でました!wslhost.exe このプロセスが80番ポートで受け付けてますね!
という事は、Windowsにきた通信はwslhost.exeがキャッチしてUbuntuに渡してくれるのか?
試してみましょう!
Windowsでlocalhsotに通信してみる
ブラウザでlocalhost
を開いてみましょう。するとUbuntu
側のコンソールはこうなるはず。
※PowerShellからやるならcurl -I localhost
とかが手軽です。通信経路は同じ。
$ sudo python3 -m http.server 80 # さっき立てたWebServerです。
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
127.0.0.1 - - [12/Dec/2023 20:30:04] "GET / HTTP/1.1" 200 -
127.0.0.1
から通信がきてますね!
図であらわすと以下
点線はホストOSを外部に公開している通信も含めた時の話で、
実際の所は赤い実線がlocalhostに向けた内部通信になります。
WindowsでWSL2のIPにアクセスしてみる
では、172.18.110.165
にアクセスするとどうなるのか?
127.0.0.1 - - [12/Dec/2023 20:30:04] "GET / HTTP/1.1" 200 - # localhost
172.18.96.1 - - [12/Dec/2023 20:41:20] "GET / HTTP/1.1" 200 - # WSL2のIP指定
アクセス元のIPが代わりましたね!ご存知の通り、仮想スイッチ経由になりました。
図であらわすとこうですね!
ちなみにWSL2では同時に同じポートでのLISTENは受け付けてくれないので、衝突は発生せず先勝ちとなるようでした。通信経路が見えると色々わかってきますね!
最後に
はい、内部の通信について理解が深まったでしょうか?
おそらく次の疑問としては、WSL2を外部からアクセス可能にするためにはどうしたらいいのだろうか?とか思う人もいるんじゃないでしょうか。私はその必要に迫られた事はないので試してませんが、おそらくの答えとしては、仮想スイッチ[WSL]を外部ネットワークに変更し、物理NIC[WiFi]に繋げる事で外部からのアクセスもできると予想されます。
あとは、Hyper-Vが通信受けられるようにWindowsのファイアウォールとかの調整も必要かもしれませんね。
仕組みを理解出来ていれば、このように外部通信からの応用やエラーの原因究明もスムーズに行う事ができます。
みなさんも、これまで理解せず使っていた機能とかがどうなっているのか調べてみてはいかがでしょうか!
気が向いたら第3回としてDockerも含めた内部Network整理しようと思います!
お疲れ様です!