🔥

アップデートされたWSL2を使用して、WSL2上のDocker-CEは快適になるか

2024/07/06に公開

はじめに

ライセンス変更の話からずいぶん経ち、Docker Desktop の話題も落ち着いたように見えます。仕事で使っている場合には色々と大変だったと思いますが、今も個人で利用する範囲では Docker Desktop を無料で使えます。

本記事ではDocker Desktopを使わずに、WSL2 (Windows Subsystem for Linux 2)を使用して環境を作ります。何番煎じだろうかという話でもありますが、WSL2に入った新機能などで従来よりも使い勝手がよくなったのかを確認してみました。個人的に、当時の制約から解放されて便利になったのではという期待がありました

環境情報

Ubuntu 24.04 LTSを使用します。Microsoft Storeからインストールします。

WSL2環境情報

Windows11 23H2 の環境を使っています。
この環境において、WSL2のバージョンは以下のような状態となっていました。

>wsl --version
WSL バージョン: 2.2.4.0
カーネル バージョン: 5.15.153.1-2
WSLg バージョン: 1.0.61
MSRDC バージョン: 1.2.5326
Direct3D バージョン: 1.611.1-81528511
DXCore バージョン: 10.0.26091.1-240325-1447.ge-release
Windows バージョン: 10.0.22631.3737

ここで注目なものが WSL2のバージョンで2.2.4という部分です。いくつかの機能が実験的機能としてリリースされていましたが、徐々に正式な機能に格上げされてくると思われます。
リリースノートを見ると、2.0.5の時点で以下の機能が設定ファイル上Promoteされていました。正式な一般機能までもう少しですかね。

  • experimental.dnsTunneling -> wsl2.dnsTunneling
  • experimental.firewall -> wsl2.firewall
  • experimental.networkingMode -> wsl2.networkingMode
  • experimental.autoProxy -> wsl2.autoProxy

今となってはかなり昔ですが、WSLの環境ではLinux GUIのアプリケーションを動かすのが手間でした。最近ではWSLgが搭載されているので、その点もラクになりました。

簡易まとめ

割と先が長くなっているので、結論が知りたい人向けにまとめておきました

  • WSL2+Dockerについてはあまり改善なし
    • 現時点において networkingMode=mirrored では解決できない
    • メモリ問題に苦しんでいるようなら、autoMemoryReclaim の設定で改善
      • autoMemoryReclaim=gradual
  • Dockerを使わないWSL2上でのサービス提供という観点ならば恩恵はありそう
    • このときに networkingMode=mirroredは有効

Ubuntu 24.04 LTSセットアップ

Microsoft StoreからUbuntu 24.04を検索して、「入手」のボタンを押してシステムにインストールします。
インストール後は、スタートメニューから「Ubuntu 24.04 LTS」を探して起動します。初回はユーザー名とパスワードを設定します。これはWSL2 Ubuntu 24.04の環境内で使用するものです。

ユーザーの作成が終わったら、sudo apt update を実行してパッケージリストの更新を行っておきます。

Docker のインストール

WSL2 Ubuntu 24.04 LTSの環境で、Docker-CEをインストールします。インストールは以下のコマンドを実行して行います。ここでは普段使用するユーザーで、dockerコマンドを実行する際に sudo を付与する手間を避けるため、dockerグループに現在のユーザーを追加させています。

wsl-shell
$ cd $HOME
$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh
$ sudo usermod -aG docker $USER

ユーザーのグループへの追加を反映させるため、作業中のシェルをログアウトで抜けます(ウィンドウを閉じてもよいです)。

余談ですが、WSLの環境でDockerをインストールしようとしたときに、このようなメッセージが表示されます。Docker Desktop for Windowsをオススメされています!

# Executing docker install script, commit: 6d9743e9656cc56f699a64800b098d5ea5a60020

WSL DETECTED: We recommend using Docker Desktop for Windows.
Please get Docker Desktop from https://www.docker.com/products/docker-desktop/

You may press Ctrl+C now to abort this script.

さてインストール後、表示されるバージョン情報は以下の状態となっていました。本記事の後半はこの状態で記載したものとなっています。

Client: Docker Engine - Community
 Version:           27.0.3
 API version:       1.46
 Go version:        go1.21.11
 Git commit:        7d4bcd8
 Built:             Sat Jun 29 00:02:23 2024
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          27.0.3
  API version:      1.46 (minimum version 1.24)
  Go version:       go1.21.11
  Git commit:       662f78c
  Built:            Sat Jun 29 00:02:23 2024
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.7.18
  GitCommit:        ae71819c4f5e67bb4d5ae76a6b735f29cc25774e
 runc:
  Version:          1.7.18
  GitCommit:        v1.1.13-0-g58aa920
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

簡単な動作確認

定番のHello Worldを試しておきます。以下のコマンドを実行して、"Hello from Docker!" の表示が確認できればOKです。

$ docker run hello-world

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:94323f3e5e09a8b9515d74337010375a456c909543e1ff1538f5116d38ab3989
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

続いて、wslinfoコマンドを使って、ネットワークの状態を見ておきます。ここでは"nat"が出力されました。

$ wslinfo --networking-mode
nat

動作確認いろいろ

サーバーとしてWebサーバーを用意してみます。ここではnginxを使って、以下のような起動をさせてみます。これはコンテナの外側からポート8080でWebサーバーへアクセスできる設定です。

