Centos

我如何弄清楚為什麼我的 systemctl 服務沒有在 CentOS 7 上啟動?

  • May 8, 2018

我正在使用 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'.

如何找出我的服務無法啟動的原因?

您的服務在該部分中沒有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命令添加選項以使其為其創建一個),您應該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 毫秒。)

或者,如果您希望服務在返回某些特定退出狀態值時重新啟動,但認為它在其他情況下失敗,那麼也有相應的選項。

引用自:https://unix.stackexchange.com/questions/442575