scratch イメージから作る WSL ディストリビューション
こんにちは、Fairy Devices の熊谷です。
Windows Subsystem for Linux (WSL) 内の Linux ディストリビューションは、 Microsoft Store を介さずとも、ルートファイルシステムを tar アーカイブ形式でインポートすることで利用できることをご存知でしょうか?
この方法を使うことで、必要最小限のリソースで動作する、軽量でセキュアな WSL 環境を手に入れることもできます。例えば、自社向けにセキュリティ保護された環境[1] を配布することで、一貫したセキュリティレベルでの管理が実現できたりします。
この記事では、以下の Microsoft のドキュメントを参考に、Docker の scratch イメージから WSL 用のカスタムディストリビューションを構築する手順を解説します。
scratch とは?
全ての Dockerfile は Ubuntu や Alpine のようなベースイメージから作成されます。
これらのディストリビューションにはシェルやパッケージマネージャー、各種ライブラリなどが含まれており、ユーザーが使いやすいように必要なものをまとめて提供しています。
一方で scratch は明示的に何も含まれておらず、超最低限のイメージを作るのに適しています。
アプリケーションの実行に必要なコンポーネントに限定することで、軽量かつセキュアなイメージを作成するのに向いています。
scratch をベースに作成したイメージは、Docker コンテナとしてだけでなく、WSL でも動かすことができます。
この記事のゴール
この記事では、cowsay ライクなコマンドである Ferris Says を実行するカスタムディストリビューションの作成を目指します。
Docker の scratch イメージから WSL カスタムディストリビューションを作成する流れは以下の通りです。
- Docker イメージの作成: Dockerfile を使って、scratch イメージをベースに必要最小限のファイル(Ferris Says の実行ファイル、共有ライブラリ、WSL 設定ファイル)を追加します。
- rootfs をエクスポート: 構築した Docker イメージから rootfs を tar アーカイブ形式でエクスポートします。
- WSL へインストール: エクスポートした tar アーカイブを WSL にインストールし、新しいカスタムディストリビューションとして登録します。
1. Docker イメージの作成
マルチステージビルドを利用して必要なファイルを集めて、実行環境へコピーします。
Ferris Says は cargo install でインストールします。
インストールされた fsays コマンドの依存ライブラリを ldd コマンドで調べ、これらも実行環境へコピーします。
$ ldd /usr/local/cargo/bin/fsays
linux-vdso.so.1 (0x00007ffddf355000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007bf53a200000)
/lib64/ld-linux-x86-64.so.2 (0x00007bf53a8cc000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007bf53a5d2000)
次に、WSL 構成ファイルを用意します。前述したドキュメントによると以下の 2 ファイル要るようです。
/etc/wsl-distribution.conf: WSL を使用して初めて起動したときに Linux ディストリビューションを構成する方法を制御するディストリビューション 保守管理者によって作成されたファイル。/etc/wsl.conf: ユーザーに固有のグローバル システム設定を含み、ディストリビューションの起動方法を制御するファイル。
WSL 配布構成ファイル
ここでは、ディストリビューション名を設定するのが主な目的です。
シェルすらない環境のため、Windows Terminal のプロファイルに追加されないように不要な設定は無効にします。
[oobe]
defaultName = ferris-says
[shortcut]
enabled = false
[windowsterminal]
enabled = false
WSL 構成ファイル
wsl.conf ファイルは、ディストリビューションごとに設定を構成します。
これらの設定はデフォルトでは true ですが、この記事では不要なため false に変更します。
[boot]
systemd = false
[automount]
enabled = false
mountFsTab = false
[network]
generateHosts = false
generateResolvConf = false
[interop]
enabled = false
appendWindowsPath = false
Dockerfile
一連の処理をまとめた Dockerfile が以下です。
################################################################################
## Ferris Says ビルド用
FROM rust:latest AS builder
## Ferris Says のバイナリをインストール -> /usr/local/cargo/bin/fsays
RUN cargo install fsays
################################################################################
## 依存パッケージダウンロード用
FROM ubuntu:24.04 AS base
## 依存ライブラリのパッケージを明示的にインストール
RUN apt-get update && apt-get install -y --no-install-recommends \
libc6 \
libgcc-s1 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
## プロセス生成時に使用される passwd を作成
RUN echo "root:x:0:0::/:" > /tmp/passwd
################################################################################
## 実行環境
FROM scratch
## fsays
COPY --from=builder /usr/local/cargo/bin/fsays /usr/bin/fsays
## 依存ライブラリ(ld, libc, libgcc_s)
COPY --from=base /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
COPY --from=base /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
COPY --from=base /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libc.so.6
COPY --from=base /lib/x86_64-linux-gnu/libgcc_s.so.1 /lib/x86_64-linux-gnu/libgcc_s.so.1
## WSL settings
COPY ./wsl.conf /etc/wsl.conf
COPY ./wsl-distribution.conf /etc/wsl-distribution.conf
COPY --from=base /tmp/passwd /etc/passwd
これらのファイル(Dockerfile, wsl.conf, wsl-distribution.conf)を用意し、以下のコマンドで Docker イメージをビルドします。
$ docker image build -t ferris-says .
$ docker image ls ferris-says
REPOSITORY TAG IMAGE ID CREATED SIZE
ferris-says latest cc80e003fe40 2 days ago 6.26MB
2. rootfs をエクスポート
ビルドした Docker イメージから、WSL で利用できる tar アーカイブ形式の rootfs をエクスポートします。
$ docker container create -t --name wsl_export ferris-says fsays
$ docker container export wsl_export | gzip > ferris-says.wsl
$ docker container rm wsl_export
これで ferris-says.wsl というファイルが作成されます。
……おや? 拡張子が .wsl になっていますね。
これは、実体は .tar.gz ですが、名前だけ変えています。
こうすることで、Windows がこのファイルを WSL ディストリビューションとして認識し、エクスプローラーからダブルクリックするだけでインストールしてくれるようになります。
3. WSL へインストール
最後に、作成した tar アーカイブを WSL にディストリビューションとしてインストールします。
前のセクションで説明したように、.wsl 拡張子のファイルをダブルクリックしてインストールすることも可能ですが、ここではコマンドによるインストール例を示します。
PowerShell またはコマンドプロンプトを開き、以下のコマンドを実行します。
> wsl.exe --install --from-file ferris-says.wsl --no-launch
これで、ferris-says という名前の新しいディストリビューションが登録されました!
wsl.exe --list でインストールされているディストリビューションの一覧を確認できます。
カスタムディストリビューションの起動
インストールが完了したら、以下のコマンドで新しいカスタムディストリビューションを起動してみましょう。
--distribution, -d オプションでディストリビューションを指定します。
--exec, -e オプションは、既定のシェルを使用せずに指定されたコマンドを直接実行します。
> wsl.exe -d ferris-says -e fsays "タラバガニはヤドカリの仲間"
____________________________
< タラバガニはヤドカリの仲間 >
----------------------------
\
\
_~^~^~_
\) / o o \ (/
'_ - _'
/ '-----' \
おわりに
本記事では、Docker の scratch イメージから WSL カスタムディストリビューションを構築する基本的な手順を解説しました。
この環境はとても最小限であり、シェルやパッケージマネージャーは含まれていません。
しかし、用途によっては、パッケージマネージャーを導入したり、特定の開発環境に特化したツールを追加したりして、さらにカスタマイズを進めるのも良いでしょう。
あなただけのカスタムディストリビューションを作ってみてはいかがでしょうか。
Discussion