私の質問に言及する前に、ほとんどのシステムに関する質問を確認しましたが、説得力のある答えが見つかりませんでした。私はサーバーを実行するNodejsアプリケーションを作成しました。
const express = require('express');
const app = express(),
port = process.env.PORT || 5000;
app.get('/' , ( req , res ) => {
res.send('Hello World')
})
app.listen( port , () => {
console.log(`The server listens on port ${port}`)
})
最初はserver.jsを実行するサービスを作成し、非常にスムーズに動作しました。
[Unit]
Description=Hello World
After=network.target
[Service]
ExecStart=/usr/bin/node /home/msimou/Desktop/helloWorld/server.js
User=msimou
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
ただし、サービスを開始または停止する.shファイルを生成して同じ操作を試み、ユニットファイルに含めようとしましたが、不明な理由でサーバーが機能しませんでした。更新されたユニットファイルは次のとおりです。
[Unit]
Description=Hello World
After=network.target
[Service]
ExecStart=/bin/bash /home/msimou/Desktop/helloWorld/init/startHelloWorld.sh
ExecStop=/bin/bash /home/msimou/Desktop/helloWorld/init/stopHelloWorld.sh
User=msimou
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
ログファイルを確認してエラーが/var/log/syslog
発生しましたがjournalctl
、私が見ることができる唯一のことは、システムが5秒間継続的にサービスを開始および停止することでした。を利用して確認してみると、サービスのsystemctl status helloWorld.service
成功状態と出てきますが、Nodejsアプリケーションに関連するプロセスが見つかりません。
答え1
サービスタイプを指定しなかったため、デフォルトのsystemd
サービスタイプが使用されますType=simple
。
したがって、コマンドが実際のサービスプロセスを開始すると仮定systemd
します。ExecStart
自己制御グループ(cgroup)でプロセスを開始して監視します。このプロセスのすべての子プロセスは、ExecStart
同じ制御グループのメンバーになります。
ExecStart
プロセスが終了すると、systemdはこれがサービスが終了したことを意味すると仮定します。これで、実際のサービスを開始するためにスクリプトを使用しているので、この仮定は正しくありません。この時点で、サービスをクリーンアップするために、制御グループの残りのプロセスをすべて終了します(実際のサービスプロセスを効果的に終了します)。その後、サービスを再起動しようとしてループが繰り返されます。
スクリプトを使用して間接的にサービスを開始すると、サービスを通知することなくsimple
サービスを種類別に効果的に変更できます。しかし、このジャンルにはそれに関連する追加のレガシー荷物もあります。また、サービスプロセスの監視がより困難になるため、必要な場合以外は使用しないことをお勧めします。forking
systemd
forking
systemd
理想的には、実際のサービスプロセスの開始位置をそのままにして、ExecStart=
オプションを含む物理ファイルまたはオプションが参照する別のファイルに環境変数を指定する必要があります。追加の起動コマンドはおよび/またはオプションにすることができます。これにより、そのコマンドが提供するデフォルト値と自動プロセス監視を維持できます。必要に応じてサービスを引き続き使用できます。.service
Environment=
EnvironmentFile=
ExecStartPre=
ExecStartPost=
Type=simple
ExecStop=
Type=simple
を使用すると、Type=forking
systemdは制御グループを介してサービスを追跡します。サービスが別のプロセスを作成している場合、そのプロセスがサービスの基本プロセスであるかどうかはわかりませんPIDFile=
。提供する必要があります。ExecStop=
単にサービスを盲目的に終了する以上のことをすることです。
サービスの制御グループにプロセスがない場合、systemd
サービスは依然として失敗したと検出されます。ただし、使用またはType=forking
使用しないと、PIDFile=
サービスのメインプロセスが終了する可能性があり、サブプロセスが1つ以上存在する限り障害を検出できない可能性があります。
プロセスが完了したときにExecStop=
サービスのプロセスグループにプロセスが残っている場合、これは何らかの理由で正常なシャットダウンが失敗したことを意味し、そうでない場合はすぐに制御グループの残りのプロセスをクリーンアップするためsystemd
に使用されます。SIGKILL
指定されたマニュアルページにリストされているさまざまなオプションを使用してくださいsystemd.kill(5)
。
したがって、aを使用するType=simple
必要はなく、PIDFile=
サービスやシステム全体がクラッシュして古いPIDファイルが残っても心配する必要はありません。
あなたが使用し、あなたのサービスが複数のプロセスを使用している場合は、監視目的と必要に応じて終了のためにサービスの基本プロセスを正しく識別するプロセスをType=forking
使用する必要があります。PIDFile=
systemd
SIGTERM
サービスに「基本/唯一のプロセスに送信」よりも複雑なシャットダウンプロセスが必要な場合は、ExecStop=
オプションType=
を使用してください。ただし、必要な待機/タイムアウトも処理する必要があります。サービスは閉鎖されましたか?十分プロセスがExecStop=
終わったら。その後、サービスの制御グループに残っているプロセスがあれば、安全にシャットダウンできると仮定してすぐにクリーンアップするためにsystemd
使用されます。SIGKILL