Systemdがserviceプロセス終了時にstopするのは正しいか
systemd
- TOP
- Old Archives
- Systemdがserviceプロセス終了時にstopするのは正しいか
SystemdユニットでExecStop
を書いたのが初めてだったのだけれど、どうしてもExecStop
を書くとType
によらずstop
されてしまう。
Type
がoneshot
であるならばこれは正しい。
Type=oneshot
である場合、.service
ユニット起動時にExecStart
を実行し、この終了を待つ。
ExecStart
プロセスの実行中はactiveとなり、実行が終了するとサービスそのものが終了したとみなし、inactiveになる。
Systemdユニットに詳しい人は割と少ないのでサービスタイプについて改めて解説しておこう。
oneshot
は単純にその時に実行するだけのサービスである。
起動は実行終了を待ち、終了したらサービス自体を終了する。
simple
はデフォルトのサービスタイプである。
このサービスタイプはプロセスを実行していることで機能するサービスである。
フォアグラウンドで実行を継続するタイプのサービスに対して適用し、起動時は実行すると起動完了とみなす。oneshot
のように起動したプロセスの実行中がactiveとなる。
forking
はoneshotのようにサービスの実行終了を待つが、ステータスは直接実行したプロセス($MAINPID
)だけでなく、その子プロセスで判断する。
これは実行するのがサービスそのものではなく、起動スクリプトである場合に有用である。
さぁ、ここまではいい。
問題は、ExecStop
がいつ実行されるのか、である。
普通に考えればsystemctl stop foo.service
したときに実行されるものだろう。
ところが実際は「サービスが終了した場合にも実行される」。
これはExecStopPost
と同じだ。
だが、そうでないケース(今回の場合は、iscsiターゲットにログインし、ファイルシステムをマウントする)は困ってしまう。
このようなケースにおいてはiscsiターゲットログインとファイルシステムマウントをそれぞれ別のユニットとして管理するという方法もあるが、いずれにせよ「実行時に終わっては困る」のである。
このようなケースにおいてはTypeとしてoneshot
を指定した上でRemainAfterExit=true
とすることで目的を達することができる。
これにより、実行が終了した(起動したプロセスが終了した)場合でも実行ステータスは実行中になる。
つまり、ExecStop
というのは、「サービスを停止する」のではなく「サービスプロセスのガベージコレクション」なのだ。
RemainAfterExit=true
は基本的にoneshot
と組み合わせる前提になっている。
simple
やforking
でも作用するが、マニュアルにはoneshot
前提で書かれている。
つまりSystemdが起動したプロセスが終了してもサービスは有効な状態になっているようなスクリプトはoneshot
であるべきだと考えられているのだろう。
だが、これは適切なのだろうか?
確かに、実行終了してもactiveな状態になっているようなものはsimple
の「サービスを提供するために実行しつづける」には該当しないし、forking
の「子プロセスがサービスとして機能する」である必然性もない。
だからoneshot
だけの例外的な振舞いだと考えていいように思われるが、それでも「サービス終了時に明示的にstopしてしまう」のであればRemainAfterExit=false
がデフォルトであることには違和感がある。
それ以上に「ExecStop
は明示的に停止された場合にのみ実行する」オプションがないのは問題ではないのか。
OnSuccess
やOnFailre
はあるが、「明示的に指定された場合のみ実行したい」という希望には沿わない。
(あるいは、存在するが私が見つけられないのだろうか)
むしろ「OnSuccess
やOnFailre
があるのだから、ExecStop
は明示的停止した場合にのみ実行したい」というのが自然なように思うのだが…