Windows 10 or 11 (WSL2)のUbuntuでsystemctlを利用する方法(systemdをPID1で動作させる方法)

2020年8月9日Windows

 

2023-01-24 更新

WSL2にUbuntu22.04を導入しようと思い、またsystemctlコマンド使えるようにしないとなーと思っていたら、いつの間にか、systemdが正式に対応していました。

 

手順はシンプルです。

1.WSLで「/etc/wsl.conf」というファイルを作成する。

注意するポイント

Winodws側の「C:\Users\[ユーザ]\.wslconfig」とは別物なので注意。

2.以下の内容を記載し保存

[boot]
systemd=true

3.WSLを再起動

powershellで以下のコマンドを実行

PS C:\Users\xxx> wsl --shutdown

4.systemdがPID 1で起動していることを確認

$ ps -ae
    PID TTY          TIME CMD
      1 ?        00:00:00 systemd
      2 ?        00:00:00 init

Microsoftのブログ

https://devblogs.microsoft.com/commandline/systemd-support-is-now-available-in-wsl/

これで、構築の都度genieを導入する作業から開放されました。

なので、以下の作業は今後不要になりました!

WSL2にUbuntuをインストールし systemctl コマンドを実行すると以下のようなエラーが発生し実行することができません。

$ systemctl
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down

そのため、以下のようなことができずに起動後に service コマンドを実行するシェルなどを実行して我慢していました。

  • サービスの自動起動などを設定することができない
  • 内部的にsystemctlを利用しているシステムを実行できない(minikubeなど)

今回この問題を解決する方法を解説されているサイトを元に手順をまとめてみましたので、同じ現象で困っている方は試してみてください。

 

[2021/12/18]Update

Microsoftのページに記載されているdotnet-runtimeのインストール方法では6.0がインストールされてしまうため、genieでサポートされている5.0をインストールする手順に記事を修正しました。

[2021/8/7]Update

OSをWindows11をアップグレードするために、クリーンインストールすることになり、WSL2の環境を再構築すると、これまでに方法ではsystemdをPID1で動作させることができなくなっていたため、手順を更新しました。

大きくは変わっていませんが、dotnetのバージョンなど依存プログラムが変わっているのでそのあたりに気をついて設定すれば問題なく利用できました。

Windows11でも問題なしです。

systemctlでエラーが発生する原因

答えは先ほどの systemctl コマンドのエラーメッセージにもありますが、 systemd PID1 で動作していないためです。

エラーメッセージ

System has not been booted with systemd as init system (PID 1).

実際に ps aux コマンドでプロセスの状態を確認すると確かに PID1 init プロセスとなっていることがわかります。

$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0    892   552 ?        Sl   15:30   0:00 /init
root        49  0.0  0.0    892    80 ?        Ss   15:30   0:00 /init
root        50  0.0  0.0    892    80 ?        S    15:30   0:00 /init
snow        51  0.0  0.0  10040  4992 pts/0    Ss   15:30   0:00 -bash
snow       130  0.0  0.0  10604  3316 pts/0    R+   16:11   0:00 ps aux

原因がわかったので、対策としては systemd PID1 で動作させる方法がわかれば、なんとかなりそうです。

systemdプロセスをPID1で稼働させる方法

以下のGitHubで公開されている genie を利用することで systemd を PID1 で動作させることができます。

https://github.com/arkane-systems/genie

 

では、順番に設定していきましょう。

daemonizeなどの各種依存モジュールをインストール

genie のREADMEにも書かれていますが、debian系の場合は各種モジュールが必要となっています。

READMEの抜粋

Dependent packages on Debian are daemonizedbusdotnet-runtime-5.0gawklibc6libstdc++6policykit-1systemd, and systemd-container. For the most part, these are either already installed or in the distro and able to be installed automatically. You need debhelper and dotnet-sdk-5.0 (and optionally pbuilder) to build the Debian package, but not to simply build genie or install locally.

The chief exception is dotnet-runtime-5.0 , for which you will need to follow the installation instructions here:

記載されている依存モジュールを全部インストールする必要があります。

 

最初にdotnet-runtime-5.0をインストールし、その後に残りのモジュールをインストールしましょう。

 

dotnet-runtime-5.0をインストール

以下のmicrosoftのページを参考にインストール用のコマンドを作成します。

https://docs.microsoft.com/en-us/dotnet/core/install/linux-ubuntu#2004-

2021-12-18現在は、dotnet-runtime-6.0のインストール方法が掲載されていますので、少し変更してdotnet-runtime-5.0をインストールする手順に置き換えます。

ubuntuのバージョンが20.04の場合は以下のコマンドを実行すればOKです。

wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
sudo apt-get update; \
  sudo apt-get install -y apt-transport-https && \
  sudo apt-get update && \
  sudo apt-get install -y aspnetcore-runtime-5.0

残りの依存モジュールをインストールする

sudo apt install -y daemonize dbus gawk libc6 libstdc++6 policykit-1 systemd systemd-container

wsl-transdebianのリポジトリ設定

以下のページを参考に wsl-transdebianのリポジトリを設定します。

https://arkane-systems.github.io/wsl-transdebian/

sudo apt install apt-transport-https

sudo wget -O /etc/apt/trusted.gpg.d/wsl-transdebian.gpg https://arkane-systems.github.io/wsl-transdebian/apt/wsl-transdebian.gpg

sudo chmod a+r /etc/apt/trusted.gpg.d/wsl-transdebian.gpg

