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

Dav*_*ave 19 startup boot logs centos services

我使用的是 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
Run Code Online (Sandbox Code Playgroud)

该文件指向此

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

forever start /home/rails/NodeJSserver/server.js
Run Code Online (Sandbox Code Playgroud)

我可以自己运行这个文件。但是当我尝试将它作为服务的一部分运行时,我注意到我的 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'.
Run Code Online (Sandbox Code Playgroud)

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

tel*_*coM 19

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

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

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

如何修复

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

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

[Service]
Type=forking
PIDFile=/absolute/path/to/nodejs.pid
User=rails
... <the rest as before>
Run Code Online (Sandbox Code Playgroud)

如果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
Run Code Online (Sandbox Code Playgroud)

您可以添加其他选项。

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

或者,如果您希望服务在返回某些特定退出状态值时重新启动,但考虑到它在其他情况下失败,那么也有一些选项。