シェルスクリプトを指すと、node.jsアプリケーションのシステムサービスファイルが機能しません。

シェルスクリプトを指すと、node.jsアプリケーションのシステムサービスファイルが機能しません。

私の質問に言及する前に、ほとんどのシステムに関する質問を確認しましたが、説得力のある答えが見つかりませんでした。私はサーバーを実行する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サービスを種類別に効果的に変更できます。しかし、このジャンルにはそれに関連する追加のレガシー荷物もあります。また、サービスプロセスの監視がより困難になるため、必要な場合以外は使用しないことをお勧めします。forkingsystemdforkingsystemd

理想的には、実際のサービスプロセスの開始位置をそのままにして、ExecStart=オプションを含む物理ファイルまたはオプションが参照する別のファイルに環境変数を指定する必要があります。追加の起動コマンドはおよび/またはオプションにすることができます。これにより、そのコマンドが提供するデフォルト値と自動プロセス監視を維持できます。必要に応じてサービスを引き続き使用できます。.serviceEnvironment=EnvironmentFile=ExecStartPre=ExecStartPost=Type=simpleExecStop=Type=simple


を使用すると、Type=forkingsystemdは制御グループを介してサービスを追跡します。サービスが別のプロセスを作成している場合、そのプロセスがサービスの基本プロセスであるかどうかはわかりません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

関連情報