web-dev-qa-db-ja.com

systemdでOnFailureを使用する適切な方法

サービスが実行されているソフトウェアがあり、存在しない場合はいくつかの構成ファイルを生成し、存在する場合はそれらを読み取ります。私が直面している問題は、これらのファイルが破損してソフトウェアが起動できなくなり、サービスが失敗することです。この場合、これらのファイルを削除してサービスを再起動します。

これを行うことで、失敗した場合に実行されるサービスを作成してみました。

[Service]
ExecStart=/bin/run_program
OnFailure=software-fail.service

このサービスは次のとおりです。

[Service]
ExecStart=/bin/rm /file/to/delete
ExecStop=systemctl --user start software.service

ただし、問題は、サービスが失敗した場合でも、このサービスが開始されないことです。
やってみました

systemctl --user enable software-fail.service

ただし、他のサービスと同様に、システムが起動するたびに起動します。

私の一時的な解決策は

ExecStopPost=/bin/rm /file/to/delete

しかし、これが問題を解決するための満足のいく方法ではありません。それは、サービスが停止した場合、それが失敗によるものかどうかに関係なく、常にファイルを削除するためです。

失敗した場合の出力:

● software.service - Software
   Loaded: loaded (/home/trippelganger/.config/systemd/user/software.service; enabled;  vendor preset: enabled)
   Active: failed (Result: exit-code) since Fri 2018-05-04 09:05:26 CEST; 5s ago
  Process: 1839 ExecStart=/bin/run_program (code=exited, status=1/FAILURE)
 Main PID: 1839 (code=exited, status=1/FAILURE)



May 04 09:05:26 trippelganger systemd[595]: software.service: Main process exited, code=exited, status=1/FAILURE
May 04 09:05:26 trippelganger systemd[595]: software.service: Unit entered failed state.
May 04 09:05:26 trippelganger systemd[595]: software.service: Failed with result 'exit-code'.

Systemctl --user status software-fail.serviceの出力は次のとおりです。

● software-fail.service - Delete corrupt files
   Loaded: loaded (/home/trippelganger/.config/systemd/user/software-fail.service; disabled; vendor preset: enabled)
   Active: inactive (dead)
5
trippelganger

[〜#〜] note [〜#〜]:ここでは_ExecStopPost=_の代わりに_OnFailure=_を使用したいと思うかもしれませんが(これは私の別の回答を参照)、これは対処しようとしています_OnFailure=_設定が機能しない理由.

ユニットを開始しない_OnFailure=_の問題は、ユニットが間違ったセクションにあるためである可能性があります。_[Unit]_ではなく_[Service]_セクションにある必要があります。

代わりにこれを試すことができます:

_# software.service
[Unit]
Description=Software
OnFailure=software-fail.service

[Service]
ExecStart=/bin/run_program
_

そして:

_# software-fail.service
[Unit]
Description=Delete corrupt files

[Service]
ExecStart=/bin/rm /file/to/delete
ExecStop=/bin/systemctl --user start software.service
_

この設定で動作させることができます。

ただし、プログラムが失敗した理由を実際に判断できないため、_OnFailure=_を使用することはここでは理想的ではなく、_ExecStop=_を直接呼び出すことによって_/bin/systemctl start_でプログラムの別の開始をチェーンすることはかなりハックです。 .. _ExecStopPost=_を使用して終了ステータスを確認するソリューションは、間違いなく優れています。

_OnFailure=_内で_[Service]_を定義すると、systemd(少なくともFedora 27のバージョン234)は次のように不満を示します。

_software.service:6: Unknown lvalue 'OnFailure' in section 'Service'
_

ログにそれが表示されているかどうかわからない...(たぶんこれは最近のsystemdで追加されたのでしょうか?)これはそこで起こっていることのヒントになるはずです。

5
filbranden

サービスが失敗した場合にクリーンアップを実行するには、サービスが成功したかどうかにかかわらず実行される ExecStopPost= を使用できます。

ExecStopPost=で実行するコードでは、$SERVICE_RESULT$EXIT_CODE、または$EXIT_STATUSのいずれかを使用して、障害状態を特定し、それに応じて行動できます。これらの環境変数の documentation を参照して、どちらが適切かを確認してください。

次に、Restart=on-failureを使用して、失敗したときにsystemdがユニットの再起動を試行できるようにします。

まとめると、次のようになります。ファイルが破損するたびにrun_programがステータス2で終了すると仮定すると(うまくいけば、これを上記のドキュメントにある他の障害シナリオに適合させることができます)、これは機能するはずです。

[Service]
ExecStart=/bin/run_program
ExecStopPost=/bin/sh -c 'if [ "$$EXIT_STATUS" = 2 ]; then rm /file/to/delete; fi'
Restart=on-failure

[〜#〜] note [〜#〜]:二重ドル記号$$は、これをsystemdにエスケープするため、シェルは$EXIT_STATUSを参照してその変数にアクセスします。単一のドル記号を使用しても機能しますが、systemdは代わりにその置換を行い、シェルは[ "2" = 2 ]を参照します。このすべてのロジックをシェルスクリプトに入れ、ExecStopPost=のフルパスで呼び出すことで、そのほとんどをバイパスできます。これはおそらくより良い方法であり、ログに記録するなど、スクリプトにコマンドを簡単に追加することもできます。エラー状態から回復するために実行されたアクション)

うまくいけば、これにより、特定の状況で正しく構成する方法を理解するための十分な指針が得られるでしょう。

5
filbranden

注意が必要なのはsystemdバージョンです。 $EXIT_STATUSと関連する値の良さは、2017年5月にリリースされたsystemdバージョン232で導入されました

RHEL 7.xのような一部のDistro(タイピング時)は、$EXIT_STATUSなどの変数を設定しないsystemdバージョン219をまだ使用しています。したがって、上記の優れたアドバイスを使用することはできません:( ...

0
Rob