1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WSL2 + VPN環境でDockerコンテナから外部サーバーに繋がらない?MTUが原因かも

1
Posted at

はじめに

WSL2のDev Container環境でVPNに接続中 mvn install を実行したら、プライベートMavenリポジトリへの接続がタイムアウト。

結論から言うと、MTU(Maximum Transmission Unit)の問題でした。

同じ沼にハマっている人の助けになればと思い、原因の切り分けから解決までの流れを残しておきます。

環境

  • ホストOS:Windows(VPNはWindows側で接続)
  • WSL2:Ubuntu 22.04
  • Docker:28.x(WSL2内で稼働)
  • IDE:Cursor(Dev Containers拡張でコンテナ起動)

症状

Dev Container内でMaven Installを実行すると、プライベートリポジトリへの接続でタイムアウトが発生。

[FATAL] Non-resolvable parent POM:
  Could not transfer artifact from/to private-maven-repo
  (https://private-gitlab.example.com/...):
  Connect to private-gitlab.example.com:443 failed: Read timed out

原因の切り分け

ここからが本題です。VPNなしでコンテナを起動し、後からWindows側でVPN接続した状態で確認していきます。

Step 1:コンテナ内から疎通確認

$ curl -v --connect-timeout 5 https://private-gitlab.example.com
* Trying 203.0.113.10:443...
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* Connection timed out after 5000 milliseconds

TLS Client Helloを送った後にタイムアウト。接続自体はできていない。

Step 2:WSL側(コンテナの外)から確認

$ curl -v --connect-timeout 5 https://private-gitlab.example.com
* Connected to private-gitlab.example.com (203.0.113.10) port 443 (#0)
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* SSL connection timeout

TCP接続は成功しているのに、TLSハンドシェイクでタイムアウト。これがヒントでした。

Step 3:MTUの確認

# WSL側
$ ip link show eth0
2: eth0: ... mtu 1400 ...

# コンテナ側
$ docker exec <container> cat /sys/class/net/eth0/mtu
1500

VPNはパケットを暗号化のために追加ヘッダーで包むので、実際に流れるパケットサイズが元より大きくなります。MTUが大きいままだとこのオーバーヘッド分だけサイズ超過してパケットがドロップされる、というのが原因でした。

解決手順

WSL2・Docker・コンテナのMTUをすべて1200に下げることで解決しました。

VPNなしでDev Containerを起動した後、Windows側でVPN接続してから以下を実行します。すべてWSL側(コンテナの外)で実行します。

1. WSL2のMTUを下げる

sudo ip link set eth0 mtu 1200

この時点でWSLからの疎通を確認:

curl -v --connect-timeout 10 https://private-gitlab.example.com
# → TLSハンドシェイクが通るようになる!

2. DockerブリッジのMTUを下げる

sudo ip link set docker0 mtu 1200

3. コンテナを再起動する

docker restart <container-name>

4. コンテナ内のMTUを下げる

コンテナ内に ip コマンドがない場合は、nsenter でホスト側から変更できます。

PID=$(docker inspect -f '{{.State.Pid}}' <container-name>)
sudo nsenter -t $PID -n ip link set eth0 mtu 1200

5. 疎通確認

docker exec <container> curl -vk --connect-timeout 10 https://private-gitlab.example.com
# → HTTP 302が返ってくれば成功!

6. ビルド実行

docker exec -it <container> bash
cd /workspace
./mvnw install -s ./settings.xml -Dmaven.test.skip=true
# → 成功!

注意点

MTU設定は永続化されない

ip link set によるMTU変更は一時的なもののようで、以下のタイミングでリセットされるみたいです:

  • WSLの再起動(wsl --shutdown
  • コンテナの再作成(Rebuild Container)

VPN経由のビルドが必要になるたびに、手順1〜4を再実行してください。
(毎回打つのは面倒なので、スクリプト化しておくと便利です。)

おしまい!

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?