web-dev-qa-db-ja.com

Systemdは起動直後にサービスを終了します

OSSEC HIDS用のsystemdユニットファイルを作成しています。問題は、systemdがサービスを開始するとすぐに停止することです。

そのExecStartディレクティブを使用すると、すべて正常に動作します。

ExecStart=/var/ossec/bin/ossec-control start

しかし、OSSECログで細かい改善を行うと、起動後にSIG 15を受け取ることになります。

ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start'

別の小さな変更サービスを作成すると、20秒後にSIG 15を受け取ります。

ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start && sleep 20'

つまり、systemdはサービスの開始後に/ bin/shプロセスを終了し、bin/shはOSSECを終了します。

この問題を解決するにはどうすればよいですか?

15
Daniil Svetlov

準備プロトコルの不一致

ヴィーランドが示唆したように、サービスのTypeは重要です。その設定は準備プロトコル systemdがサービスが話すことを期待するものを示します。 simpleサービスはすぐに準備ができていると見なされます。 forkingサービスは、その初期プロセスが子をフォークして終了した後に準備ができていると見なされます。 dbusサービスは、サーバーがデスクトップバスに表示されたときに準備ができていると見なされます。などなど。

サービスユニットで準備されたプロトコルがサービスの動作と一致するように宣言されていない場合、問題が発生します。準備プロトコルの不一致により、サービスが正しく開始されない、または(より一般的には)systemdが失敗したと(誤って)診断されます。サービスがsystemdの起動に失敗したと見なされた場合、サービスの孤立したすべての孤立したプロセスを実行するために、(サービスの観点から)失敗の一部として実行されたままになっている可能性があるものを強制終了します。サービスは適切に非アクティブ状態に戻ります。

あなたはまさにこれをやっています。

まず、単純なもの:sh -cType=simpleまたはType=forkingと一致しません。

simpleプロトコルでは、初期プロセスはbeサービスプロセスに渡されます。しかし実際には、sh -cラッパーが実際のサービスプログラム子プロセスとしてを実行します。つまり、MAINPIDはうまくいかず、最初にExecReloadが機能しなくなります。 Type=simpleを使用する場合、最初にsh -c 'exec …'またはnot usesh -cを使用する必要があります。後者は、多くの場合、一部の人々が考えるよりも正しいコースです。

sh -cType=forkingとも一致しません。 forkingサービスの準備プロトコルは非常に具体的です。最初のプロセスは子をforkしてから終了する必要があります。 systemdはこのプロトコルにタイムアウトを適用します。最初のプロセスが割り当てられた時間内に分岐しない場合、準備ができていないことになります。最初のプロセスが割り当てられた時間内に終了しない場合、それも失敗です。

ossec-controlである不要な恐怖

これにより、複雑なもの、つまりossec-controlスクリプトが表示されます。

判明しました System 5のrcスクリプトであり、4から10のプロセス間で分岐し、それ自体が分岐して終了します。 rcループ、競合状態、任意のforsを使用して1つのスクリプトでサーバープロセスのセット全体を管理しようとするSystem 5 sleepスクリプトの1つです。それらを避け、半起動状態でシステムを窒息させる可能性がある障害モード、および20年前に人々がAIXシステムリソースコントローラーやデーモンツールなどを発明した他のすべての恐怖。そして、特異なenableおよびdisable動詞を実装するために、オンザフライで書き換えるバイナリディレクトリ内の非表示のシェルスクリプトを忘れないでください。

したがって、/bin/sh -c '/var/ossec/bin/ossec-control start'を実行すると、次のようになります。

  1. systemdは、サービスプロセスであると想定しているものをforkします。
  2. それがossec-controlをフォークするシェルです。
  3. その結果、4人から10人の孫が分岐します。
  4. 孫はすべてフォークして、順番に終了します。
  5. ひ孫はすべてフォークし、並行して終了します。
  6. ossec-controlは終了します。
  7. 最初のシェルが終了します。
  8. サービスプロセスはgreat-great- grandchildrenでしたが、この方法が一致するためどちらでもないforkingnorsimple準備プロトコル。systemdはサービス全体が失敗したと見なし、サービスをシャットダウンします。

Systemdでは、この恐怖は実際にはまったく必要ありません。どれでもない。

systemdテンプレートサービスユニット

代わりに、非常にシンプルなテンプレートユニットを記述します。

 [Unit] 
 Description = OSSEC HIDS%i server 
 After = network.target 
 
 [Service] 
 Type = simple 
 ExecStartPre =/usr/bin/env/var/ossec/bin /%p-%i -t 
 ExecStart =/usr/bin/env/var/ossec/bin /% p-%i -f 
 
 [インストール] 
 WantedBy = multi-user.target 

これを/etc/systemd/system/[email protected]として保存します。

さまざまな実際のサービスは、このテンプレートのinstantiationsで、次の名前が付けられています。

次に、機能を有効または無効にしますサービス管理システムから直接RedHatバグ752774 修正済み)。非表示のシェルスクリプトは必要ありません。

 systemctl enable ossec @ dbd ossec @ agentlessd ossec @ csyslogd ossec @ maild ossec @ execd ossec @ analysisd ossec @ logcollector ossec @ remoted ossec @ syscheckd ossec @ monitord

さらに、systemdは実際の各サービスを直接知り、追跡します。 journalctl -uでログをフィルタリングできます。個々のサービスがいつ失敗したかを知ることができます。これは、どのサービスが有効になって実行されているかを認識しています。

ちなみに、Type=simple-fオプションは、他の多くの場合と同じようにここにあります。実際にはごく少数のサービス実際に準備ができていることを示すexitの提供により、これらのサービスもそのようなケースではありません。しかし、それがforkingタイプの意味です。デーモンが本来行うべきであるという誤った受け止められた知恵の概念が原因で、メインのサービスは実際には分岐して終了します。実際、そうではありません。それは1990年代以来ありません。追いつく時間です。

参考文献

37
JdeBP

Type = forkingを維持し、start service/appがpidを維持している場合は、pidファイルの場所を指定します。

[単位]
Description = "起動時にアプリを実行"
After = network.target syslog.target auditd.service

[サービス]
Type = forking
PIDFile =/var/run/Apache2/Apache2.pid
ExecStart =/etc/init.d/Apache2 start
ExecStop =/etc/init.d/Apache2 stop
StandardOutput = syslog
StandardError = syslog
Restart = on-failure
SyslogIdentifier = webappslog

[インストール]
WantedBy = multi-user.target
エイリアス= webapps

1
Raushan

ある程度関連していますが、systemdが30秒後に「殺す」ように見えるsystemdサービスがありました。

systemctl status service-nameは、30秒が経過するとmain process exited, code=exited, status=1/FAILUREと表示されます。

「単独で」正常に実行されます(手動で 同じ環境 を使用してターミナルで)。

だったことが判明

Type=forking
...
Environment=ABC="TRUE"
ExecStart=/path/to/my_script_to_spawn_process.sh

my_script_to_spawn_process.sh以内

/bin/something > /dev/null 2>&1 &

これは機能しますが、出力ログ情報を破棄していました(通常はファイルに送られます。そうでない場合は、journalctl)。

/bin/something > /tmp/my_fileなどの別の場所にログを記録するように変更する

次に、/tmp/my_fileをテーリングすると、実際の原因が明らかになりました。これは(接線的に)bashのようにEnvironment=ABC="true"の構文を使用できないこと、引用符なし、またはEnvironment="ABC=true"のような引用符内のすべてのキー値である必要があり、これによりプロセスが終了しました。約30秒後の「セットアップ段階」。

0
rogerdpack