ここ数週間 systemd について学んできたので、トピックごとにまとめておきます。
第一回目は、OS起動時に systemd で実行される default.target
を起点とした依存関係のツリーについてです。
なお、本記事の内容は Ubuntu 16.04, Debian Stretch で動作確認しています。
systemctl list-dependencies
まずはおもむろに sudo systemctl list-dependencies
を実行してみましょう!
default.target
を起点として、それから要求される形でどのようなユニットが起動されたかが見られます。緑は成功、赤は失敗、白はその他(依存関係が満たされず、起動されなかった、など)です。
他のことは忘れて良いので、今回、このコマンドだけでも覚えて帰ってください!
default.target とは?
default.target
とは、OS の起動シーケンスの起点となるユニットで、systemd は default.target
に記述されている依存関係を満たすように、各種ユニットを立ちあげます。
defualt.target
の実体はシンボリックリンクで、具体的な処理の中身はリンク先のターゲットによって定められています。
default.target に紐づくターゲットとは?
一般には、GUI のシステムでは graphical.target
に、GUI 無しのシステムでは multi-user.target
に紐付いています。
default.target
に何が紐付いているかは systemctl get-default
で確認できます。
$ systemctl get-default
graphical.target
また、 systemctl set-default
によって default.target
に紐づくターゲットを変更できます。
$ sudo systemctl set-default multi-user.target
Removed symlink /etc/systemd/system/default.target.
Created symlink from /etc/systemd/system/default.target to /lib/systemd/system/multi-user.target.
graphical.target の中身は?
multi-user.target
+ display-manager.service
です。マルチユーザ環境の構築をしつつ、 display manager を立ちあげます。
詳しく知りたい人は graphical.target
の中身を読んでみてください。
$ cat /lib/systemd/system/graphical.target
multi-user.target は何をするのか?
multi-user.target
は複数ユーザ環境のベースとなるターゲットで、多くのサービスがこのターゲットに紐付いて起動されます。
multi-user.target
自身で指定されている依存関係は basic.target
への Requires だけですが、外部のユニットから指定された multi-user.target.wants
が重要です。
- /lib/systemd/system/multi-user.target.wants/
- /etc/systemd/system/multi-user.target.wants/
これらのディレクトリの下に multi-user.target
に依存するユニットのシンボリックリンクが置かれており、これらが集まって multi-user.target
を起点とした依存関係のグラフが形成され、OS 起動時に実行されるわけです。
どうやってユニットを multi-user.target に紐付けるのか?
systemd で管理された各種ユニットは、定義ファイルに
[Install]
WantedBy=multi-user.target
のように記述することで、multi-user.target
の起動時に一緒に起動するよう、要求することができます。
なお、この記述だけがあっても自動起動はしません。systemctl enable <unit>
コマンドで有効にして初めて、 multi-user.target.wants
にシンボリックリンクが生成され、 multi-user.target
の実行時にユニットがあわせて起動されるようになります。
また systemctl disable <unit>
をすれば、シンボリックリンクが削除されて、 multi-user.target
の依存関係のグラフからユニットが外されます。
ただし、enable にしていても、依存ツリーの中で自身が要求されなければ起動されないですし、disable であっても、何かしらのルートで要求があると起動します。このあたりの依存関係のルールの詳細は、別の記事で説明しようと思います。
「起動にかかった時間」とは?
「OSの起動にかかる時間」とは、「defualt.target
の依存関係ツリーを立ち上げるのにかかった時間」とほぼ同じ意味で、 systemd-analyze
コマンドで確認できます。
$ sudo systemd-analyze
Startup finished in 5.483s (firmware) + 4.044s (loader) + 1.658s (kernel) + 6.310s (userspace) = 17.496s
同様のログは、journalctl
にも記録されています。
$ sudo journalctl -b
...
Apr 11 14:07:24 somehost systemd[1]: Reached target Multi-User System.
Apr 11 14:07:24 somehost systemd[1]: Reached target Graphical Interface.
Apr 11 14:07:24 somehost systemd[1]: Starting Update UTMP about System Runlevel Changes...
Apr 11 14:07:24 somehost systemd[1]: Started Update UTMP about System Runlevel Changes.
Apr 11 14:07:24 somehost systemd[1]: Startup finished in 2.185s (kernel) + 9.827s (userspace) = 29.116s.
...
default.target にカスタムのターゲットを紐付けたい
この仕組みを利用すれば、カスタムのターゲットも簡単に作成できます。
graphical.target
を参考にするのが良いでしょう。
例えば、自社ロボット専用の起動シーケンスを作りたい場合、下記のようなターゲットを作り、
$ cat /lib/systemd/system/robot.target
[Unit]
Description=Robot Mode
Requires=multi-user.target
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target
AllowIsolate=yes
起動時に立ちあげたい systemd のユニットに
[Install]
WantedBy=robot.target
のような依存関係を定義し、
sudo systemctl set-default robot.target
を実行すれば、OS起動時に自動でユニットを立ちあげられるようになります。また、
sudo systemctl set-default multi-user.target
などとすれば、元の起動シーケンスに戻せます。
AllowIsolate とは何か?
AllowIsolate
や有効になっているユニットは、 systemctl isolate
コマンドで起動することができます。systemctl isolate
コマンドでターゲットを起動すると、 指定したターゲットが(明示的に)依存するユニット以外は全て停止してから、ターゲットが起動されます。set-default で指定するターゲットは、基本的には AllowIsolate
が指定されたターゲットです。
ただし、下記の Issue で議論されているように、 systemctl isolate
が実行された瞬間に、 明示的に 定義されている依存関係以外はいったんすべて終了してしまうので、モードの切替に systemctl isolate
コマンドは使いづらいです。例えば robot.target に切り替えたい場合、 set-default
してからシステムを再起動する方が確実です。
関連資料
全体の体系としては分かりづらいですが、個々の仕様を確認するには systemd のオンラインマニュアルが有用です。