Mar*_*mou 4 systemd services node.js
在我提到我的问题之前,我已经检查了大部分与systemd相关的问题,但我找不到令人信服的答案。我编写了一个运行服务器的 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}`)
})
Run Code Online (Sandbox Code Playgroud)
最初,我创建了一个运行 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
Run Code Online (Sandbox Code Playgroud)
但是,我通过创建启动或停止服务的 .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
Run Code Online (Sandbox Code Playgroud)
我检查了日志文件/var/log/syslog
并journalctl
发现了错误,但我唯一能看到的是 systemd 连续启动和停止我的服务 5 秒。当我检查 using 时systemctl status helloWorld.service
,它说该服务具有成功状态,但是我找不到与我的 nodejs 应用程序相关的任何进程。
由于您没有指定服务类型,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=
选项来帮助 systemd 在停止服务时首先杀死主服务进程,或者一个合适的ExecStop=
,可以做一些比盲目杀死进程更友好的事情。
如果服务的控制组中没有进程,systemd
仍然会检测到服务已经失败。但是有Type=forking
和没有PIDFile=
,服务的主进程可能会死亡,只要至少有一个子进程仍然存在,故障就可能不会被检测到。
当ExecStop=
进程完成时,如果服务的进程组中还剩下任何进程,则systemd
认为这意味着由于某种原因有序关闭失败,并将立即用于SIGKILL
清理控制组中的剩余进程,除非使用各种选项另有说明systemd.kill(5)
手册页中列出。
因此,如果您使用Type=simple
,您将不需要 aPIDFile=
并且不必担心如果服务崩溃或整个系统给您留下陈旧的 PID 文件该怎么办。
如果您使用Type=forking
并且您的服务使用多个进程,您应该使用一个PIDFile=
以便systemd
可以正确识别您的服务的主进程,用于监视目的和在必要时杀死。
如果您的服务需要一个更复杂的关闭过程,而不仅仅是“将 a 发送SIGTERM
到它的主/唯一进程”,请ExecStop=
不管Type=
选项如何使用,但请注意它也需要处理任何必要的等待/超时;预期的结果是在进程结束时完成服务关闭ExecStop=
。如果在此之后服务的控制组中还有任何剩余进程,systemd
则将假定它们可以安全地被杀死并立即用于SIGKILL
清理它们。
归档时间: |
|
查看次数: |
1770 次 |
最近记录: |