投稿日:2020年11月3日
systemctlコマンドを上手く使いこなすことでsystemd、unitに対しての理解を深め、正しい設定の仕方や問題が起きた際の対処方法を学ぶことができます。この記事ではsystemctlを使ってunitを探索しています。
systemctlコマンドはそのOSで動いているsytemdのunitを操作することができます。
unitの中には絶対に止めてはいけないサービスがあります。
例えばGCPのCompute EngineのUbuntu20.04インスタンスで以下のようなコマンドをうったとします。
$ sudo systemctl disabled ssh.service
この様にすると、2度とそのインスタンスにアクセスすることができなくなってしまいます。
unitを操作するコマンドを打つときにはそのunitに何の役割があるか、コマンドがどのような影響をもたらすのかを理解する必要があります。
まずはunitに対しての最も基本的なコマンドについて紹介します。
現在のセッションでunitを起動、停止する場合にはstart、stopコマンドを使用します。
$ systemctl start nginx.service
$ systemctl stop nginx.service
enableコマンドでunitを有効化するとそのunitはOS起動時にsytemdプロセスによって自動的に起動させることができます。
サーバーなどのプロセスのunitはこの自動起動設定をすると良いでしょう。
disableコマンドで自動起動をOFFにできます。
$ systemctl enable nginx.service # 自動起動ON
$ systemctl disable nginx.service # 自動起動OFF
まずは現在のsystemdのunitを一覧表示してみます。
$ systemctl list-units
出力には次の要素が含まれます。
list-unitsで表示されるのは、デフォルトではLOADEDがloadedでACTIVEがactiveのunitだけです。
--allフラグをつけることで全てのunitを表示することができます。
$ systenctl list-units --all
このコマンドではsystemdがload・parseしようとした全てのunitが表示されます。
list-unitsコマンドは--stateフラグや--typeフラグでフィルタリングして表示することができます。
例えば
のunitを一覧表示するには下のようなコマンドになります。
$ systemctl --type=service --state=inactive --all
上のコマンドではparse・loadされメモリに読み込まれようとしたunitだけを表示しています。
それ以外にもunitの定義は存在する場合があります。
unit定義ファイルを一覧表示するコマンドがlist-unit-filesです。
$ systemctl list-unit-files --all
出力はUNIT_FILEというunitの定義ファイル名とSTATEが表示されます。
STATEがstaticのunit定義ファイルはinstallの定義が含まれておらず、unitがenabledにできないことを意味します。
このようなunitは一回きりの起動、または他のunitに参照される対象としての定義である事が考えられます。
現在可動中のserviceが正しいものか確認したり、unit定義ファイルの書き方を学ぶために、unit定義ファイルの中身を表示する方法を説明しておきます。
基本的にこれはcatコマンドを使用すればOKです。
試しにここではatd.serviceというサービスの定義ファイルを表示してみます。(atdはコマンドの実行をスケジューリングするservice)
$ systemctl cat atd.service
# /lib/systemd/system/atd.service
[Unit]
Description=Deferred execution scheduler
Documentation=man:atd(8)
After=remote-fs.target nss-user-lookup.target
[Service]
ExecStartPre=-find /var/spool/cron/atjobs -type f -name "=*" -not -newercc /run/systemd -delete
ExecStart=/usr/sbin/atd -f
IgnoreSIGPIPE=false
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
ちなみにsystemctlコマンドのサービス指定は.serviceなどを省略してsystemctl cat atd
とすることもできます。
unitは依存関係を組むことができます。
list-dependenciesコマンドはunitの依存関係を表示するコマンドです。
$ systemctl list-dependencies
default.target
● ├─accounts-daemon.service
● ├─apport.service
● ├─display-manager.service
● ├─e2scrub_reap.service
● ├─grub-common.service
● ├─systemd-update-utmp-runlevel.service
● └─multi-user.target
● ├─apport.service
● ├─atd.service
● ├─chrony.service
● ├─console-setup.service
● ├─cron.service
● ├─dbus.service
[...]
この出力によると、全てのunitがdefault.targetを起点に起動しているようです。
次にatdサービスの依存関係をみてみます。
コマンドの引数にサービス名を与えることでそのサービスの依存関係を表示することができます。
$ systemctl list-dependencies atd.service
atd.service
● ├─system.slice
● └─sysinit.target
● ├─apparmor.service
● ├─blk-availability.service
● ├─dev-hugepages.mount
● ├─dev-mqueue.mount
● ├─finalrd.service
● ├─keyboard-setup.service
[...]
atd.serviceがどのunitに依存しているか、つまりどのunitを先に起動しているべきかを表すツリーが表示できました!
再帰的な依存関係の表示はデフォルトではtargetタイプしか表示されていませんが、実は他のタイプのunitもそれぞれ依存しているunitが存在するはずです。
実際に依存するunitの依存関係を再帰的に表示しまうと表示が煩雑になってしまうことは容易に想像できますね。
このコマンドは親切設計のためにデフォルトではtargetタイプのunitの依存関係だけを表示しているのです。
全ての依存関係を表示する場合には--allフラグをつけます。
$ systemctl list-dependencies atd.service --all
またこのunitが何のunitに依存されているのかを確認したい場合は--reverseフラグをつけます。
$ systemctl list-dependencies atd.service --reverse
atd.service
● └─multi-user.target
● └─graphical.target
全ての依存関係を見た時の結果と一致していますね!
--before、--afterオプションはどのunitより前に起動しているべきか、どのunitより後に起動しているべきかを一覧表示できます。
$ systemctl list-dependencies atd.service --before
atd.service
$ systemctl list-dependencies atd.service --before
atd.service
unitのプロパティを表示するにはshowコマンドをつかいます。
$ systemctl show atd.service
Type=simple
Restart=on-failure
NotifyAccess=none
RestartUSec=100ms
TimeoutStartUSec=1min 30s
TimeoutStopUSec=1min 30s
TimeoutAbortUSec=1min 30s
RuntimeMaxUSec=infinity
WatchdogUSec=0
[...]
catコマンドで確認できるunit設定ファイルと比較してみましょう。
ただし、いまのままだとプロパティの数が多すぎて少し見づらいですね。
-pオプションを使うと特定のプロパティだけを表示できるので、これを使ってみましょう!
ここでは例としてDocumentationのプロパティの値を比較してみます。
$ systemctl cat sshd.service
# /lib/systemd/system/ssh.service
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
Alias=sshd.service
$ systemctl show sshd.service -p Documentation
Documentation=man:sshd(8) man:sshd_config(5)
一致していますね。
ここで次のunitのマスクに進む前に調べる対象のサービスとしてnginxをインストールしておきましょう。
$ sudo apt update
$ sudo apt install nginx
ComputeEngineのコンソールの外部IPにアクセスしてnginxのサンプルページが表示されることを確認しておきます。
unitのmaskとはそのunitの有効化をできなくする事です。
maskしたunitは/dev/nullのシンボリックリンクが作成されます。
disabledと違い、再度unitを起動、または自動起動化するにはそのmaskを解除しなければできません。
$ systemctl mask nginx.service # nginxをマスク
$ systemctl start nginx
Failed to start nginx.service: Unit nginx.service is masked
マスクができています。ls -la /etc/systemd/system
で確認してみるとnginx.serviceから/dev/nullへのシンボリックリンクが作成されていることがわかるでしょう。
マスクを解除するにはunmaskコマンドを使用します。
$ systemctl unmask nginx.service
editコマンドは対象のサービスの定義を編集するコマンドです。
もちろん、unitの定義ファイルはnanoやviなどのエディタで直接定義ファイルを編集することもできます。
しかし、その方法では誤った定義ファイルにした時注意点でも説明した様にOSの動作に意図しない問題を起こしてしまう可能性があります。
それを防ぐためにeditコマンドでは対象unitの差分だけを作成します。
systemctl edit nginx.service
[Unit]
Description=A high performance web server and a reverse proxy server
編集が完了すると、対象unit定義ファイル.dというディレクトリが作成され、その中にoverride.confという名前で差分の内容が入ったファイルが作成されます。
次回unitが読み込まれた時、このoverride.confの内容が元の定義ファイルの内容にマージされます。
ちなみに手動で再読込する場合はsudo sytemctl daemon-reload
というコマンドを使います。
もし、編集した差分に間違いがあった場合などにはその.dディレクトリを削除すれば元のデフォルトファイルに戻すことができます。
$ sudo rm -r /etc/systemd/system/nginx.service.d
$ sudo systemctl reload-daemon # 設定の再読込