sudo cat << EOF > /etc/apt/sources.list.d/wsl-transdebian.list
deb https://arkane-systems.github.io/wsl-transdebian/apt/ $(lsb_release -cs) main
deb-src https://arkane-systems.github.io/wsl-transdebian/apt/ $(lsb_release -cs) main
EOF

sudo apt update

genieインストール

genie をインストールします。

sudo apt install -y systemd-genie

 

genieを実行しsystemdをPID1にする

genie がインストールできたら実行してみましょう。

genie -s

しかし、初期状態では240秒ほど待たされてしまいます。。。

genie起動時に長時間待機されるエラーを解消する

genieを起動すると240秒経過したあとに以下のような警告メッセージが表示されます。

Waiting for systemd....!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Timed out waiting for systemd to enter running state.
This may indicate a systemd configuration error.
Attempting to continue.
Failed units will now be displayed (systemctl list-units --failed):
  UNIT                       LOAD   ACTIVE SUB    DESCRIPTION
● systemd-remount-fs.service loaded failed failed Remount Root and Kernel File Systems
● multipathd.socket          loaded failed failed multipathd control socket

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

2 loaded units listed.

上記2つのエラーについて解消することで10秒程度で正常に起動することができるようになります。

systemd-remount-fs.serviceのエラーを解消する

genieのページに解決方法が記載されていますので、そちらを参考にします。

https://github.com/arkane-systems/genie/wiki/Systemd-units-known-to-be-problematic-under-WSL#systemd-remount-fsservice

This occurs because systemd-remount-fs is trying to remount the root partition to make sure that it has the options configured in /etc/fstab; and the Ubuntu default /etc/fstab assumes that the root partition is labeled “cloudimg-rootfs". This isn’t the case under WSL (the root partition is one of its .vhdx files), so the remount fails. (This isn’t strictly a problem with the service – you’d get the same error if you tried to remount / manually.)

There are two ways to solve this one: either find the device the root partition is mounted from (probably /dev/sdb, but check first), and label it appropriately:

「cloudimg-rootfs」というラベルが必要になるので、ルートパーティションがマウントされているデバイスにラベルを付けましょう。

とう言うことですので、dfコマンドなどでルートパーティションのデバイス名を確認します。

$ df
Filesystem     1K-blocks      Used Available Use% Mounted on
/dev/sdb       263174212   6028448 243707608   3% /
tools          498867196 178713864 320153332  36% /init
none             8043924         0   8043924   0% /dev
tmpfs            8046008         0   8046008   0% /sys/fs/cgroup
none             8046008       908   8045100   1% /run
none             8046008         0   8046008   0% /run/lock
none             8046008         0   8046008   0% /run/shm
none             8046008         0   8046008   0% /run/user
drivers        498867196 178713864 320153332  36% /usr/lib/wsl/drivers
lib            498867196 178713864 320153332  36% /usr/lib/wsl/lib
none             8046008         4   8046004   1% /mnt/wsl
none             8046008        64   8045944   1% /mnt/wslg
none             8046008        76   8045932   1% /mnt/wslg/versions.txt
none             8046008        76   8045932   1% /mnt/wslg/doc
drvfs          498867196 178713864 320153332  36% /mnt/c
drvfs           15728640    339788  15388852   3% /mnt/g
drvfs           15728640    400880  15327760   3% /mnt/h

私の環境ではルートパーティションは「/dev/sdb」でしたので、以下のコマンドを実行しラベルを付与します。

sudo e2label /dev/sdb cloudimg-rootfs

multipathd.socketのエラーを解消する

先程と同じく genieのページに解決方法が記載されていますので、そちらを参考にします。

https://github.com/arkane-systems/genie/wiki/Systemd-units-known-to-be-problematic-under-WSL#multipathdservice

The default WSL kernel does not include the multipath support. If you have a use case for multipath under WSL, compile and use a custom kernel which includes it. Otherwise, disable/mask this unit.

WSLではmultipathはサーポートされていないので、無効化する必要があるようです。

 

以下のコマンドを実行しmultipathを無効化しましょう。

sudo systemctl disable multipathd.socket

genieを起動時に実行するようにする

.bashrc ファイルに以下のページを参考に追記しましょう。

https://github.com/arkane-systems/genie/wiki/Automatically-start-genie-on-every-shell-session

# Are we in the bottle?
if [[ ! -v INSIDE_GENIE ]]; then
  echo "Starting genie:"
  exec /usr/bin/genie -s
fi

これで、次回実行時に systemd がPID1でない場合 genie -s が実行されます。

 

systemdがPID1で稼働しているか確認する

$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.2  0.2 173092 13104 ?        Ss   18:43   0:00 /bin/systemd
root          44  0.1  0.2  53484 15464 ?        S<s  18:43   0:00 /lib/systemd/systemd-journald
root          65  0.0  0.0  18284  4944 ?        Ss   18:43   0:00 /lib/systemd/systemd-udevd
systemd+      70  0.0  0.1  18680  7860 ?        Ss   18:43   0:00 /lib/systemd/systemd-networkd

無事 systemd がPID1で動作しています。

 

systemctlが実行できるか確認する

sshd のステータスを systemctl で確認すると無事結果が表示されました

$ systemctl status sshd
● ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Sun 2020-08-09 18:43:17 JST; 7min ago
       Docs: man:sshd(8)
             man:sshd_config(5)

Windows

Posted by snow