【Linux】systemctl list-dependencies と systemd-analyze の見方、付き合い方

systemctl list-dependencies コマンドは systemd の Unit の "依存関係" や "順序関係" を表示するコマンドです。この記事ではこのコマンドの使い方を紹介します。

systemctl list-dependencies を使いこなすための基礎知識

systemd プロセスが PID=1 で起動すると、default.target という Unit ファイルの中身を確認します。default.target は SymbolicLink になっています。

例えば CentOS7.5 の Minimum インストール時のデフォルトでは /etc/systemd/system/default.target のリンク先は multi-user.target になっています

[root@localhost ~]# ls -l /etc/systemd/system/default.target
lrwxrwxrwx. 1 root root 37 12月 16 21:46 /etc/systemd/system/default.target -> /lib/systemd/system/multi-user.target

これは以下コマンドでも確認できます。

[root@localhost ~]# systemctl get-default
multi-user.target

ここで注意すべきなのは、この default.target (上の例ではmulti-user.target)が最初に起動するわけではないことです。あくまで『default.target は起動プロセス中のどこかで起動される』ことが決まっただけです。

Unit ファイルには依存関係や順序関係が書かれており、基本的に default.target から派生・連鎖する依存関係の Unit すべてを起動するようにリストアップし、その後に順序関係を見て起動順に並べ直します。

[root@localhost ~]# cat /usr/lib/systemd/system/multi-user.target

