如何查明为什么我的 systemctl 服务没有在 CentOS 7 上启动?

如何查明为什么我的 systemctl 服务没有在 CentOS 7 上启动?

我使用的是 CentOS 7。如何找出服务无法启动的原因?我创建了这个服务

[rails@server ~]$ sudo cat /usr/lib/systemd/system/nodejs.service
[Unit]
Description=nodejs server

[Service]
User=rails
Group=rails
ExecStart=/home/rails/NodeJSserver/start.sh
ExecStop=/home/rails/NodeJSserver/stop.sh

[Install]
WantedBy=multi-user.target

该文件指出了这一点

[rails@server ~]$ cat /home/rails/NodeJSserver/start.sh
#!/bin/bash

forever start /home/rails/NodeJSserver/server.js

我可以自己运行这个文件。但是当我尝试将其作为服务的一部分运行时,我注意到我的 NodeJS 服务器没有启动。即使当我检查“sudo systemctl --state=failed”时,我也没有看到任何错误......

[rails@server ~]$ sudo systemctl enable NodeJSserver
[rails@server ~]$ sudo systemctl start NodeJSserver
[rails@server ~]$
[rails@server ~]$
[rails@server ~]$ forever list
info:    No forever processes running
[rails@server ~]$
[rails@server ~]$
[rails@server ~]$ sudo systemctl --state=failed
  UNIT                           LOAD   ACTIVE SUB    DESCRIPTION
● nginx.service                  loaded failed failed The nginx HTTP and reverse proxy server
● systemd-sysctl.service         loaded failed failed Apply Kernel Variables
● systemd-vconsole-setup.service loaded failed failed Setup Virtual Console

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

3 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

如何找出我的服务无法启动的原因?

答案1

Type=您的服务在该部分中没有指定[Service],因此systemd假设您的意思是Type=simple.

这意味着只要服务正在运行,systemd启动的进程就会继续运行。ExecStart=但看起来你start.sh只运行一个命令然后退出。那是命令foreverforever start作为守护进程启动目标命令,或者换句话说,在后台启动。命令完成后forever start,正在运行的 shellstart.sh将退出。

此时,systemd认为该服务失败。但是等等,分配给该服务的控制组中仍然有一个正在运行的进程。 “所以,”他想systemd,“它不仅失败了,而且还留下了烂摊子。不能这样。”由于没有KillMode=指定KillSignal=systemd因此继续使用默认值,并为该控制组中的任何剩余进程发送 SIGTERM,如果它们没有及时停止,则后续发送 SIGKILL。之后,你的实际 NodeJS 进程就会死掉,这是肯定的。

如何修复它

由于您运行的命令ExecStart=将在实际服务器启动后立即退出,因此您不能使用默认的Type=simple.您必须指定其他服务类型。

你可以使用Type=forking.对于这种类型,man systemd.service建议使用一个PIDFile=选项,因此如果您的 NodeJS 服务器为自己创建了一个 PID 文件(或者您向命令添加了选项forever以使其为其创建一个 PID 文件),您应该让systemd知道它将在哪里。

[Service]
Type=forking
PIDFile=/absolute/path/to/nodejs.pid
User=rails
... <the rest as before>

如果Type=forking不适合您,那么您可以Type=oneshot指定RemainAfterExit=yes

这使得在启动服务和停止服务时systemd只运行命令,而不关心其他任何事情。ExecStart=ExecStop=

systemd不过,仍会记住该服务上次设置为停止还是启动状态。因此,如果你设置另一个服务依赖于这个服务,然后手动停止你的 NodeJS 服务,另一个服务不会自动停止,并且在无法使用你的 NodeJS 服务时无疑会返回错误。


第三个选项是完全跳过该forever命令并让其systemd完成重新启动 NodeJS 进程的工作。在这种情况下,您的整个nodejs.service单位将是:

[Unit]
Description=nodejs server

[Service]
User=rails
Group=rails
ExecStart=/home/rails/NodeJSserver/server.js
Restart=always

[Install]
WantedBy=multi-user.target

您可以添加其他选项。

例如,您可以指定RestartSec=5在服务意外终止时尝试重新启动服务之前指定 5 秒的睡眠时间,以避免在服务因某种原因重新启动后立即终止时频繁尝试重新启动而占用系统资源。 (默认RestartSec=值为 100 毫秒。)

或者,如果您希望服务在返回某些特定退出状态值时重新启动,但认为它在其他退出状态值上失败,也有一些选项。

相关内容