WSL2+Ubuntu22.04に標準で入ったsystemdを試す

2022.09.30追記)
WSL2でのsystemd対応はubuntuのローカル対応ではなく、WSL自体で行われることになったようです。ストア版WSL preview 0.67.6以降 systemd対応が入っています。また、この対応は流動的で 0.68.2では一般的なディストロと同様に /sbin/init (Ubuntuの場合、これはシンボリックリンクで実体はsystemd)を起動するようになりました。まだ議論が重ねられているようなのでしばらく試行錯誤が続くと思います。

それではWSL0.67.6以降でのsystemdの利用方法ですが、/etc/wsl.confに以下の設定を行います。

```/etc/wsl.conf
[boot]
systemd = true
```
これでMicrosoft initではなくsystemdが起動するようになります。Microsoftの/initはPID2で起動し、ログインプロセス？(WSL.exeから起動するコンソールアクセス)については /init の子孫として起動します。nslogin等も不要です。

------------
先日リリースされたUbuntu 22.04には`/usr/libexec/wsl-systemd`というシェルスクリプトが同梱されています。中身を覗くとunshareで名前空間を分けてsystemdを起動するようです。過去様々なところで紹介されていた手法のようですね。

## systemdを起動する

早速試してみましょう。

```shell:wsl-systemdを実行する
$ sudo /usr/libexec/wsl-systemd
$ ps ax
    PID TTY      STAT   TIME COMMAND
      1 ?        Sl     0:00 /init
      7 ?        Ss     0:00 /init
      8 ?        R      0:00 /init
      9 pts/0    Ss     0:00 -bash
     98 ?        S      0:00 /usr/bin/unshare --fork --mount-proc --pid --propagation unchanged -- sh -c  exec /lib/systemd/systemd --unit=multi-user.target
     99 ?        Ss     0:00 /lib/systemd/systemd --unit=multi-user.target
    139 ?        S<s    0:00 /lib/systemd/systemd-journald
    163 ?        Ss     0:00 /lib/systemd/systemd-udevd
    187 ?        Ss     0:00 @dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
    190 ?        Ss     0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers
    191 ?        Ssl    0:00 /usr/libexec/polkitd --no-debug
    192 ?        Ssl    0:00 /usr/sbin/rsyslogd -n -iNONE
    193 ?        Ss     0:00 /lib/systemd/systemd-logind
    194 ?        Ss     0:00 /lib/systemd/systemd-networkd
    217 ?        Ssl    0:00 /usr/sbin/ModemManager
    291 ?        Ss     0:00 /lib/systemd/systemd-resolved
    301 ?        Ss     0:00 /usr/sbin/cron -f -P
    305 ?        Ssl    0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
    309 tty1     Ss+    0:00 /sbin/agetty -o -p -- \u --noclear --keep-baud console 115200,38400,9600 linux
    311 ?        Ss     0:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
    314 ?        Ss     0:00 /sbin/agetty -o -p -- \u --noclear tty1 linux
```

起動しました。cronやsshd,systemd-resolvedなど様々起動しています。

## systemctlで操作する

sshdを止めてみましょう。

```shell:sshdを止めようとする
$ sudo systemctl stop ssh
Failed to stop ssh.service: 通信端点が接続されていません
See system logs and 'systemctl status ssh.service' for details.
```

エラーです。systemd がPID 1ではないのが原因でしょうか？

先ほどの /usr/libexec に nslogin というファイルがあります。こちらはスクリプトではなくバイナリのようです。マニュアルは見当たりませんが、きっと nslogin = name space login でしょう。

実行してみます。

```shell:nsloginを実行
$  /usr/libexec/nslogin
```

何も起こりません。
名前空間に入ったに違いないという淡い期待でプロセスを確認してみます。

```shell:プロセスを確認する
$ ps ax | grep system
      1 ?        Ss     0:00 /lib/systemd/systemd --unit=multi-user.target
```

systemdがPID 1になってます。

再度systemctlで操作してみます。
```
$ sudo systemctl stop ssh
```

エラーが出なくなりました。
停止できたかどうか確認してみます。

```shell:systemctl確認
$ /usr/libexec/nslogin sudo systemctl stop ssh
ThinkCentre:~$ /usr/libexec/nslogin sudo systemctl status ssh
○ ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
     Active: inactive (dead) since Wed 2022-04-27 04:49:56 JST; 4s ago
       Docs: man:sshd(8)
             man:sshd_config(5)
    Process: 204 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS)
    Process: 219 ExecStart=/usr/sbin/sshd -D $SSHD_OPTS (code=exited, status=0/SUCCESS)
   Main PID: 219 (code=exited, status=0/SUCCESS)

 4月 27 04:49:40 ThinkCentre systemd[1]: Starting OpenBSD Secure Shell server...
 4月 27 04:49:41 ThinkCentre sshd[219]: Server listening on 0.0.0.0 port 22.
 4月 27 04:49:41 ThinkCentre sshd[219]: Server listening on :: port 22.
 4月 27 04:49:41 ThinkCentre systemd[1]: Started OpenBSD Secure Shell server.
 4月 27 04:49:56 ThinkCentre sshd[219]: Received signal 15; terminating.
 4月 27 04:49:56 ThinkCentre systemd[1]: Stopping OpenBSD Secure Shell server...
 4月 27 04:49:56 ThinkCentre systemd[1]: ssh.service: Deactivated successfully.
 4月 27 04:49:56 ThinkCentre systemd[1]: Stopped OpenBSD Secure Shell server.
```

ちゃんと停止しています。
nslogin の引数にコマンドラインを並べても実行できるようです。

ちなみに、、wsl-systemdを実行していない(=systemdを起動していない)状態でnsloginを実行すると以下のようにdistroを一旦停止させてやり直しなさいとエラーが出ます。
```
$ /usr/libexec/nslogin ls
ERROR: Systemd is not running. Please terminate this instance by running "wsl -t <distro>" from Windows shell and try again.
```

以前、Ubuntuのブログに我々はWSLでsystemdを動かす方法を検討している。今も方法はいろいろあるけどそれは標準じゃないぞ的なことが書かれていましたが、ちゃんと実現したようですね。

2022.04.30追記)
https://github.com/microsoft/WSL/issues/5126#issuecomment-1111957720 によると、

launch your shells with "/usr/libexec/nslogin /bin/bash", eg from Windows:
```
wsl -e /usr/libexec/nslogin /bin/bash
```
ubuntu2204.exeだとこうなっているそうです。インストーラーを使ってインストールしていれば実は自動だったんですね。Terminalのコマンドラインをこちらに書き換えておくと、特に意識することなく常に systemd が PID 1 の環境で使えるようですね。

2022.05.04追記)
`wsl -e /usr/libexec/nslogin /bin/bash`でWSLに接続すると環境変数SHELLが`/usr/libexec/nslogin`になってしまうようです。ssh_configのMatchのように環境変数SHELLに対してコマンドを引き渡すような場合はエラーになってしまいます。.bashrcでSHELLを再定義するというのもありですが、今はsystemdがPID 1でないといけないケースだけnsloginを使うのが良いかもしれません。