[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes

上記の例において、例えば Requires=basic.target は依存関係を示し、『multi-user.target Unitの実行に当たっては basic.target も起動する必要がある』ことを意味しており、例えば After=basic.target は順序関係を示し、『basic.target (実際にはbasic.targetに関連した処理)が完了した後に multi-user.target に関連した処理を開始する』ことを意味しています。

basic.target にはまた依存関係や順序関係が記されているため、どんどんツリー構成が深くなっていきます。

このツリー構成を表示するのが systemctl list-dependencies コマンドです。

依存関係と順序関係

"依存関係" と "順序関係" は別の概念です。まずは "依存関係" により『起動すべきUnit』が決まり、その後にそれらの Unit をどのような順番で実行していくかを "順序関係" により並べ直し、起動していきます。

『起動すべき Unit』に無い Unit が『順序関係』に出てくることもありますが、その Unit はそもそも起動すべきでないため、無視されます。

また、依存関係も順序関係も一方向のみを定義すればそれでOKです。片方のUnit で Before と書いたからと言って指定先 Unit で After= を書く必要はありません。

依存関係は『そのUnitを起動するか否か』を決めるものなので特に矛盾は発生しません。一方、順序関係は矛盾が起こりうるため注意が必要です。最悪の場合はOS起動しなくなってしまいます。

依存関係を深く知る

systemctl list-dependencies コマンドの見方

あるUnitファイルの依存関係を見るためには systemctl list-dependencies [Unitファイル] コマンドを使います。[Unitファイル]を省略すると自動で default.target が指定されます。

default.target は SymbolicLink なので前述の通り CentOS7.5 のMinimumインストール時の場合は以下コマンドはいずれも同じ結果になります。

  • systemctl list-dependencies
  • systemctl list-dependencies default.target
  • systemctl list-dependencies multi-user.target

以下に systemctl list-dependencies の実行結果(一部)を示します。

このツリーは『multi-user.target Unit を起動するにあたり、他に何のUnitを起動する必要があるか』を示しています。階層の深さは起動順序とは関係がありません。あくまでどのUnitの起動が必要とされているかを示しているに過ぎません。

緑丸は起動に成功したもの、赤丸は起動を試みたものの失敗に終わったものを示しています。

例えば auditd.service や chronyd.service, crond.service 等のUnitファイルを覗いてみると、[Install]ディレクティブに『WantedBy=multi-user.target』と記載されています

[root@localhost ~]# cat /usr/lib/systemd/system/auditd.service
[Unit]
Description=Security Auditing Service
DefaultDependencies=no
~~~
[Install]
WantedBy=multi-user.target

依存関係の指定の仕方は複数ありますが、これがまず1つ目の指定方法です。

次に、systemd-ask-password-wall.path のUnitファイルを覗いて見ましょう。

[root@localhost ~]# cat /usr/lib/systemd/system/systemd-ask-password-wall.path
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Forward Password Requests to Wall Directory Watch
Documentation=man:systemd-ask-password-console.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
Before=paths.target shutdown.target

[Path]
DirectoryNotEmpty=/run/systemd/ask-password
MakeDirectory=yes

依存関係が無いのになぜ multi-user.target との依存関係が示されているのでしょうか?このファイルが存在する場所を find で確認してみます。

[root@localhost ~]# find / -name systemd-ask-password-wall.path -print
/usr/lib/systemd/system/multi-user.target.wants/systemd-ask-password-wall.path
/usr/lib/systemd/system/systemd-ask-password-wall.path

multi-user.target.wants というディレクトリの下にこのUnitファイル名があります。このファイルは SymbolicLink で、リンク先は /usr/lib/systemd/system直下の同名ファイルになっています。

このように、*.wants というディレクトリの下に SymbolicLink を配置することで依存関係を示すこともできます。これが依存関係を示す方法の2つ目です。(実は WantedBy= に指定すると .wants ディレクトリに SymbolicLinkを作成する動作になるのでそういう意味では同じかもしれませんが、WantedBy に書く方法と書かない方法としてここでは区別しています。)

似たようなケースとして network.service を見てみます。/usr/lib/systemd/system にも /etc/systemd/system にもこの Unit ファイルが無いので同様に find で探してみます。

[root@localhost ~]# find / -name network.service -print
/run/systemd/generator.late/runlevel5.target.wants/network.service
/run/systemd/generator.late/runlevel4.target.wants/network.service
/run/systemd/generator.late/runlevel3.target.wants/network.service
/run/systemd/generator.late/runlevel2.target.wants/network.service
/run/systemd/generator.late/network.service
/sys/fs/cgroup/systemd/system.slice/network.service

/run/systemd/generator.late/runlevel3.target.wants/ というディレクトリの下にあります。これは実は generator という仕組みで動的に Unit ファイルが生成されているのです。

また、runlevel3.target というのは実は multi-user.target のAliasになっているため、この network.service も multi-user.target と依存関係があるのです。

なお補足ですが、init 系における RunLevel は、systemd においては target に置き換わっており、それぞれの RunLevel がどの target ファイルに置き換わっているか(Aliasになっているか)は以下のコマンドで確認できます。

[root@localhost ~]# ls -l /usr/lib/systemd/system/runlevel?.target
lrwxrwxrwx. 1 root root 15 12月 16 21:38 /usr/lib/systemd/system/runlevel0.target -> poweroff.target
lrwxrwxrwx. 1 root root 13 12月 16 21:38 /usr/lib/systemd/system/runlevel1.target -> rescue.target
lrwxrwxrwx. 1 root root 17 12月 16 21:38 /usr/lib/systemd/system/runlevel2.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 12月 16 21:38 /usr/lib/systemd/system/runlevel3.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 12月 16 21:38 /usr/lib/systemd/system/runlevel4.target -> multi-user.target
lrwxrwxrwx. 1 root root 16 12月 16 21:38 /usr/lib/systemd/system/runlevel5.target -> graphical.target
lrwxrwxrwx. 1 root root 13 12月 16 21:38 /usr/lib/systemd/system/runlevel6.target -> reboot.target

なお、実は systemctl list-depndencies だけでは multi-user.target の依存関係の一部しか表示されていません。具体的には、target に紐付く依存関係のみが表示されているのです。

しかし実際には .target 以外の Unit、例えば .service にも依存関係を示すことが可能です。例えば dbus.service には以下のような依存関係が書かれています。

[root@localhost ~]# cat /usr/lib/systemd/system/dbus.service
[Unit]
Description=D-Bus System Message Bus
Documentation=man:dbus-daemon(1)
Requires=dbus.socket
~~~

Requires として dbus.socket が存在していますが、list-dependencies には表示されていません。これはオプション無しの場合は .target に関してのみ再帰的に依存関係を表示するからです。全ての Unit で再帰的に依存関係を表示する場合は -a を使います

systemctl list-dependencies -a の実行結果(一部)を以下に示します。

このように全ての依存関係が示されました。ここに示された依存関係がこのように、Unitファイルの [Unit] ディレクティブに Wants= や Requires= 等で依存関係を示すのが3つ目の方法です。

なお、Wants や Requires 以外には以下の指定の仕方もあります。

RequiresOverridable=, Requisite=, RequisiteOverridable=, BindsTo=

依存関係や順序関係の重複

ところで、 -a を付けるとより顕著に見えてきますが、同じ Unit がかなり重複して表示されています。依存関係は該当Unitを『起動するか否か』の判断材料でしかなく、複数回起動されるような意味はありません。従って1回だけ表示されようが複数回表示されようが、起動は1回のみです。次に紹介する『順序関係の表示』についても同様です。

順序関係を深く知る

systemctl list-dependencies --after コマンドの見方

あるUnitファイルの順序関係を見るためには systemctl list-dependencies [Unitファイル] --after コマンドを使います。[Unitファイル]を省略すると自動で default.target が指定されます。

先の例の通り CentOS7.5 のMinimumインストール時の場合は以下コマンドはいずれも同じ結果になります。

  • systemctl list-dependencies --after
  • systemctl list-dependencies default.target --after
  • systemctl list-dependencies multi-user.target --after

以下に systemctl list-dependencies --after の実行結果(一部)を示します。

このツリーは『multi-user.target Unit を起動するまでに何を起動する必要があるか』を示しています。階層が深いものほど、先に実行されている必要があります。

緑丸は起動したもの、赤丸は起動できなかったもの(起動に失敗したか、Unitファイルが存在しないか、依存関係から起動が必要とされなかったか)です。

basic.target は multi-user.target ファイルに『After=basic.target』と書かれているのでそれが反映されていますが、chronyd.service 等にはそのような記述はありません。

おそらく chronyd.service 等は WantedBy=multi-user.target となっていることで、少なくともこのコマンドの表示上では WantedBy= には Before=の意味も含まれようです。

また、--before オプションを付けると逆に『multi-user.target Unit を起動した後に何を起動する必要があるか』を示しています。

以下に systemctl list-dependencies --before の実行結果(一部)を示します。

このあたりは RunLevel5 相当の graphical.target 用の Unit であるため、RunLevel3 相当の multi-user.target が default.target となっている環境においては軒並み起動していないことを示す "赤丸" が表示されています。

実際にどのような順番でサービス等のUnitが起動しているかを確認する

実際の起動順序を表示するコマンドを使って、サービス等のUnitの起動順序を確認します。

systemd-analyze plot > plot.svg

このコマンド結果として出力された plot.svg をブラウザ等で開くとどのような順番でUnitが起動したかを確認することができます。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする