我有一个简单的 systemd 服务单元来启动我的 Node.JS 网络服务器,但由于某种原因,它Restart=on-failure
无法工作并重新启动该过程。
这是我的服务单元文件(已删除专有名称):
[Unit]
Description=Node.JS web server
After=network.target
[Service]
User=villa
Environment=NODE_PATH=.
WorkingDirectory=/path/to/server/code
PermissionsStartOnly=true
ExecStart=/usr/local/bin/node server.js
ExecStop=/bin/killall node
Restart=on-failure
RestartSec=1
[Install]
WantedBy=multi-user.target
接下来,我先执行daemon-reload
,然后执行restart
该过程,然后像SIGKILL
这样终止它:
[root@localhost ~]# ps -ef | grep node
villa 24783 1 17 10:54 ? 00:00:00 /usr/local/bin/node server.js
root 25172 26051 0 10:54 pts/1 00:00:00 grep --color=auto node
[root@localhost ~]# kill -9 24783
[root@localhost ~]# sleep 2
[root@localhost ~]# ps -ef | grep node
root 29462 26051 0 10:55 pts/1 00:00:00 grep --color=auto node
正如你所见,即使等待更长比RestartSec
设置,该过程不会重新启动。
如上所述,终止进程后的状态如下:
[root@localhost ~]# systemctl -l status webserver.service
● webserver.service - Node.JS web server
Loaded: loaded (/etc/systemd/system/webserver.service; enabled; vendor preset: disabled)
Active: failed (Result: exit-code) since Wed 2017-05-03 10:54:53 EDT; 7min ago
Process: 27843 ExecStop=/bin/killall node (code=exited, status=1/FAILURE)
Process: 24783 ExecStart=/usr/local/bin/node server.js (code=killed, signal=KILL)
Main PID: 24783 (code=killed, signal=KILL)
May 03 10:54:31 localhost.localdomain node[24783]: <...web server's standard output, nothing abnormal at all...>
May 03 10:54:53 localhost.localdomain systemd[1]: webserver.service: main process exited, code=killed, status=9/KILL
May 03 10:54:53 localhost.localdomain systemd[1]: webserver.service: control process exited, code=exited status=1
May 03 10:54:53 localhost.localdomain systemd[1]: Unit webserver.service entered failed state.
May 03 10:54:53 localhost.localdomain systemd[1]: webserver.service failed.
奇怪的是,如果我使用完全相同的服务单元文件,但使用命令/usr/bin/sleep 1000
而不是node server.js
,则该sleep
进程会在我之后立即正确重新启动kill -9
。所以 Node.JS 一定出了什么问题。
关于为什么我的 Node 进程无法重新启动,您有什么想法吗?
答案1
事实证明,我的 systemd 服务单元文件始终是正确的(除了删除以下行ExecStop=
:标记已发布,这使得我的文件更多的正确)。我的问题是,我的服务单元文件位于 中/usr/lib/systemd/system
,不幸的是,另一个开发人员在没有告诉我的情况下将相同的文件(减去该Restart=
行)放在 中/etc/systemd/system
。
根据systemd.unit(5)
(man systemd.unit
):
单元文件从编译期间确定的一组路径加载,如下面的两个表格中所述。在前面列出的目录中找到的单元文件将覆盖列表中较低目录中的同名文件。
Table 1. Load path when running in system mode (--system). ┌────────────────────────┬─────────────────────────────┐ │Path │ Description │ ├────────────────────────┼─────────────────────────────┤ │/etc/systemd/system │ Local configuration │ ├────────────────────────┼─────────────────────────────┤ │/run/systemd/system │ Runtime units │ ├────────────────────────┼─────────────────────────────┤ │/usr/lib/systemd/system │ Units of installed packages │ └────────────────────────┴─────────────────────────────┘
简而言之,systemd 看到的文件中/etc/systemd/system
没有该Restart=
行前它看到的是我更新的文件,/usr/lib/systemd/system
其中确实有该Restart=
行。我只需删除过时的文件,我的问题就解决了。
答案2
从我读日志的方式来看,它可能因为而死亡ExecStop=/bin/killall node
,其被列为以“1 / FAILURE”状态退出。
看来这个killall
命令是以 root 身份运行的,因为PermissionsStartOnly=true
。ExecStop 命令似乎也没有必要。它很危险,因为它可能会终止与此单元无关的节点进程。以 root 身份运行,可能会产生意想不到的后果。
这也是不必要的,因为systemd
它会帮你停止 Node 应用。默认情况下,它会先向进程发送 SIGTERM。然后,如果它没有响应,稍后会发出 SIGKILL。
尝试移除你的ExecStop=
线路。