以下のコマンドは、基本的にroot権限で実行するものとする。
1.最小限のユニットファイル
1.1 ユニットファイルを作成
コマンドでsystemctl edit --full --force <作成するユニット名>.service
を実行すると、エディタが自動で開く。
エディタで以下のように入力し、エディタを閉じれば、最低限のユニットファイルができあがる。(ここでは仮に、tcpdumpでパケットキャプチャをするサービスを作ってみる)
[Unit]
Description=systemdユニットのテスト
[Service]
ExecStart=/usr/bin/tcpdump -w /var/log/capture.pcap
「Description」はユニットの説明、「ExecStart」はsystemctl start <ユニット名>.service
で実行される、ユニットの処理を開始するコマンドを指定する。
これを設定することで、systemctl status <ユニット名>
でユニットの情報表示、systemctl start <ユニット名>
でユニットの起動、systemctl stop <ユニット名>
でユニットの停止ができるようになる。
1.2 解説
systemdのユニットファイルは、/usr/lib/systemd/system/
(/lib/systemd/system/
の場合もある)の下、もしくは/etc/systemd/system/
の下に配置される。/usr/lib/systemd/system/
はパッケージマネージャが管理するので、基本的に編集するのは/etc/systemd/system/
下のファイルになる。
systemctl edit
コマンドを使うと、/etc/systemd/system
下のファイルを操作できる。オプションによって以下のように動作が変わる。
-
systemctl edit <ユニット名>.service
: 既存のユニットファイルの設定の一部をオーバーライドする。ファイルは/etc/systemd/system/<ユニット名>.d/
下に保存される。 -
systemctl edit --full <ユニット名>.service
: 上のように別ディレクトリでオーバーライドするのではなく、/etc/systemd/system/<ユニット名>.service
を直接書き換える。 -
systemctl edit --full --force <ユニット名>.service
: 指定したユニットが存在しない場合、/etc/systemd/system/<ユニット名>.service
を新規作成する。
エディタなどで直接/etc/systemd/system/
の下にファイルを作ってもよい。ただし、その場合は編集後に、設定を反映するためにsystemctl daemon-reload
を実行する必要がある。
2.serviceの動作を変更する
1で作ったシンプルなユニットファイルでも機能するが、もう少し細かい設定をしてみたい。
以下の設定は[Service]の下で設定する。
※ここでは一部の設定項目しか紹介していない。他の設定項目については、systemd.unit(5)、systemd.service(5)、systemd.exec(5)、systemd-kill(5)、systemd.resource-control(5)などを参照のこと。
Type=
serviceのタイプを指定する。
Type=simple
デフォルト。基本的にはこれを使えば問題ない。
Type=forking
親プロセスがすぐに終了し、子プロセスを起動するようなコマンドの場合、このタイプを使う。
Type=oneshot
設定の変更やある種の起動コマンドのような、一瞬で処理が終了する(裏で長時間プロセスを動かさない)コマンドに使う。このタイプでは、一緒にRemainAfterExit=true
(プロセスが終了しても、サービスはActive状態として扱われる)を設定することがある。
Restart=
プロセスが終了したときに、プロセスを自動でもう一度開始するかどうかを設定できる。(systemctl stop
などで明示的に停止した場合は再開されない)
Restart=no
再開しない(デフォルト)
Restart=on-failure
異常終了した場合は再開する。(終了コード0以外の場合に異常終了とみなす。)
Restart=always
必ず再開する。
RestartSec=
Restart=の設定で再開するまでの間隔を指定できる。
デフォルトは100ms(100ミリ秒)
StartLimitBurst=, StartLimitIntervalSec=
StartLimitIntervalSec
秒以内にStartLimitBurst
回以上、サービスを開始しようとすると無効になる。
Restart=
と組み合わせて、何度も繰り返し再開を試みるのを抑止できる。
デフォルトは10秒、5回
SuccessExitStatus=
デフォルトで正常終了扱いになる「0」以外に、正常終了扱いにする終了コードを指定できる。
User=,Group=
コマンドの実行ユーザ、実行グループを指定できる。(デフォルトではroot)
ExecStop=
systemctl stop
などでサービスを停止するときに実行するコマンドを指定できる。(デフォルトではSIGTERMを送ってプロセスを終了する)
ExecStopPost=
プロセスが終了した後に、後処理として実行するコマンドを指定できる。
プロセスが異常終了し、Restart=on-failureの設定などで再起動される場合にも実行される。
CPUQuota=
CPUの最大使用率を制限する。単位として「%」をつけて指定する。
topコマンドなどのCPU使用率の表示と同じように、1コアをすべて使った場合に100%となるので、マルチコアのシステムでは100%以上を指定してもよい。
MemoryHigh=
最大使用メモリを指定する。単位としてK, M, G, Tが使える。
メモリ制限を超過してもプロセスは停止しないが、実行が非常に遅くなる。
MemoryMax=
上のMemoryHighと同様だが、メモリ制限を超過するとプロセスが停止する。
1.1のユニットファイルの改善
上で紹介した設定項目を使用して、1.1のユニットファイルを改善してみた。
・改善点
- 異常終了時に自動で再開する
- プロセス終了時にキャプチャファイルの名前を変更し、上書きされないようにする
[Unit]
Description=systemdユニットのテスト
[Service]
Type=simple
ExecStart=/usr/bin/tcpdump -w /var/log/capture.pcap
Restart=on-failure
ExecStopPost=/usr/local/bin/mv_capture.sh
また、以下のようなスクリプト/usr/local/bin/mv_capture.sh
を作成しておく。(ExecStopPost=
で直接コマンドを書かないのは、systemdはシェルを通さずにコマンドを実行するため、コマンド置換が使えないから)
#!/bin/bash
mv /var/log/capture.pcap /var/log/capture_$(date '+%Y%m%d%H%M%S').pcap
参考リンク
https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html
https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html
https://www.freedesktop.org/software/systemd/man/latest/systemd.kill.html