【Linuxのサービス依存関係と順序関係】systemctl list-dependencies と systemd-analyze の見方 | SEの道標
Linux基礎

【Linuxのサービス依存関係と順序関係】systemctl list-dependencies と systemd-analyze の見方

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

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

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

例えば CentOS7 や CentOS8 の 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 起動に失敗することもあります。

例えば以下の設定をすると起動しなくなってしまいます。(ひたすら起動を試み続ける。)

sysinit.target ファイルに『After=basic.target』を追記

なぜなら basic.target には『After=sysinit.target』と書かれており、鶏⇔卵の関係になり、お互い相手の処理が終わるのを待ち続けるからです。

依存関係を深く知る

systemctl list-dependencies コマンドの見方

ある Unit ファイルの依存関係を見るためには systemctl list-dependencies [Unit ファイル] コマンドを使います。[Unit ファイル]を省略すると自動で default.target が指定されます。 default.target は SymbolicLink なので前述の通り CentOS7 や CentOS8 の 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=

Wants と Requires の違い

Wants と Requires の違いは失敗時の挙動です。

Wants は依存度が弱く、依存関係の相手が起動に失敗したとしても気にせず起動処理を進めます。一方、Requires は依存度が強く、依存関係の相手の起動に失敗した場合は自分も失敗として処理します

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

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

従って 1 回だけ表示されようが複数回表示されようが、起動は 1 回のみです。次に紹介する『順序関係の表示』についても同様です。

順序関係を深く知る

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

ある Unit ファイルの順序関係を見るためには systemctl list-dependencies [Unitファイル] --after コマンドを使います。

[Unit ファイル]を省略すると自動で default.target が指定されます。 先の例の通り CentOS7 や CentOS8 の 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 が起動したかを確認することができます。

コメント

  1. nanabach より:

    依存関係と順序関係の違いがなかなか分からなかったのですが、この記事読んですっきりしました。
    ありがとうございます。

タイトルとURLをコピーしました