node.js - 当 Node 应用程序永远使用时,如何将其启动为systemd服务?

标签 node.js systemd forever

我是 Node 新手,正在阅读 Ryan Lewis 撰写的优秀 AWS 开发人员教程。在该类(class)中,我们学习使用 AWS Marketplace 中的 Bitnami Node.js 镜像将 Node.js 应用程序部署到 AWS EC2。为了练习一下,我想使用 systemd 将应用程序转换为服务,以便它在重新启动后恢复。然而,经过大量调试后,我发现该服务似乎一直在重新启动,并且该应用程序从未上线。这可能是由应用程序的启动方式引起的。它使用forever CLI 工具运行。当我手动运行 npm start 时,我看到以下输出:

npm start

> hbfl@1.0.0 prestart /home/bitnami/hamstercourse
> npm run build


> hbfl@1.0.0 build /home/bitnami/hamstercourse
> webpack

(node:19917) DeprecationWarning: Chunk.modules is deprecated. Use Chunk.getNumberOfModules/mapModules/forEachModule/containsModule instead.
Hash: aa4bec1a367d114f2c7f
Version: webpack 3.3.0
Time: 12349ms
             Asset     Size  Chunks                    Chunk Names
application.min.js   363 kB       0  [emitted]  [big]  application
    stylesheet.css  13.4 kB       0  [emitted]         application
  [10] ./node_modules/react-redux/es/index.js + 14 modules 37.6 kB {0} [built]
  [18] ./node_modules/react-router-dom/es/index.js + 13 modules 11.9 kB {0} [built]
  [59] ./node_modules/redux/es/index.js + 6 modules 21.3 kB {0} [built]
  [62] ./node_modules/react-router-redux/es/index.js + 4 modules 5.87 kB {0} [built]
 [105] ./app/index.jsx 1.86 kB {0} [built]
 [209] ./app/router.jsx 2.85 kB {0} [built]
 [211] ./app/routes/index.jsx 1.65 kB {0} [built]
 [287] ./app/reducers/index.js 316 bytes {0} [built]
 [288] ./app/reducers/hamsters.js 717 bytes {0} [built]
 [289] ./app/reducers/races.js 649 bytes {0} [built]
 [290] ./app/reducers/user.js 2.32 kB {0} [built]
 [291] ./app/reducers/leaderboards.js 355 bytes {0} [built]
 [292] ./app/reducers/status.js 285 bytes {0} [built]
 [293] ./app/index.less 41 bytes {0} [built]
 [326] ./node_modules/css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!./node_modules/less-loader/dist!./app/index.less 247 bytes [built]
    + 312 hidden modules
Child extract-text-webpack-plugin:
       [0] ./node_modules/css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!./node_modules/less-loader/dist!./app/index.less 247 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       [0] ./node_modules/css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!./node_modules/less-loader/dist!./app/scenes/Config/index.less 485 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin:
       [0] ./node_modules/css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!./node_modules/less-loader/dist!./app/scenes/User/index.less 275 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin:
       [0] ./node_modules/css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!./node_modules/less-loader/dist!./app/scenes/Leaderboards/index.less 485 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin:
       [0] ./node_modules/css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!./node_modules/less-loader/dist!./app/scenes/Races/index.less 485 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin:
       [0] ./node_modules/css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!./node_modules/less-loader/dist!./app/scenes/Race/index.less 485 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin:
       [0] ./node_modules/css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!./node_modules/less-loader/dist!./app/scenes/Main/index.less 501 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin:
       [0] ./node_modules/css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!./node_modules/less-loader/dist!./app/scenes/Login/index.less 488 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin:
       [0] ./node_modules/css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!./node_modules/less-loader/dist!./app/scenes/Hamster/index.less 485 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin:
       [0] ./node_modules/css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!./node_modules/less-loader/dist!./app/scenes/Hamsters/index.less 617 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       [0] ./node_modules/css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!./node_modules/less-loader/dist!./app/scenes/Main/Hero/index.less 827 bytes {0} [built]
        + 1 hidden module
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules
Child extract-text-webpack-plugin:
       2 modules

