systemd - service 編

こんにちは、masm11 です。

前回から始まった systemd シリーズ。今回は .service ファイルの書き方です。

.service ファイルとは

このファイルにサービスの定義を記述します。

sysvinit 等であれば /etc/init.d//etc/rc.d/ に置いていた script の代わりとなるものです。

ファイルの置き場所としては、OS のパッケージに含まれる場合は /usr/lib/systemd/system//lib/systemd/system/ にある場合が多いと思いますが、 自分で作る場合は /etc/systemd/system/ に置きます。

[Unit] 部分

.service ファイルは、まず [Unit] という行から始まります。 [Unit] 部分は以下のような感じになっています。

[Unit]
Description=ZFS replication service
After=network.target
Requires=network.target

Description はこのサービスの説明です。あまりたいした意味はないのですが、 以下のように、ログに出力される時などに使われます。

10月 08 02:00:00 luna systemd[1]: Started ZFS replication service.

AfterRequires は依存関係を記述します。 Requires を書いておくと、network.target が起動に失敗した場合は この unit は起動しなくなります。

依存関係を記述する方法は、他にも WantsConflicts などいろいろありますが、 AfterRequires を使っていればわりとなんとかなっています。

[Service] 部分

.service ファイルには [Service] 部分があります。 以下のような感じになっています。

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/etc/systemd/lo-setup start
ExecStop=/etc/systemd/lo-setup stop
Type

simple, exec, forking, oneshot, dbus, notify, idle の 中から選択して指定します。よく使うのは oneshot, simple, forking です。

  • oneshot: 一度実行してすぐ終了するタイプに指定します。
  • simple: デフォルトです。 起動したプロセスがサービスを提供する場合に指定します。
  • fork: 起動したプロセスが起動時に fork する場合に指定します。
ExecStart / ExecStop / ExecStartPre

ExecStartsystemctl start した時に実行するコマンドを指定します。

ExecStopsystemctl stop した時にサービスを停止するコマンドを指定します。 省略することもよくあります。省略した場合は systemd がプロセスにシグナルを 送って止めます。

ExecStartPreExecStart の前に実行しておきたいコマンドを指定します。 ExecStartPre は複数指定することができます。

マニュアルには

If the command is not a full (absolute) path, it will be resolved to a full path using a fixed search path determinted at compilation time.

と、コマンドがフルパスでなくても大丈夫そうなことが書いてありますが、 経験的にはフルパスでないと動いてくれません。

コマンドの前に - を書いておくと、エラーを無視してくれるようです。 ExecStartPre でちょっと先に実行しておきたいけど、エラーになる場合もある、 というような場合に便利そうです。

RemainAfterExit
RemainAfterExit=yes

と指定しておくと、プロセスが終了しても、異常扱いになりません。

Restart / RestartSec
Restart=always

と指定しておくと、プロセスが終了した場合に、もう一度起動してくれます。

ただ、すぐに起動してしまうので、間隔をあけたい場合は、追加で

RestartSec=5

と指定しておけば、5秒待ってくれます。

User

プロセスのユーザを指定します。

User=masm

聞くところによると、存在しないユーザを指定すると root になってしまう 仕様だそうです。User を指定する際にはご注意ください。

StandardOutput / StandardError

これらは、プロセスの標準出力と標準エラー出力をどうするかを指定します。

私は大抵 journal と指定しています。この場合、systemd の journal に 出力され、journalctl コマンドで見ることができます。

他にも、ファイルへ出力したり、tty に出力したり、いろいろな指定ができるようです。

[Install] 部分

これを書いておくと、systemctl enable できるようになります。

[Install]
WantedBy=multi-user.target

multi-user で起動する際には、この .service も start する、 という指定です。

大抵の場合は multi-user.target で大丈夫です。

@%i

.service ファイルのファイル名に @ を含めることができます。 例えば zfsnap@.service という感じです。

この場合、systemctl enablesystemctl start の際には、

systemctl start zfsnap@2w.service

というように指定します。@ の後ろに 2w と付けました。 この 2w.service ファイルの中で、%i を使って受け取れます。 具体的には以下のように使います。

[Service]
Type=oneshot
ExecStart=/usr/bin/zfsnap snapshot -a %i zbak/android zbak/svc zbak/tama

この場合だと、%i2w に置き換わって、

/usr/bin/zfsnap snapshot -a 2w zbak/android zbak/svc zbak/tama

が実行されるわけです。

この zfsnap@.service ファイル一つで、zfsnap@2w.service, zfsnap@3d.service など いろんな使い方ができます。

あまり使わないですが、たまに便利なことがある機能です。

まとめ

今回は .service ファイルの書き方を経験を交えながら淡々と説明しました。 前回同様、私が使うものだけに絞っています。

.service ファイルはそれだけで使うこともできますが、 他の unit ファイルと組み合わせて使うこともできる、便利なものです。 組み合わせ方は次々回以降に説明しますのでご期待下さい。

ではまた!