systemd
を書いています OSSECHIDSのユニットファイル。問題は、systemd
サービスを開始するとすぐに停止します。
次のExecStart
を使用する場合 ディレクティブはすべて正常に機能しています。
ExecStart=/var/ossec/bin/ossec-control start
しかし、少し改善した後、これを行うと、OSSECログでSIG 15
を受信していることがわかります。 開始後。
ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start'
別の小さな変更を加えると、サービスはSIG 15
を受け取ります 20秒後。
ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start && sleep 20'
つまり、systemd
/bin/sh
を強制終了します サービス開始後に処理し、/bin/sh
次に、OSSEC
を強制終了します 。
この問題を解決するにはどうすればよいですか?
承認された回答:
準備プロトコルの不一致
Wielandが示唆しているように、Type
サービスの重要です。その設定は、準備プロトコルを示します systemdはサービスが話すことを期待しています。 simple
サービスはすぐに準備ができていると見なされます。 forking
サービスは、最初のプロセスが子をフォークして終了した後、準備ができていると見なされます。 dbus
サーバーがデスクトップバスに表示されると、サービスの準備が整います。など。
サービスユニットで宣言された準備プロトコルがサービスの機能と一致しない場合、問題が発生します。準備プロトコルの不一致により、サービスが正しく開始されないか、(より一般的には)systemdによって失敗と(誤)診断されます。サービスがsystemdの開始に失敗したと見なされた場合、サービスのすべての孤立した追加プロセスが保証されます。 サービスを適切に非アクティブ状態に戻すために、(その観点から)障害の一部として実行されたままになっている可能性のあるものが強制終了されます。
あなたはまさにこれをやっています。
まず第一に、単純なもの:sh -c
Type=simple
と一致しません またはType=forking
。
simple
プロトコルの場合、最初のプロセスはになります。 サービスプロセス。しかし実際にはsh -c
ラッパーは実際のサービスプログラムを子プロセスとして実行します 。したがって、MAINPID
うまくいかず、ExecReload
手始めに、動作を停止します。 Type=simple
を使用する場合 、sh -c 'exec …'
のいずれかを使用する必要があります または使用しない sh -c
そもそも。後者は、多くの場合、一部の人々が考えるよりも正しいコースです。
sh -c
Type=forking
と一致しません また。 forking
の準備プロトコル サービスは非常に具体的です。最初のプロセスでは、子をフォークしてから終了する必要があります。 systemdはこのプロトコルにタイムアウトを適用します。最初のプロセスが割り当てられた時間内に分岐しない場合、準備ができていません。割り当てられた時間内に最初のプロセスが終了しない場合、それも失敗です。
ossec-control
である不必要な恐怖
それは私たちを複雑なものに導きます:そのossec-control
スクリプト。
System 5 rc
であることが判明しました 4〜10個のプロセスをフォークするスクリプトで、プロセス自体もフォークして終了します。これは、System 5 rc
の1つです。 for
を使用して、サーバープロセスのセット全体を1つのスクリプトで管理しようとするスクリプト ループ、競合状態、任意のsleep
sそれらを回避しようとすること、システムを半分起動した状態で窒息させる可能性のある障害モード、および20年前にAIXシステムリソースコントローラーやdaemontoolsなどの発明を人々にもたらした他のすべての恐怖。そして、特異なenable
を実装するために、その場で書き換えるバイナリディレクトリ内の隠しシェルスクリプトを忘れないでください。 およびdisable
動詞。
したがって、/bin/sh -c '/var/ossec/bin/ossec-control start'
を実行すると 何が起こるか:
- systemdは、サービスプロセスとして期待されるものをフォークします。
- これがシェルで、
ossec-control
をフォークします 。 - これにより、4〜10人の孫が分岐します。
- 孫は全員、順番に分岐して終了します。
- 曽孫はすべて分岐し、並行して終了します。
-
ossec-control
終了します。 - 最初のシェルが終了します。
- サービスプロセスはgreat-great- 孫ですが、この働き方はどちらとも一致しない
forking
またsimple
準備プロトコル、systemdはサービス全体が失敗したと見なし、シャットダウンします。
systemdでは、この恐怖は実際にはまったく必要ありません。どれもありません。
systemdテンプレートサービスユニット
代わりに、非常に単純なテンプレートユニットを作成します。 :
[Unit] Description=The 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 [Install] WantedBy=multi-user.target
これを/etc/systemd/system/[email protected]
として保存します 。
さまざまな実際のサービスはインスタンス化です このテンプレートの名前:
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
次に、機能を有効または無効にしますサービス管理システムから直接提供されます (RedHatバグ752774が修正されました)、非表示のシェルスクリプトは必要ありません。
systemctl enable [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
さらに、systemdは実際の各サービスを直接知り、追跡するようになります。 journalctl -u
を使用してログをフィルタリングできます 。個々のサービスがいつ失敗したかを知ることができます。どのサービスが有効になって実行されているかを認識しています。
ちなみに:Type=simple
および-f
オプションは、他の多くの場合と同じようにここにあります。野生のサービスのほとんどは実際に準備ができていることを示しています exit
のdintによる 、そしてこれらもそのような場合ではありません。しかし、それがforking
タイプはを意味します。メインの野生のサービスは、デーモンが行うことになっていることであるという誤った知識の概念を受け取ったために、分岐して終了します。実際、そうではありません。 1990年代からではありません。追いつく時が来ました。
さらに読む
- ジョナサンデボインポラード(2015)。 Unixデーモンの準備プロトコルの問題 。頻繁に与えられる回答。