> hbfl@1.0.0 start /home/bitnami/hamstercourse
> forever stopall && ./node_modules/.bin/forever start index.js

info:    No forever processes running
warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: index.js

然后该进程将转到后台,并可以使用永远列表永远停止等进行管理。如所解释的 here , systemd 杀死后台进程(并且背后有很好的推理)。

为了证实我的怀疑,我尝试像这样运行该服务:

[Unit]
Description=Node.js Hamster Http Server

[Service]
PIDFile=~/hamster-99.pid
User=bitnami
Group=bitnami
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
KillSignal=SIGQUIT
WorkingDirectory=/home/bitnami/hamstercourse
ExecStart=/opt/bitnami/nodejs/bin/node /home/bitnami/hamstercourse/index.js

[Install]
WantedBy=multi-user.target

启用服务并重新加载守护程序后,输出为:

hamster.service - Node.js Hamster Http Server
   Loaded: loaded (/etc/systemd/system/hamster.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2019-06-26 10:57:46 UTC; 28min ago
 Main PID: 19847 (.node.bin)
    Tasks: 11
   Memory: 26.8M
      CPU: 2.019s
   CGroup: /system.slice/hamster.service
           +-19847 /opt/bitnami/nodejs/bin/.node.bin /home/bitnami/hamstercourse/index.js

Jun 26 10:57:46 ip-172-31-35-115 systemd[1]: hamster.service: Main process exited, code=dumped, status=3/QUIT
Jun 26 10:57:46 ip-172-31-35-115 systemd[1]: Stopped Node.js Hamster Http Server.
Jun 26 10:57:46 ip-172-31-35-115 systemd[1]: hamster.service: Unit entered failed state.
Jun 26 10:57:46 ip-172-31-35-115 systemd[1]: hamster.service: Failed with result 'core-dump'.
Jun 26 10:57:46 ip-172-31-35-115 systemd[1]: Started Node.js Hamster Http Server.
Jun 26 10:57:48 ip-172-31-35-115 node[19847]: Server started at http://localhost:3000

好消息是:这实际上运行了该服务。欢呼!但是,它跳过了 npm start 实际运行的许多基本步骤(例如缩小应用程序),并且它当然不会永远运行应用程序。人们可能会讨论在作为服务运行时是否需要使用像forever这样的管理工具,但应该可以从systemd运行它而无需更改应用程序,对吗?那么我该怎么做呢?

更新:

我刚刚找到https://unix.stackexchange.com/questions/308311/systemd-service-runs-without-exiting并尝试在单元文件中使用 Type=forking 。这似乎确实有效。但这是正确的方法吗?或者还有其他最佳实践吗?

最佳答案

我认为Type=forking是正确的。

https://www.freedesktop.org/software/systemd/man/systemd.service.html

If set to forking, it is expected that the process configured with ExecStart= will call fork() as part of its start-up. The parent process is expected to exit when start-up is complete and all communication channels are set up. The child continues to run as the main service process, and the service manager will consider the unit started when the parent process exits. This is the behavior of traditional UNIX services. If this setting is used, it is recommended to also use the PIDFile= option, so that systemd can reliably identify the main process of the service. systemd will proceed with starting follow-up units as soon as the parent process exits.

这就是永远的工作原理。另请注意,apache2 服务也使用 Type=forking

关于node.js - 当 Node 应用程序永远使用时,如何将其启动为systemd服务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56772079/

相关文章:

node.js - 我如何通过 Mongodb 查询数组类型

linux - 使用 Systemd 在 Ubuntu VM 的后台运行 Node 应用程序

javascript - 使用forever运行node.js脚本

angularjs - http-server 未在 systemd 中启动

php - PHP是否有一个forever.js等价物来连续运行我的脚本?

node.js - Forever:安装两个 Node 版本后,指定要运行的 Node 版本

javascript - Express.js 需要 session 才能访问特定路由

mysql - 使用 sequelize 在 mySql 中定义静态函数(如 Mongoose )

node.js - 使用 unix 套接字连接 docker websocket

apache-kafka - 无法在 CentOS 7 上将 Kafka-Connect 作为服务启动