
我有一個 systemd 單元檔案(serv_unit.service):
[Unit]
Description=My service
[Service]
Type=simple
Restart=always
RestartSec=60
StartLimitInterval=400
StartLimitBurst=3
ExecStart=/etc/init.d/myscript start
[Install]
WantedBy=multi-user.target
/etc/init.d/myscript
source /etc/myfile.sh # JAVA_home & other vars are resolved through this file
mode=$1
case "$mode" in
'start')
# Start daemon
daemon --user=abc $JAVA_HOME/bin/java -cp $appClassPath $MAIN_CLASS $args &
我面臨的問題是當我執行以下命令時:
systemctl start serv_unit.service
我沒有看到java進程。但是當我刪除尾隨&IE:
daemon --user=abc $JAVA_HOME/bin/java -cp $appClassPath $MAIN_CLASS $args
可以看到java進程(並且java進程沒有崩潰,因此排除了它在後台崩潰的可能性)
原因是什麼?
答案1
除了主要問題之外,從 systemd 呼叫 init.d 腳本有點多餘,而且通常從一開始就是一個壞主意。這就是您所需要的:
User=abc
EnvironmentFile=/etc/myfile.conf
ExecStart=/usr/bin/env $JAVA_HOME/bin/java -cp $appClassPath $MAIN_CLASS $args
EnvironmentFile 只能是普通的 KEY=value 分配,但如果設定必須採用 shell 腳本語法,您也可以使用:
User=abc
ExecStart=/bin/sh -c ". /etc/myfile.sh && exec $$JAVA_HOME/bin/java -cp $$appClassPath $$MAIN_CLASS $$args"
SyslogIdentifier=
(如果服務產生標準輸出訊息,您還應該在這兩種情況下進行設定。)
服務類型
Systemd 服務預計遵循特定規則。一個.service
單元只能有一個「主」守護程序,該Type=
選項告訴 systemd 該進程如何運作。
Type=simple
表示初始進程(即從 ExecStart= 啟動的進程)本身就是服務的主進程。一旦主進程退出,服務就被認為已經停止了,因此所有剩餘物都會被清理乾淨。
這意味著如果您使用 Type=simple,您就是在告訴 systemd 該守護進程將不會進入“背景”。事實上,你還告訴 systemdinit.d 腳本– 不是daemon
– 是服務的主要流程...
exec
因此,如果 init.d 腳本不僅不嘗試將實際的守護程序置於後台,而且還通過如下方式啟動它,那就最好了:
case "$mode" in
'start-foreground')
# Start daemon in foreground
exec daemon --user=abc $JAVA_HOME/bin/java -cp $appClassPath $MAIN_CLASS $args
另一方面,Type=forking
表示初始過程將要在啟動過程中 fork 並退出,並且應該從 PIDFile= 或啟發式發現主程序。
使用哪一個
使用具有以下功能的守護進程內建「守護程式」模式Type=forking
具有顯著的優勢:systemd 服務保持在「正在啟動」狀態,直到守護程式最終嘗試進入後台,此時它最終會移動到「已啟動/活動」狀態。這有助於配置依賴項,例如服務 A 可以聲明「After=B.service」。
但是,如果後台是透過外部方式完成的,例如 shell&
功能 – 沒有任何可以報告守護程序是否準備就緒的東西 – 那麼它就完全結束了無用你可能應該Type=simple
在沒有任何背景選項的情況下使用。