WSLのディストリビューションを自作してみる
公開日:
最終更新日:
TL;DR
DOCKER_IMAGE_NAME="busybox:latest"
CONTAINER_NAME="wsl_export"
DISTRIBUTION_NAME="BusyBox"
docker container create --name $CONTAINER_NAME $DOCKER_IMAGE_NAME
docker container export $CONTAINER_NAME > /mnt/c/path/to/rootfs.tar
docker container rm $CONTAINER_NAME
wsl.exe --import $DISTRIBUTION_NAME C:/path/to/install-location C:/path/to/rootfs.tar
wsl.exe --distribution $DISTRIBUTION_NAME
はじめに
私は普段、Windows 11なデスクトップパソコンにインストールしたWSL(Ubuntu)上で諸々の趣味開発をしています。しかしLinuxディストリビューションとしてはUbuntuよりArch Linuxの方が使い慣れていて、できることならUbuntuではなくArch Linuxを使いたいと以前から感じていました。幸いなことに、WSLは標準で様々なLinuxディストリビューションをサポートしていて、その中にはArch Linuxもあります。
$ wsl.exe --list --online
インストールできる有効なディストリビューションの一覧を次に示します。
'wsl.exe --install <Distro>' を使用してインストールします。
NAME FRIENDLY NAME
AlmaLinux-8 AlmaLinux OS 8
AlmaLinux-9 AlmaLinux OS 9
AlmaLinux-Kitten-10 AlmaLinux OS Kitten 10
AlmaLinux-10 AlmaLinux OS 10
Debian Debian GNU/Linux
FedoraLinux-42 Fedora Linux 42
SUSE-Linux-Enterprise-15-SP6 SUSE Linux Enterprise 15 SP6
SUSE-Linux-Enterprise-15-SP7 SUSE Linux Enterprise 15 SP7
Ubuntu Ubuntu
Ubuntu-24.04 Ubuntu 24.04 LTS
archlinux Arch Linux
kali-linux Kali Linux Rolling
openSUSE-Tumbleweed openSUSE Tumbleweed
openSUSE-Leap-16.0 openSUSE Leap 16.0
Ubuntu-20.04 Ubuntu 20.04 LTS
Ubuntu-22.04 Ubuntu 22.04 LTS
OracleLinux_7_9 Oracle Linux 7.9
OracleLinux_8_10 Oracle Linux 8.10
OracleLinux_9_5 Oracle Linux 9.5
openSUSE-Leap-15.6 openSUSE Leap 15.6
しかしそもそもの話として、私はWSLにおける「ディストリビューション」がどういったもので、どう配布されているものであるのかを知りません。そこで今回は、適当なディストリビューションを自作する過程を通して、いろいろと勉強していこうと思います。
用語説明
まず、今日において、WSLとは一般的にWSL 2のことを指します。この記事でもWSL 2のことをWSLと呼称します。
WSLは、Windows Subsystem for Linuxの略であり、WindowsにLinuxディストリビューションをインストールする技術です。
WSLは仮想化技術(Hyper-V)を使用して、軽量ユーティリティ仮想マシン(VM)内でLinuxカーネルを実行します。このVMと関連したプロセスが、「VmmemWSL」です。
そして、各Linuxディストリビューションは、WSLで管理されるVM内で分離されたコンテナとして実行されます。コンテナとして実行されたそれぞれは一般的にインスタンスと呼ばれるようです。各インスタンスは、ネットワーク名前空間、デバイスツリー、CPU/カーネル/メモリ/スワップ、/init
バイナリを共有しつつ、独自のPID名前空間、マウント名前空間、ユーザー名前空間、Cgroup名前空間、およびinitプロセスを持つとされています。
ここでは便宜上、以下のようにします。
- Linuxディストリビューション
- 実際にLinuxをホストOSとしてインストールする際に使われるもの
- Dockerイメージ
- Docker上にLinuxシステムを構築する際に使われるテンプレート
- Dockerコンテナ
- Docker上に構築されたLinuxシステム
- WSLディストリビューション
- WSL上にLinuxシステムを構築する際に使われるテンプレート
- WSLインスタンス
- WSL VM上に構築されたLinuxシステム
- WSL VM
- WSLインスタンスをつかさどる存在
- WSLインスタンスの自動シャットダウンなどを行う
tarやvhdxからWSLインスタンスを作成する
ありがたいことにMicrosoftは公式ドキュメントにて、DockerイメージからWSLインスタンスを作成する方法を順を追って説明してくれています。例として挙げられているのはCentOSですが、簡単に異なるDockerイメージに応用できます。
「TL;DR」として記事の冒頭に書いたのが、BusyBoxなWSLインスタンスを作成するスクリプトです。主な手順としては、以下のようになっています。
- DockerイメージからDockerコンテナを作成
- Dockerコンテナのファイルシステムをtar形式でエクスポート
- tarファイルをWSLディストリビューションとしてインポート
- WSLインスタンスが作られる
まずはWSL固有の事情について説明します。
wsl.exe
では、--import
オプションを使って、ファイルからディストリビューションをインストールする(WSLインスタンスを作成する)方法を提供しています。対応しているファイル形式はtarもしくはvhdxです。(ファイル名に制限はありません。)
wsl.exe --import $DistroName C:/path/to/install-location C:/path/to/rootfs.tar
vhdxというのは、仮想ハードディスク(Virtual Hard Disks)のためのフォーマットで、Hyper-V仮想マシンで使われているものです(公式ドキュメント)。WSLはHyper-Vの上に成り立っているもので、インストールしたLinuxが使うファイルシステムもvhdx形式でWindowsのファイルシステム上に保存されています。
私の環境では、Ubuntuのファイルシステムを保存したvhdxは、~\AppData\Local\wsl\{0ae58ad6-369c-424e-8f74-3f17610e65f0}\ext4.vhdx
に保存されているようでした。また、以下のキーでレジストリを検索することで、WSLインスタンスについてのメタデータを確認することができます。
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss
wsl.exe --import
を実行したときには、このレジストリに新たにキーが登録されると同時に、C:/path/to/rootfs.tar
を元にC:/path/to/install-location/ext4.vhdx
が作成される形です。
ちなみに、wsl.exe --install
を--from-file
オプション付きで実行することでも、インストールは可能なようです。この場合、インストール先ディレクトリは自動的に決定されるようです。
wsl.exe --install --name $DISTRIBUTION_NAME --from-file C:/path/to/rootfs.tar
(wsl.exe
には--export
オプションもあり、WSL環境のバックアップを取りたいなどの一般的なユースケースではこちらが便利でしょう。)
Dockerイメージからtarを作成する
さて、tarさえ用意できれば、WSLインスタンス構築に使えるWSLディストリビューションを作ることができることがわかりましたが、ではそのtarはどのような形式をしているのでしょうか? これは、ファイルシステムをそのままアーカイブとしてまとめたものなようでした。
そのようなtarアーカイブとしては、Alpine Linuxが提供するMini root filesystemや、Dockerでコンテナをエクスポートする際に作成するアーカイブが例として挙げられます。
$ docker container export --help
Usage: docker container export [OPTIONS] CONTAINER
Export a container's filesystem as a tar archive
Aliases:
docker container export, docker export
Options:
-o, --output string Write to a file, instead of STDOUT
しかしDockerコンテナをエクスポートしたものが常に問題なくWSLにインポートでき使用できるとは限らないようです。例えばbusybox:latest
を元に作成したものでは、/etc/fstab
が存在しないことから、wsl.exe
からの起動時にエラーが出力されてしまいました。(起動自体はしました。)
wsl: Processing /etc/fstab with mount -a failed.
あらかじめtarファイルに空の/etc/fstab
を追加しておくことで対処可能なようでした。
mkdir ./etc/
touch ./etc/fstab
tar --append ./etc/fstab --file rootfs.tar
また、archlinux:latest
を元に作成したものでは、/etc/machine-id
が存在しないことから、bashが次のようなエラーを出力してしまいました。
-bash: /etc/machine-id: No such file or directory
そのパスに空ファイルを作成することでエラー自体はなくなりますが……対処としてこれで十分であるとは思えません。どうすればいいのでしょうねぇ……。
アプリケーションが動くWSLを作ることはできるのか?
Dockerコンテナのように1つのアプリケーションを動かし続けるようなWSLインスタンスを作ることも不可能ではありません。例えばnginxイメージから作ったnginxディストリビューションについて、以下のようにするとhttp://localhost:80/
でnginxが立ち上がります。
wsl.exe -d nginx --exec /usr/sbin/nginx
そしてwsl.exe
を--exec
オプションなしで実行した際に呼び出されるものは、/etc/passwd
から変更可能なため、以下のように変更することで、wsl.exe -d nginx
だけでnginxが立ち上がるようになります。
-root:x:0:0:root:/root:/bin/bash
+root:x:0:0:root:/root:/usr/sbin/nginx
しかしどちらの場合も、15秒が経過すると接続できなくなってしまいました。これは、一定時間アイドル状態が続いた場合に、リソースの節約のため、WSLインスタンスがVMによって自動でシャットダウンされる挙動によるものです。WSLのインスタンスはサーバとして動かし続けるものとしては設計されていないのです。
おわりに
WSL用のディストリビューションの自作を通して、WSLについて少し詳しくなれたのでよかったです。あとでUbuntuからArch Linuxへデータの移行などをしようと思います。