Ubuntuシステムのシンプル(ワンショット)とフォークの違いは何ですか?

Ubuntuシステムのシンプル(ワンショット)とフォークの違いは何ですか?
#!/bin/bash
sleep 2
nohup java -jar /home/ubuntu/radius/radius-test.jar >> /home/ubuntu/radius/radius.log &
nohup java -jar /home/ubuntu/radius/radius-test-2.jar >> /home/ubuntu/radius/radius-2.log &

起動時に自動的に実行される上記のようなスクリプトファイルがあります。

私が見つけた多くの方法の中で、私はsystemdを使用することにしました。

ところで、Typeオプションを指定する正しい方法があるのか​​、それとも問題がないのかを知りたいです。

[Unit]
Description=My Shell Script

[Service]
Type=simple or oneshot
RemainAfterExit=yes
ExecStart=/home/ubuntu/radius/radius-start.sh

[Install]
WantedBy=multi-user.target


---

[Unit]
Description=My Shell Script

[Service]
Type=forking
ExecStart=/home/ubuntu/radius/radius-start.sh

[Install]
WantedBy=multi-user.target

どちらの方法でも起動時にサービスが実行され、私のjarファイルも実行されます。そして、サービスはまだアクティブであり、jarプロセスは維持されます。その後、サービスが終了すると、すべてのjarプロセスも終了します。

確認の結果、フォークがバックグラウンドメソッドに適しており、子プロセスが実行され、親プロセスが終了することがわかりました。 (これもわかりません。)また、pidファイルを指定する必要があるか、fork方式を使用しないでください。

Simple または Oneshot を使用するにはフロントエンド操作が必要だとします。しかし、私のjarプロセスはバックグラウンドで実行する必要があります。

これら2つの方法の違いは何ですか?どのオプションを使用するのが正しい方法ですか?

ベストアンサー1

ユニットファイルの2つのバージョンを見て、提案を見てみましょう。

simpleまたはoneshotサービス

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/home/ubuntu/radius/radius-start.sh

Type=oneshotRemainAfterExit=yesとの使用に適していますType=simple

いつものようにsimple走ってくださいExecStart=。その後、プロセスが終了すると、すべてがクリーンアップされ、サービスが「停止」されます。ただし、radius-start.sh一部のプロセスは起動してすぐに停止します。これは、systemdが孤立プロセスを見つけてクリーンアップの一部として終了することを意味します。

それでoneshot、それは本当に走ってExecStart=死ぬことを意味します。このデバイスが停止したときにコマンドをRemainAfterExit=トリガーしたり、関係を利用して他のデバイスを停止したりするのに役立つ便利な方法を使用できます。ただし、作成したサブプロセスの最新の状態は提供されません。ExecStop=ConsistsOf=

この技術の大きな問題は、(孤立した)子プロセスをすぐに終了したり、子プロセスが終了したときにデバイスが停止/失敗したことを理解していないことです。


forking提供する

[Service]
Type=forking
ExecStart=/home/ubuntu/radius/radius-start.sh

これはあなたのサービスの正しいバージョンです。forkingが実行され、ExecStart=まもなく終了する予定です。その後、Systemdはいくつかの子プロセスを作成すると予想し、これらの子プロセスの状態を追跡します。基本プロセスが終了すると、systemdはサービスが停止したと見なします。

このアプローチに固執する場合は、PIDFile=systemdが2つのプロセスのうちどのプロセスが基本プロセスであるかを知るように設定することをお勧めします。

[Service]
...
PIDFile=/run/myservice.pid
...
#!/bin/bash
sleep 2
nohup java -jar /home/ubuntu/radius/radius-test.jar >> /home/ubuntu/radius/radius.log &
echo $! > /run/myservice.pid
nohup java -jar /home/ubuntu/radius/radius-test-2.jar >> /home/ubuntu/radius/radius-2.log &

ただし、systemdのドキュメントには次のように明確に記載されています。

最新のプロジェクトではPIDファイルを避ける必要があります。サービスの主なプロセスを決定し、不要なフォークを避けるためにPIDファイルを使用する必要がないように、可能な場合はType = notifyまたはType = simpleを使用してください。

bash実行しようとしているすべてのタスクは既にsystemdによってデフォルトで提供されているため、プロセスを実行するためにここを呼び出す必要はありません。


文字通りのアドバイスType=simple

あなたのサービスをそのまま実装するには、2つのサービスを使用して実装します。

# radius-test.service
[Service]
Type=simple
ExecStartPre=/bin/sleep 2
ExecStart=/usr/bin/java -jar /home/ubuntu/radius/radius-test.jar
StandardOutput=append:/home/ubuntu/radius/radius.log
# radius-test2.service
[Unit]
After=radius-test.service

[Service]
Type=simple
ExecStart=/usr/bin/java -jar /home/ubuntu/radius/radius-test-2.jar
StandardOutput=append:/home/ubuntu/radius/radius-2.log

サービスの1つが失敗した場合は、どのサービスが失敗したかを検出して復元できます。これらのサービスに特定の関係が必要な場合は定義できます。たとえば、順序付けはを使用して実装できますAfter=。もう一方が失敗した場合、それらの1つが完全に停止するようにしますBindsTo=


ソリューションの改善

  • ExecStartPre=/bin/sleep 2:これは通常ハッカー攻撃です。遅延により、良い日には不要な遅延が発生し、悪い日には不十分な遅延が発生する可能性があります。寝るべき理由を理解するのが最善です。たとえば、サービスを実行する前にネットワークを使用できるようにする必要がある場合は、代わりにを使用してくださいAfter=network.target
  • Type=simple:実際にはこれがデフォルトです。したがって、この行を削除できます。
  • radius-testが起動したときに常にradius-test2を実行するには、関係を使用します(またはWants='セクションで指定)。WantedBy=radius-testradius-test2[Install]
  • 停止中に停止したい場合は、radius-test2関係を使用してください。radius-testPartOf=
  • StandardOutput=append:...:自分のファイルに書き込むのに問題はありませんが、組み込みログを使用すると便利です。この行を削除するとログを取得できますjournalctl -u myservice.servicejournalctlログの回転、サイズ制限、フィルタリングなど、さまざまな追加機能を提供します。私はしばしば次のことをします。

journalctl -u myservice --since "5 hours ago" --until "4 hours ago"

改善されたバージョンは次のとおりです。

# /etc/systemd/system/radius-test.service
[Unit]
Description=Radius Test 1
After=network.target
Before=radius-test-2
Wants=radius-test-2

[Service]
ExecStart=/usr/bin/java -jar /home/ubuntu/radius/radius-test.jar

[Install]
WantedBy=multi-user-target

# /etc/systemd/system/radius-test2.service
[Unit]
Description=Radius Test 2
PartOf=radius-test

[Service]
ExecStart=/usr/bin/java -jar /home/ubuntu/radius/radius-test-2.jar

究極のシンプルなソリューション

StandardOutput=ただし、ログを削除して使用したので、これを単一の単位にマージすることもできます。より簡単な解決策は次のとおりですExecStartPost=

# /etc/systemd/system/radius-test.service
[Unit]
Description=Radius Test
After=network.target

[Service]
ExecStart=/usr/bin/java -jar /home/ubuntu/radius/radius-test.jar
ExecStartPost=/usr/bin/java -jar /home/ubuntu/radius/radius-test-2.jar

[Install]
WantedBy=multi-user-target

おすすめ記事