我是node的新手,并遵循Ryan Lewis的优秀AWS开发人员教程。在该课程中,我们将学习如何使用 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
然后该过程进入后台,可以使用forever list
、forever stop
等进行管理。正如这里所解释的,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
运行应用程序。有人可能会讨论在作为服务运行时是否希望使用像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
如果设置为分叉,则预计进程配置 ExecStart= 将调用 fork() 作为其启动的一部分。父级 预计在启动完成且所有 建立沟通渠道。孩子继续以 主要服务流程,服务经理会考虑单位 在父进程退出时启动。这是的行为 传统的 UNIX 服务。如果使用此设置,建议 同时使用 PIDFile= 选项,以便 systemd 可以可靠地识别 服务的主要过程。systemd 将继续启动 父进程退出后立即跟进单元。
这就是forever
的工作方式。另请注意,apache2
服务也使用Type=forking
。