WSL2 + Docker Desktop上で動かしているMySQLへ、VirtualBoxのゲストOSから接続する。
今回の環境では、DockerのMySQLをホストWindowsの3307番ポートに公開していた。
0.0.0.0:3307->3306/tcpしかし、VirtualBoxから、
<ホストPCのIPv4>:3307へ直接接続することはできなかった。
最終的にはWindowsのportproxyを使って、
VirtualBox ↓Windowsホスト ↓portproxy ↓localhost:3307 ↓Docker Desktop / WSL2 ↓MySQL:3306という経路を作ることで接続できた。
この記事では、その設定手順だけまとめる。
実際に「Dockerでポート公開してるのになんで繋がらんねん」と順番に調べた記録はこちら。
前提
今回確認した環境は以下。
ホストPC├─ Windows├─ WSL2├─ Docker Desktop│ └─ MySQLコンテナ│└─ VirtualBox └─ WindowsMySQLコンテナは、
コンテナ側 : 3306Windows側 : 3307として公開している。
まずdocker psで確認する。
docker psMySQLのPORTSが今回の環境では以下のようになっていた。
0.0.0.0:3307->3306/tcp以下では、この3307をDocker Desktop上のMySQLへ接続するポートとして扱う。
1. ホストWindowsのIPv4アドレスを確認する
ホストWindowsで、
ipconfigを実行する。
WSL2やVirtualBoxが入っていると複数のネットワークアダプターが表示される。
今回使用したのは、ホストPCが実際のネットワーク接続に使っているアダプターのIPv4アドレス。
Wi-Fi接続なら、例えば以下のような箇所を見る。
Wireless LAN adapter Wi-Fi:
IPv4 Address. . . . . . . . . . . : 192.168.x.x以降、このアドレスを、
<ホストPCのIPv4>とする。
2. localhostからMySQLの公開ポートへ接続できるか確認する
ホストWindowsで、
Test-NetConnection localhost -Port 3307を実行する。
今回の環境では、
TcpTestSucceeded : Trueとなった。
ここがFalseなら、今回とは状況が違う。
今回解決したのは、
localhost:3307 → Trueなのに、
<ホストPCのIPv4>:3307 → Falseとなるケース。
3. portproxyでVirtualBox向けの入口を作る
Windowsの管理者PowerShellを開く。
今回の切り分けでは、まず13307番ポートを入口として設定した。
netsh interface portproxy add v4tov4 ` listenaddress=0.0.0.0 ` listenport=13307 ` connectaddress=127.0.0.1 ` connectport=3307これで、
Windows:13307 ↓localhost:3307へ転送する。
設定は以下で確認できる。
netsh interface portproxy show all今回なら、
0.0.0.0 13307 → 127.0.0.1 3307という形になる。
4. Windows Firewallで13307を許可する
VirtualBoxからWindowsの13307へ接続するため、受信を許可する。
管理者PowerShellで、
New-NetFirewallRule ` -DisplayName "VirtualBox to Docker MySQL 13307" ` -Direction Inbound ` -Protocol TCP ` -LocalPort 13307 ` -Action Allowを実行する。
5. ホストWindows自身から確認する
まずVirtualBoxへ行く前に、ホストWindows自身から確認する。
Test-NetConnection <ホストPCのIPv4> -Port 13307今回の環境では、
TcpTestSucceeded : Trueになった。
ここがTrueになってからVirtualBox側を確認する。
6. VirtualBoxから確認する
VirtualBoxのゲストWindowsで、
Test-NetConnection <ホストPCのIPv4> -Port 13307を実行する。
こちらも、
TcpTestSucceeded : Trueになれば、VirtualBoxからWindowsホストのportproxyまで通信できている。
今回確認できた経路はこう。
VirtualBox ↓<ホストPCのIPv4>:13307 ↓Windows portproxy ↓127.0.0.1:3307 ↓Docker Desktop / WSL2 ↓MySQL:33067. アプリ側でポートを指定できない場合
今回もう一つ引っかかったのがこれ。
接続対象のアプリに、MySQLのポート番号を指定する設定が見当たらなかった。
13307を指定できないのであれば、VirtualBoxから見える入口自体をMySQL標準の3306番にすればいい。
13307の設定を削除する場合は、
netsh interface portproxy delete v4tov4 ` listenaddress=0.0.0.0 ` listenport=13307そして3306を入口にする。
netsh interface portproxy add v4tov4 ` listenaddress=0.0.0.0 ` listenport=3306 ` connectaddress=127.0.0.1 ` connectport=3307経路はこうなる。
VirtualBox ↓<ホストPCのIPv4>:3306 ↓Windows portproxy ↓127.0.0.1:3307 ↓Docker Desktop / WSL2 ↓MySQL:3306Firewall側でも3306の受信を許可する。
New-NetFirewallRule ` -DisplayName "VirtualBox to Docker MySQL 3306" ` -Direction Inbound ` -Protocol TCP ` -LocalPort 3306 ` -Action AllowVirtualBox側から、
Test-NetConnection <ホストPCのIPv4> -Port 3306がTrueになれば、ポート指定できないアプリからも通常のMySQLポートとして接続できる形になる。
うまくいかないときの切り分け
今回の調査で役に立ったのは、いきなりVirtualBoxから確認するのではなく、接続経路を順番に見ることだった。
① localhost:3307 ↓② ホストIPv4:portproxyのポート ↓③ VirtualBox → ホストIPv4:portproxyのポート例えば、
Test-NetConnection localhost -Port 3307がFalseなら、まずDocker Desktop側までの接続を見る。
これがTrueで、
Test-NetConnection <ホストPCのIPv4> -Port 13307がFalseなら、Windows側のportproxyやFirewallを確認する。
ホスト自身からTrueなのにVirtualBoxからFalseなら、そこからVirtualBoxとWindowsホスト間の通信を疑う。
一気にMySQLまで見ようとせず、
「どの地点まではTrueなのか」
を見ると切り分けしやすい。
補足:3307 → 3307のportproxyではうまくいかなかった
今回最初は、
0.0.0.0:3307 ↓127.0.0.1:3307というportproxyを作った。
設定自体は、
netsh interface portproxy show allで表示された。
IP HelperサービスもRunningで、IPv6のバインドも有効だった。
しかし、
netstat -ano | findstr :3307ではLISTENしている状態を確認できず、Test-NetConnectionもFalseのままだった。
そこで入口を13307へ変更したところ、接続できるようになった。
そのため今回の環境では、
13307 → 3307のように別ポートを入口として使っている。
なお、ここでは「なぜ3307→3307ではLISTENしなかったのか」までは確認していない。
今回実際に確認できたのは、
3307 → 3307 接続できなかった
13307 → 3307 接続できたというところまで。
まとめ
今回の環境では、VirtualBoxからDocker Desktop上のMySQLへ直接接続するのではなく、
VirtualBox ↓Windowsのportproxy ↓Docker Desktop / WSL2 ↓MySQLという経路を作ることで接続できた。
ポイントは、docker psで、
0.0.0.0:3307->3306/tcpと表示されていることだけで判断せず、
localhost → Windows自身のIPv4 → VirtualBoxと順番にTest-NetConnectionしていくこと。
今回はその切り分けをしていった結果、Windows側にportproxyで入口を作るところまでたどり着いた。
遠回り込みでどうやってここにたどり着いたかは、本編にまとめている。