Windows Subsystem for Linux
しかし、WSLを使えるようになったことで、Windowsマシンでも手軽にUbuntuを利用できるようになりました。開発環境や作業環境としてUbuntuをWSL上で使っているという方も多数いることでしょう。
さらに、WSLを使えば、Ubuntu環境を作ったり、壊したりも手軽にできます。
PS> wsl --install ubuntu-24.04 # 作ったり PS> wsl --unregister ubuntu-24.04 # 壊したり
でも、作ったり、壊したりまでは簡単でも、そのあとの環境の再構築・
そうだ、cloud-initを使おう
Ubuntu 24.
ユーザーデータの配置場所と優先順位
WSLで稼働するUbuntuのcloud-initは初回起動時にユーザーデータを次の順番で探し、合致するユーザーデータが見つかった時点で検索は終了、見つけたそのユーザーデータを読み込み・
%USERPROFILE%\.cloud-init\<インスタンス名>.user-data
%USERPROFILE%\.cloud-init\<ID>-<VERSION_
ID>.user-data %USERPROFILE%\.cloud-init\<ID>-all.
user-data %USERPROFILE%\.cloud-init\default.
user-data
ちなみに、デフォルトでは大文字・
これらのパスについて解説します。
まず、4つ全部に共通する%USERPROFILE%
という部分ですが、これはWindowsの環境変数で、現在のWindowsユーザーフォルダーC:\Users\<ユーザー名>\
など)
続いて個別のパスの解説へと移るのですが、その前に1にあるwsl
コマンド側でUbuntu-24.
とあるものがインスタンスでありその名前です。
PS> wsl -l Linux 用 Windows サブシステム ディストリビューション: Ubuntu-24.04 (既定値)
ただ、WSL側がいうところのwsl
コマンド側で
これを踏またうえで1から解説しますと、1は特定の
続いて2ですが、2に含まれる<ID>
と<VERSION_
には、それぞれ、WSLインスタンス内部の/etc/
に記載されるID
とVERSION_
を代入したパスになります。例えば、Ubuntu 24./etc/
に記載されたID
はubuntu
でVERSION_
は24.
であるため、対応するパスは%USERPROFILE%\.cloud-init\ubuntu-24.
となります。
$ grep -e ID= -e VERSION_ID= /etc/os-release VERSION_ID="24.04" ID=ubuntu
先ほどの
3は2と考え方は同じですが、2と違って<VERSION_
の部分がall
となっています。これはディストリビューション名/etc/
のID
)
4は1~3のどれにも該当しなかった場合に読み込まれるユーザーデータです。4はディストリビューションに依存しない処理[3]をおこなう場合に便利でしょう。
このように優先順位が高いパスほど適用範囲が狭まります。
ユーザーデータを作成する
早速ですが、ユーザーデータを作成します。より広範なユーザーデータのサンプルはcloud-initのドキュメントを見るなどしていただくとして、今回は次のサンプルを使います。
#cloud-config
locale: ja_JP.UTF-8
users:
- name: wsl-user
groups: users,sudo,netdev,audio,adm
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
lock_passwd: true
write_files:
- path: /etc/wsl.conf
append: true
content: |
[user]
default=wsl-user
packages:
- unzip
この時点で他にユーザーデータは作成していないため、Ubuntuを使用するすべてのWSLインスタンスでこのユーザーデータが実行されます。
簡単ですが部分ごとに内容を解説しておきましょう。
locale: ja_JP.UTF-8
locale
ではロケールを日本語ja_
)C.
)
users:
- name: wsl-user
groups: users,sudo,netdev,audio,adm
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
lock_passwd: true
このusers
ではwsl-user
という名前のユーザーを作成して、グループへの追加やシェルの設定、sudoの設定[4]をします。
write_files:
- path: /etc/wsl.conf
append: true
content: |
[user]
default=wsl-user
ここでは/etc/
に追記をおこない、WSLインスタンスを起動したときに、上で作成するよう指定したwsl-user
としてログインするよう設定しています[5]。
packages:
- unzip
最後にpackages
に書かれたパッケージをインストールするよう指定しています。
WSLインスタンスを作成する
ユーザーデータが準備できたのでこのファイルを3の%USERPROFILE%\.cloud-init\ubuntu-all.
として保存しておきます。先程見たように、このパスはすべてのUbuntuのWSLインスタンスが対象となりうるパスで読み込み順位は3位です。ユーザーデータが準備できたので実際にWSLインスタンスを作成してみましょう。先ほど見たように、ユーザーデータの置き場所=ユーザーデータの適用パターンは複数あるので、それぞれ解説します。
すべてのUbuntuのWSLインスタンスに適用
まずは、作成したユーザーデータのファイルを3の%USERPROFILE%\.cloud-init\ubuntu-all.
として保存しておきます。このパスはすべてのUbuntuのWSLインスタンスが対象となりうるパスで読み込み順位は3位です。
それでは、WSLインスタンスを作成します。次のコマンドを実行します。
PS> wsl --install -d Ubuntu-24.04 --name Test01
今回はUbuntu 24.Test01
というインスタンス名で作成します。なお、--name
オプションが使えない場合はお使いのWSLのバージョンが古い可能性があるため、wsl --update
を実行して更新してください。
ダウンロード・wsl-user
としてログインした状態となっているはずです。また、パスワードの入力なしで、sudoも使え、ロケールも日本語になっているはずです。
$ id uid=1000(wsl-user) gid=1000(wsl-user) groups=1000(wsl-user),4(adm),27(sudo),29(audio),100(users),107(netdev) $ sudo id uid=0(root) gid=0(root) groups=0(root) $ locale LANG=ja_JP.UTF-8 LANGUAGE= LC_CTYPE="ja_JP.UTF-8" LC_NUMERIC="ja_JP.UTF-8" LC_TIME="ja_JP.UTF-8" LC_COLLATE="ja_JP.UTF-8" LC_MONETARY="ja_JP.UTF-8" LC_MESSAGES="ja_JP.UTF-8" LC_PAPER="ja_JP.UTF-8" LC_NAME="ja_JP.UTF-8" LC_ADDRESS="ja_JP.UTF-8" LC_TELEPHONE="ja_JP.UTF-8" LC_MEASUREMENT="ja_JP.UTF-8" LC_IDENTIFICATION="ja_JP.UTF-8" LC_ALL=
現時点で、他にユーザーデータはなく、すべてのUbuntuリリースで実行されるユーザーデータのため、Ubuntu 22.--name
オプションは使えませんので、次のように起動します。
PS> wsl --install -d Ubuntu-22.04
特定のリリースのUbuntuインスタンスに適用
次にユーザーデータを2の%USERPROFILE%\.cloud-init\ubuntu-24.
に配置します。これはWSLインスタンスで使用されるディストリビューションとそのリリースが、Ubuntu 24.
もっとも、%USERPROFILE%\.cloud-init\ubuntu-all.
と同じ内容だとどちらが読み込まれたのかがわかりません。よって、次のような内容を末尾に追記します。
runcmd:
- echo "Hello, Ubuntu 24.04" > /output
このruncmd
でコマンドを実行して、ファイルに文字列を出力させ、実行状況がわかるようにしようというわけです。
同様にWSLインスタンスを作成します。
PS> wsl --install -d Ubuntu-24.04 --name Test02
すると期待した通りにUbuntu 24.
$ cat /output Hello, Ubuntu 24.04
違いを確認するために、Ubuntu 25.ubuntu-25.
)
PS> wsl --install --from-file Downloads\ubuntu-25.04-wsl-amd64.wsl --name Test03
そして結果を確認してみます。
$ cat /output cat: /output: No such file or directory
ファイルは存在しません。また、読み込まれているユーザーデータも、期待通り、ubuntu-all.
$ sudo cat /var/lib/cloud/instance/user-data.txt #cloud-config locale: ja_JP.UTF-8 users: - name: wsl-user groups: users,sudo,netdev,audio,adm sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash lock_passwd: true write_files: - path: /etc/wsl.conf append: true content: | [user] default=wsl-user packages: - unzip
特定の名前のインスタンスに適用
最後は、3の特定の名前を持つインスタンス専用の%USERPROFILE%\.cloud-init\<インスタンス名>.user-data
です。とはいえ、作業・
ユーザーデータでのコマンド実行方法には、2で見たcloud-config
形式のユーザーデータでruncmd
を使う方法と、ユーザーデータをシェルスクリプト形式で書く方法と大きく2種類あります。両者は一長一短であるため、二者択一で考えると、
cloud-config
形式はこれまでみてきたようにユーザーの設定などはやりやすいけど、複雑なシェルスクリプトは書きづらい- シェルスクリプト形式で書くと複雑なシェルスクリプトは書きやすいけど、それ以外も頑張ってシェルスクリプトに落とし込まないといけない
というジレンマがあります。
実際には二者択一ではなく、MIMEマルチパート形式を使うことで、これら両方の形式を併用できます。最後の3は、このMIMEマルチパート形式でユーザーデータを作成してみます。
MIMEマルチパート形式のユーザーデータはcloud-init
コマンドで作成できます。今回、cloud-config
形式のユーザーデータは%USERPROFILE%\.cloud-init\ubuntu-all.
がすでにありますのでこれを再利用することにして、追加でシェルスクリプト側を作成します。以下の内容でシェルスクリプトを作成し、%USERPROFILE%\.cloud-init\test04.
として配置しておきます[7]。
#!/bin/bash
echo 'Hello, instance "Test04"' > /output
すでに作成したWSLインスタンス%USERPROFILE%\.cloud-init\
に相当するパスへ移動、次のコマンドを実行して、MIMEマルチパート形式のユーザーデータを作成します。
$ cd /mnt/c/Users/${your-windows-user-name}/.cloud-init $ cloud-init devel make-mime -a ubuntu-all.user-data:cloud-config -a test04.sh:x-shellscript > test04.user-data
test04.
は次のような内容になっているはずです。
Content-Type: multipart/mixed; boundary="===============3009917472491891126=="
MIME-Version: 1.0
--===============3009917472491891126==
Content-Type: text/cloud-config; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="ubuntu-all.user-data"
I2Nsb3VkLWNvbmZpZwpsb2NhbGU6IGphX0pQLlVURi04CnVzZXJzOgotIG5hbWU6IHdzbC11c2Vy
CiAgZ3JvdXBzOiB1c2VycyxzdWRvLG5ldGRldixhdWRpbyxhZG0KICBzdWRvOiBBTEw9KEFMTCkg
Tk9QQVNTV0Q6QUxMCiAgc2hlbGw6IC9iaW4vYmFzaAogIGxvY2tfcGFzc3dkOiB0cnVlCgp3cml0
ZV9maWxlczoKLSBwYXRoOiAvZXRjL3dzbC5jb25mCiAgYXBwZW5kOiB0cnVlCiAgY29udGVudDog
fAogICAgW3VzZXJdCiAgICBkZWZhdWx0PXdzbC11c2VyCgpwYWNrYWdlczoKLSB1bnppcA==
--===============3009917472491891126==
Content-Type: text/x-shellscript; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="test04.sh"
IyEvYmluL2Jhc2gKCmVjaG8gJ0hlbGxvLCBpbnN0YW5jZSAiVGVzdDA0IicgPiAvb3V0cHV0
--===============3009917472491891126==--
前半部分がubuntu-all.
を、後半部分がtest04.
をそれぞれ、base64でエンコードされたものになっています[8]。
そして、"Test04"という名前でインスタンスを作成し、結果を確認すると、cloud-config
形式およびシェルスクリプト形式の両方のユーザーデータの内容が実行されていることがわかります。
PS> wsl --install --from-file Downloads\ubuntu-25.04-wsl-amd64.wsl --name Test04 ... $ id uid=1000(wsl-user) gid=1000(wsl-user) groups=1000(wsl-user),4(adm),27(sudo),29(audio),100(users),105(netdev) $ cat /output Hello, instance "Test04" $ sudo cat /var/lib/cloud/instance/user-data.txt Content-Type: multipart/mixed; boundary="===============3009917472491891126==" MIME-Version: 1.0 --===============3009917472491891126== Content-Type: text/cloud-config; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="ubuntu-all.user-data" I2Nsb3VkLWNvbmZpZwpsb2NhbGU6IGphX0pQLlVURi04CnVzZXJzOgotIG5hbWU6IHdzbC11c2Vy CiAgZ3JvdXBzOiB1c2VycyxzdWRvLG5ldGRldixhdWRpbyxhZG0KICBzdWRvOiBBTEw9KEFMTCkg Tk9QQVNTV0Q6QUxMCiAgc2hlbGw6IC9iaW4vYmFzaAogIGxvY2tfcGFzc3dkOiB0cnVlCgp3cml0 ZV9maWxlczoKLSBwYXRoOiAvZXRjL3dzbC5jb25mCiAgYXBwZW5kOiB0cnVlCiAgY29udGVudDog fAogICAgW3VzZXJdCiAgICBkZWZhdWx0PXdzbC11c2VyCgpwYWNrYWdlczoKLSB1bnppcA== --===============3009917472491891126== Content-Type: text/x-shellscript; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="test04.sh" IyEvYmluL2Jhc2gKCmVjaG8gJ0hlbGxvLCBpbnN0YW5jZSAiVGVzdDA0IicgPiAvb3V0cHV0 --===============3009917472491891126==--
お片付け
最後に片付けをします。不要なWSLインスタンスごとに次の様なコマンドを実行して、インスタンスを削除しておきましょう。
PS> wsl --unregister test01
また、今後、意図しない動作を防ぐために不要なユーザーデータがあればクリーンアップしておくとよいでしょう。
このように、WSL環境でもcloud-initを使うことで、自分向けにカスタマイズされた環境を安定的に再構成できます。手軽に作ったり壊したりがやりやすくなりますね。