$ docker run --rm -p 8080:80 nginx:latest

このポートにWindows側のブラウザを使ってアクセスすると、以下のようにページが表示され、期待通りの結果となります。

このとき、同じネットワーク上にいる別のPCやスマホなどから、このページにアクセスできるかを確認してみます。アドレスはPCに割り当てられているものを使う点に注意です。

おそらく、アクセス不能でページが表示されない結果になるでしょう。Docker Desktopを使った場合との差違として定番のものです。
これを解決するためには、Windows側でWSL2側のIPアドレスを調べてポートフォワードを設定することや、ファイアウォールの設定を修正するなどが挙げられます。が、ここでは新機能を用いて対処にトライしていきます。

ネットワークモードの変更

ネットワークモードを nat から変更します。これには、設定ファイルを開きwsl2.networkingModeのパラメータを変更します。

Windowsのエクスプローラーから%USERPROFILE%の場所にある .wslconfig ファイルを開きます。このファイルがなければ、メモ帳で新規にファイルを作成します。
そしてこのファイルの中のwsl2セクションに以下のnetworkingMode=mirroredを追加します。

[wsl2]
networkingMode=mirrored

一度設定を反映指せるためにはWSL2の再起動が必要なので、他のWindowsのプロンプトから wsl --shutdown を実行して、再起動させるようにしてください。
そして、再びWSL2 Ubuntu 24.04の環境に入ってネットワークモードを確認してみると、以下のような結果が得られます。

$ wslinfo --networking-mode
mirrored

このとき、ip addr show などとしてネットワークインタフェースの状態を見てみると、Windows側に付与されているアドレス情報と同じものが設定されていることが確認できます!

アクセスできない!

先の設定で自身のIPアドレスがWSL2のほうで見える状態となりましたが、まだアクセスはできません。それどころか、localhost:8080 でアクセスしてもnginxのサーバーにアクセスできなくなってしまっています。
背後にあるWSL2のネットワークの仕組みに依存するようで、dockerでのサービス起動において、以下のように --host のネットワーク指定を付けて起動するとよいようです。

docker run --network=host nginx:latest

そしてHyper-Vファイアウォールの設定で、コンテナが使用するポートについてアクセスができるように開放処理を行います。GUIの画面は今のところ標準で用意されていないみたいなので、以下のコマンドを実行します。
この操作には管理者権限のついたPowerShellで行って下さい。

PowerShellにて Hyper-Vファイアウォールを設定(ポート開放)
New-NetFirewallHyperVRule -Name "MyWebServer" -DisplayName "My Web Server" `
-Direction Inbound -VMCreatorId '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}' `
-Protocol TCP -LocalPorts 80

以上の設定により、LAN内の他のPCからもhttp://(your-ip-address)/にアクセスして、nginxのページを表示できるようになりました。 しかし、先に書いたように-pによるポートの変換ができないことや、コンテナで使用するポート全てがWindows側で未使用でないといけなかったりなど、制約が多いのも確かです。

ルールを削除するには、以下のコマンドを実行します。

PowerShellにて後始末
Remove-NetFirewallHyperVRule -Name "MyWebServer"

Mirroredを諦め、ポートフォワードの設定について

ネットワークのモードは諦めてデフォルトのnatに戻します。WSL2のネットワークに対してポートフォワードを行うことで、外部からのアクセスもできるよう構成できます。注意点として、WSL2側に割り当てられるIPアドレスは起動ごとに変化をするので、設定適用は毎回必要です。

Windows側で以下のコマンドを実行してポート転送の設定を行います。既に設定がある場合には、削除してから転送設定を行う必要があります。

# ポートフォーワード設定
netsh interface portproxy add v4tov4 listenaddress=* listenport=<ポート番号> connectaddress=(WSL2側のIP) connectport=<ポート番号>";

# ポートフォーワード設定削除
netsh interface portproxy delete v4tov4 listenport=<ポート番号>

ここでWSL2側のIPアドレスはWindows側のコマンドから知ることができます。

> wsl -e hostname -I
172.29.0.216 172.17.0.1

このように表示され、最初の1つめのものがWSL2についたアドレスとなっていました。2つめはDockerが使用しているI/Fとなっています。

メモリについて

以下の記事にて、メモリの挙動についての説明がありました。これまでと違いメモリ解放されていくようになるので気付いたらメモリ使用量 100%というのは回避できそうです。

https://zenn.dev/takajun/articles/3acd9f77c73bb4

まとめ

  • コンテナでサービスを稼働させ、それを他のPCからアクセスさせたいのであれば Docker Desktopを使うのがよい
    • この観点では執筆時点では従来からの改善はない
    • mirroredモードと--network=hostの併用で一応コンテナ内サービスを展開できるが、利用場面は限られそう
  • 自分のみがWindows環境からWSL2上のコンテナへアクセスしたいならば、問題なく使えそう
    • localhostForwarding=true の設定を明示的に記述しておくとトラブルは少なめ
    • この点でも従来からの劇的な変化はなさそう

WSL2に入った新機能は、WSL2上Dockerの部分を改善はすること少ないというのが自分の結論でした。今後、本記事に記載した内容が改善される可能性は残っていると思うので、気長に待ちたいと思います。それまでは Docker Desktop を使う、ですかね。

Discussion