【WSL2】systemctlが動かない問題をきちんと解決する

2020年6月22日Windows,環境構築

2022/11/20追記

WSL自体がsystemdをサポートしたことで、外部ツールを使わずにWSLだけで設定が可能になりました。
こちらをご確認ください。
【WSL2】systemdがサポートされたようなので試してみた

2021/07/19追記

またまた手順が変わっていたので、改めて記事をまとめなおしました。
こちらの記事をご覧下さい。
【WSL2】Ubuntu 20.04でPID1をsystemdにする 2021年7月版

2020/08/19追記

Win環境を構築しなおして、こちらの手順をやったところうまくいきませんでした。
まとめ直した記事を公開していますので、よろしければこちらもよろしくお願いします。
【WSL2】Ubuntu20.04でPID1をSystemdにする

本文

こんにちは、しきゆらです。
今回は、前回なんとか動くようになったsystemctlについて調べなおしつつ、きちんと動くようになったので改めてメモしておきます。

前回、【WSL】WSL2でMySQL8.0が動かないのを解決するにて、mysqlを動かすために systemctlをごにょごにょして動くようにしました。
ひとまず動くようにはなったんですが、自動起動させてもきちんと動いてくれず困っていました。
今回は、そもそもなぜsystemctlさんが動かないのかを調べつつ、解決方法が見つかったのでメモしておきます。


そもそも、なぜsystemctlが動かないのか

Linuxさんは、本当にうわべしか知らなかったので、調べてみました。

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

エラーの内容としては、systemdがPID 1(init system)ではないので操作できないよ、という感じですかね。

調べてみると、Linuxが起動するときすべてのプロセスの最初として「systemd」が起動し、すべてのプロセスの親としてふるまうようです。
参考:https://dev.classmethod.jp/articles/systemd-getting-started/#toc-2

実際にWSL2上でプロセスを確認してみると、PID 1が「/init」となっていて「systemd」ではありません。
これが原因でsystemctlが動いていないようです。
エラーメッセージから考えても、PID 1がsystemdになればよい、ということです。

systemdをPID 1にする

https://www.tomoyan.net/windows/wsl
こちらのサイトにて、同様の問題についての解決方法をまとめてくれています。
こちらを参考に、手順をまとめておきます。

使うものは、こちらのリポジトリ。
https://github.com/arkane-systems/genie
WSL2限定ですが、問題を解決してくれます。

それでは、導入のために必要なものをインストールします。
gitはもちろん、READMEにあるものも使うので、インストールしておきます。

sudo apt install git dotnet-runtime-3.1 daemonize

Ubuntu(Debian?)の場合はdaemonizeも必要なようなので、併せて入れておきます。

あとは、以下のコマンドでおしまいです。

git clone https://github.com/arkane-systems/genie.git
 
cd genie
make install

あとは、以下のコマンドを実行して完了です。

genie -s

これで、PID 1がsystemdがPID 1になります。
確認してみましょう。

PID 1がsystemdになりましたね。
これにて当初のエラーにあった問題である、PID 1がsystemdじゃない、というものは解決できたことになります。

それでは、先ほどインストールした「genie」のREADMEにあるように「getty@tty1をsystemctlを使って止めてみます。

 sudo systemctl stop getty@tty1
 sudo systemctl disable getty@tty1
 
 sudo systemctl status getty@tty1
 ● getty@tty1.service - Getty on tty1
      Loaded: loaded (/lib/systemd/system/getty@.service; disabled; vendor preset: enabled)
      Active: inactive (dead)
        Docs: man:agetty(8)
              man:systemd-getty-generator(8)
              http://0pointer.de/blog/projects/serial-console.html

エラーも出ずに、きちんと止めることができました。
大丈夫そうですね。

これにて、systemctlがきちんと動くようになりました。
それでは、必要なサービスを実行してきます。
今回はMySQLですね。
MySQLを動かすために必要なほかのサービスも一緒に自動起動の設定をしておきます。

# systemd-tmpfilesの自動起動 & 起動
sudo systemctl enable systemd-tmpfiles-setup.service
sudo systemctl start systemd-tmpfiles-setup.service

# MySQLの自動起動 & 起動
sudo systemctl enable mysql
sudo systemctl start mysql

「systemd-tmpfiles-setup」というサービスは、起動時に必要なディレクトリやファイルを作成してくれるものです。
前回の記事でも書きましたが、「/var/run/mysql」というディレクトリに諸々ファイルを置いて起動するので必要になります。
(調べてみると、mysqlをインストールしたときに、上記サービスで必要なディレクトリを作ってもらうように設定ファイルも置いてくれていました)

PID 1をsystemdにするコマンドを起動時に実行する

ここまでで、ひとまずsystemdが使えるようになりました。
しかし、WSLを立ち上げるたびにgenie -sを実行するのは手間なので省いてしまいます。
.zshrcに以下のように追記します。

 if [ "`ps -eo pid,lstart,cmd | grep systemd | grep -v -e grep -e systemd- | sort -n -k2 | awk 'NR==1 { print $1 }'`" != "1" ]; then
   genie -s
 fi

PID 1がsystemdでない場合に、「genie -s」を実行します。
これで、WSLを立ち上げたときにはすでにsystemctlが使える状態になります。

まとめ

今回は、前回に引き続きWSL2環境にてsystemctlが動かない問題に対応しました。
世界は広いもので、同じ問題に困っている人がいて、なおかつすでに解決策があることが多いです。
OSSの世界は素晴らしいですね。

念のため再度記載しておきますが、今回の解決方法はWSL2限定です。
ご注意ください。

では、今回はここまで。
おわり

Posted by しきゆら