
私は、非常に長時間実行されるコマンド1(数時間単位)を管理するために独自のsystemd
ユニットファイルを書きたいと思っています。systemd に関する ArchWiki の記事スタートアップの種類の選択に関しては、次のように書かれています。
Type=simple
(デフォルト): systemd はサービスを直ちに起動するとみなします。プロセスは分岐してはならないソケットでアクティブ化されていない限り、このサービスで他のサービスを注文する必要がある場合は、このタイプを使用しないでください。
なぜプロセスがフォークしてはいけないのですか? これはデーモン呼び出しプロセス (親がフォークして終了する) のスタイルでのフォーク、またはあらゆる種類のフォークを指しているのでしょうか?
1 tmux/screen は不要です。 に頼らずに、よりエレガントな方法でステータスを確認し、サービスを再起動する方法が欲しいからですtmux send-keys
。
答え1
サービスはfork
システム コールを呼び出すことができます。Systemd はこれを阻止しませんし、阻止されても通知しません。この文は、デーモンを親プロセスから分離するためにデーモンの開始時にフォークする手法に特に言及しています。「プロセスはフォークしてはなりません [子プロセスでサービスを実行している間に親を終了してはなりません]」。
のマニュアルページこれをより詳細に、そしてこの特定の混乱を引き起こさない言葉で説明します。
デーモンとして使用される多くのプログラムには、起動時に親から分離するモード(多くの場合、デフォルト モード)があります。デーモンが起動し、 を呼び出しfork()
、親が終了します。子プロセスは を呼び出してsetsid()
、独自のプロセス グループとセッションで実行し、サービスを実行します。その目的は、デーモンがシェル コマンド ラインから呼び出された場合、端末が閉じるなど端末に何かが起こっても(この場合、シェルは認識しているすべてのプロセス グループに SIGHUP を送信します)、デーモンはカーネルまたはシェルからシグナルを受信しないようにすることです。これにより、サービス プロセスが init に採用され、終了時に init がそれを取得するため、ゾンビデーモンが、デーモンwait()
にとって不適切な何かによって起動された場合 (デーモンがシェルによって起動された場合は、このようなことは起こりません)。
デーモンが systemd などの監視プロセスによって起動される場合、フォークは逆効果になります。監視プロセスは、サービスがクラッシュした場合にサービスを再起動することになっているため、サービスが終了したかどうかを知る必要がありますが、サービスが監視プロセスの直接の子でない場合は困難です。監視プロセスは終了することがなく、制御端末もないため、不要なシグナルやリーピングに関する懸念はありません。したがって、サービス プロセスがモニターの子にならない理由はなく、そうする十分な理由があります。
答え2
この Arch wiki ページは無視してください。
設定に関してはかなり間違っていますType
。さらに、これは の記述に限ったことではありませんsimple
。 についての記述forking
も間違っています。
この種の正しい推奨事項は、systemd自体が存在するよりも数十年も前から存在しており、少なくとも1990年代初頭にまで遡ります。https://unix.stackexchange.com/a/476608/5132systemd のドキュメントには、デーモンに関する推奨事項の最近のバージョンがあり、daemontools ユーザー、IBM、 を使用している人々inittab
、そして…まあ…私が何十年も言ってきたことをほぼ繰り返しています。(2001 年に私がそのように書いたとき、それはすでに頻繁に返答されていました。)
繰り返す:
プログラムに「デーモン化」メカニズムがあり、特に子プロセスをフォークして親プロセスを終了する場合、消してそして使用しないでくださいdaemontoolsなどのおかげで、長い間これが必須となっていた多くのプログラムが、持っていないこのようなメカニズムは過去 20 年以上にわたって開発されてきましたが、他のメカニズムは最初から「デーモン化」をデフォルトとしていないため、デフォルトの動作モードで使用できます。
サービス管理サブシステムはサービスプロセスを起動するデーモンの文脈ではすでにこれらのプロセスは「デーモン化」する必要はありません。(実際、多くの現代のオペレーティングシステムでは、プログラムがデーモン化されると考えるのは誤りです。できるログインセッションコンテキストから「デーモン化」する。これが「デーモン化」の実際の目的である。) デーモンコンテキストに適した環境値とオープンファイル記述子が既に存在し、実際に「デーモン化」によって実行されるいくつかの処理が行われている。妨害するサービス マネージャーによってデーモンで定期的に実行される従来の処理の一部 (標準出力/エラーをログにキャプチャするなど)。
Type=simple
早期ソケットオープン(サービス管理がサーバーソケットを開き、それらを既に開いているファイル記述子としてサービスプログラムに渡す)を使用する または を優先しますType=notify
。
Type=simple
サービス プロセスが開始するとすぐに、サービスが準備完了として扱われます (そのため、そのサービスに基づいて注文されたサービスを開始/停止できます)。早期ソケット オープンでは、ソケット接続セマンティクスを使用して、サービス クライアントがサービスのためにサーバーに接続しようとする時点で、サーバーが実際に準備完了になるまでサービス クライアントを遅延させます。Type=notify
systemdとLinuxに特有であるという欠点がある(シェル生成などの短命なプロセスからは機能しないという問題と、systemd-notify
人間が読める形式を機械が読める形式に解析する特権プロセスではパーサーの問題が発生するという問題に加えて)。すでに起こった以前はそうではありませんでしたが、サービスが実際に準備完了と見なされるタイミングをより細かく制御できる (サービス プログラムの観点から) という利点があります。また、ステータス出力をある程度カスタマイズすることもできます。
どちらのタイプのサービスプログラムもフォークすることができます。フォークとはそして元のプロセスを終了するそれが問題だ。
(これは、シェルからプログラムを実行する場合も、サービスマネージャからプログラムを実行する場合も、同様に問題となることに注意してください。ユーザーは、プログラムが終了し、すぐに別のシェルプロンプトが表示されるのを目にします。実際、ちょうど今日、誰かが、親をフォークして終了するシェルからプログラムを実行することについて、再び質問していました。ターミナルでプログラムを実行すると、ターミナルで実行されないことがあるのはなぜですか?。
Type=oneshot
おそらく、この特定のケースでは、サービス プログラム全体が完了するまでサービスの準備が整っていないとみなされるため、この方法は望ましくないと思われます。この方法には用途がありますが、どうやらあなたには当てはまらないようです。
決して使用しないType=forking
でください。ほとんどのプログラムでは実際にプロトコルを話す。 彼らがやっていますその他、これは実際にはないこのプロトコルは、このプロトコルと正しく相互運用できず、実際に準備ができていることを示す信号ではありません。
参考文献
- ジョナサン・デ・ボイン・ポラード(2001年)。 Unixデーモンプログラムを設計する際に避けるべき間違いよくある質問。
- ジョナサン・デ・ボイン・ポラード(2015年)。本当に悪魔化する必要はありません。本当に。. システム化された恐怖の家。
- ジョナサン・デ・ボイン・ポラード(2015年)。Unixデーモンの準備プロトコルの問題よくある質問。
- https://unix.stackexchange.com/a/401611/5132