嵌入式的ubuntu系統(tǒng)如何寫好SysV Init腳本呢?與system服務又有什么差別呢?一起隨著文章來探究吧。
?問題背景
許多傳統(tǒng)Linux服務仍使用SysV Init腳本(/etc/init.d/),但在Systemd系統(tǒng)中,這些腳本需通過systemd-sysv-generator換為原生服務單元。若腳本未遵循Linux Standard Base (LSB)規(guī)范,會導致以下問題:
- 服務啟動/停止有誤:缺失關鍵命令(如status)或錯誤退出碼。
- 依賴混亂:未聲明依賴關系,導致服務啟動順序錯誤。
- 日志污染:輸出未重定向,干擾Systemd日志(journald)。
?SysV Init腳本規(guī)范指南
1. 必須支持的標準命令腳本需實現(xiàn)以下命令:
1.case"$1"in2.start)3.# 啟動服務邏輯4.;;5.stop)6.# 停止服務邏輯7.;;8.restart)9.# 建議直接調用自身stop再start,或委托給Systemd10.$0stop11.$0start12.;;13.status)14.# 返回服務運行狀態(tài)(必需?。?5.ifpidof -x"$DAEMON">/dev/null;then16.echo"Service is running"17.exit018.else19.echo"Service is stopped"20.exit3# LSB規(guī)范:未運行狀態(tài)碼21.fi22.;;23.*)24.echo"Usage:$0{start|stop|restart|status}"25.exit1esac
2. LSB頭部注釋(必需)在腳本開頭添加元數據:
1.### BEGIN INIT INFO2.# Provides: my_service3.# Required-Start: $network $syslog4.# Required-Stop: $network $syslog5.# Default-Start: 23456.# Default-Stop: 0167.# Short-Description: My Custom Service8.# Description: This service does something magical.
- Provides:服務名稱,需唯一。
- Required-Start/Stop:定義依賴的其他服務或設施如($network表示網絡就緒)。
3. 正確退出狀態(tài)碼退出碼含義
- 0 成功
- 1 泛型錯誤
- 2 無效命令參數
- 3 服務未運行(status命令專用)
- 4 權限不足
退出碼含義0成功1泛型錯誤2無效命令參數3服務未運行(status命令專用)4權限不足4. 避免破壞Systemd的特性Systemd 是一個進程生命周期管理器,它需要直接跟蹤服務的主進程(PID)。如果服務腳本不遵循規(guī)范,會導致Systemd無法正確管理服務狀態(tài)(如判斷是否運行、自動重啟等)。4.1 禁止后臺化進程4.1.1 錯誤寫法
# 傳統(tǒng)SysV腳本中常見的后臺化方式/usr/bin/my_daemon --config /etc/my.conf &
4.1.2 問題
- Systemd 會啟動腳本,但腳本中的 & 會讓 /usr/bin/my_daemon 在后臺運行。
- Systemd 只能監(jiān)控到腳本自身(即Shell進程)的狀態(tài),而無法追蹤真正的服務進程(my_daemon)。
- 當Shell腳本執(zhí)行完畢后,Systemd 會認為服務已退出,導致服務狀態(tài)顯示為 inactive (dead),即使my_daemon仍在運行。
4.1.3 正確寫法
# 使用 exec 替換當前進程(Shell腳本進程被替換為服務進程)exec/usr/bin/my_daemon --config /etc/my.conf
4.1.4 原理
- exec命令會讓當前Shell進程直接被替換為my_daemon進程。
- Systemd 可以追蹤到 my_daemon 的PID,從而正確管理服務狀態(tài)。
4.2 日志輸出規(guī)范4.2.1錯誤寫法
# 直接輸出到控制臺或文件echo"Starting service..."> /dev/console/usr/bin/my_daemon >> /var/log/my_service.log2>&1
4.2.2 問題
- Systemd 默認通過 journald 集中管理日志,直接寫入文件會導致日志分散,難以查詢。
- 若服務崩潰,Systemd 可能無法捕獲崩潰前的最后日志。
4.2.3 原理
- Systemd 會自動捕獲服務的stdout/stderr 并寫入 journald。
- 可通過journalctl -u my_service 查看完整日志,無需手動管理日志文件。
5. 注冊服務依賴SysV腳本需通過 LSB頭部注釋 聲明依賴關系,幫助Systemd理解服務啟動順序和條件。這是SysV與Systemd兼容的關鍵!5.1 LSB頭部詳解
### BEGIN INIT INFO#Provides: my_service# 服務名稱(唯一標識)#Required-Start:$network$syslog# 依賴的服務或系統(tǒng)設施#Required-Stop:$network$syslog# 停止時的依賴#Default-Start: 2345# 啟用服務的運行級別#Default-Stop: 016# 禁用服務的運行級別#Short-Description: My Service# 簡短描述#Description: Long description here.### END INIT INFO
5.1.1 關鍵字段Required-Start 服務啟動前必須就緒的依賴項,例如:
- $network 等待網絡就緒;
- $syslog 等待日志系統(tǒng)就緒;
- nginx 等待$network服務啟動;
- docker.socket 等待Docker套接字就緒;
- Default-Start/Default-Stop 定義服務在哪些運行級別自動啟動或停止;
- 2 3 4 5 多用戶模式(無圖形界面或圖形界面);
- 0 1 6 關機、單用戶模式、重啟。
5.2 依賴注冊命令5.2.1 目的將LSB頭部中的依賴關系轉換為系統(tǒng)實際的啟動鏈接(符號鏈接到 /etc/rcX.d/ 目錄)。
Debian/Ubuntu:# 生成依賴鏈接 sudoupdate-rc.d my_service defaults
# 移除依賴鏈接sudoupdate-rc.d my_service remove
5.3 依賴不注冊的后果假設 my_service 依賴網絡,但未聲明 $network:
- SysV場景:服務可能在網絡未就緒時啟動,導致連接失敗。
- Systemd場景:systemd-sysv-generator 無法生成正確的依賴關系,服務可能并行啟動,引發(fā)競態(tài)條件。
6. 總結
- 避免后臺化 → 讓Systemd直接跟蹤主進程。
- 規(guī)范日志輸出 → 信任Systemd的日志管理能力。
- 聲明依賴 → 通過LSB頭部告訴Systemd“誰先誰后”。
- 注冊服務 → 確保依賴關系生效,服務按預期啟動。
- SysV腳本的“四不像”問題本質是 對Systemd機制的不理解。遵循上述規(guī)范,可最大限度兼容Systemd,同時為未來遷移到原生Systemd服務鋪平道路。
?創(chuàng)建并啟用 SysV Init 腳本的完整流程
1. 創(chuàng)建 SysV Init 腳本的位置SysV Init 腳本必須放置在 /etc/init.d 目錄下,這是所有 SysV 風格服務腳本的標準位置。Systemd 的兼容層(systemd-sysv-generator)會自動掃描此目錄,將符合規(guī)范的腳本轉換為 Systemd 服務單元。
2. 創(chuàng)建腳本的步驟
2.1 創(chuàng)建腳本文件使用文本編輯器(如 nano)在/etc/init.d/下創(chuàng)建腳本文件:
sudo nano/etc/init.d/my_service
2.2 編寫腳本內容粘貼以下模板(需根據實際服務修改):
#!/bin/bash### BEGIN INIT INFO# Provides: my_service# Required-Start: $network $syslog# Required-Stop: $network $syslog# Default-Start: 2345# Default-Stop: 016# Short-Description: My Custom Service# Description: This service does something important.### END INIT INFO
# 服務主程序路徑DAEMON="/usr/bin/my_daemon"NAME="my_service"
case"$1"instart)echo"Starting$NAME"exec$DAEMON;;stop)echo"Stopping$NAME"killall -9$DAEMON;;restart)$0stop$0start;;status)ifpidof -x"$DAEMON">/dev/null;thenecho"$NAMEis running"exit0elseecho"$NAMEis stopped"exit3fi;;*)echo"Usage:$0{start|stop|restart|status}"exit1esac
exit0
3. 啟用服務的兩種方式3.1 傳統(tǒng) SysV 方法(兼容 Systemd)
# Debian/Ubuntusudoupdate-rc.d my_service defaults
3.2 Systemd 原生方法(推薦)
# 直接通過 Systemd 啟用(等效于 update-rc.d)sudo systemctlenablemy_serviceSystemd 會自動生成符號鏈接:Created symlink /etc/systemd/system/multi-user.target.wants/my_service.service → /lib/systemd/system/my_service.service.
4. 驗證腳本兼容性4.1 檢查 LSB 頭部合規(guī)性
# Debian/Ubuntusudoinsserv -n my_service
輸出應無錯誤,顯示依賴關系已解析。4.2 查看 Systemd 生成的單元文件
# 查看生成的 .service 文件systemctl cat my_service輸出示例:# /run/systemd/generator.late/my_service.service# Automatically generated by systemd-sysv-generator
[Unit]Documentation=man:systemd-sysv-generator(8)SourcePath=/etc/init.d/my_serviceDescription=My Custom ServiceAfter=network.target syslog.target
[Service]Type=forkingRestart=noTimeoutSec=5minIgnoreSIGPIPE=noKillMode=processGuessMainPID=noRemainAfterExit=yesExecStart=/etc/init.d/my_service startExecStop=/etc/init.d/my_service stopExecReload=/etc/init.d/my_service restart
5. 管理服務
# 啟動服務sudosystemctl start my_service
# 查看狀態(tài)systemctlstatus my_service
# 停止服務sudosystemctl stop my_service
# 重啟服務sudosystemctl restart my_service
6. 關鍵注意事項6.1 避免沖突配置如果服務已存在 Systemd 原生單元文件(如/lib/systemd/system/my_service.service),需刪除或禁用它,否則 SysV 腳本可能被忽略。6.2 禁用傳統(tǒng)服務干擾停止并禁用舊版networking服務(如果存在):
systemctl stop networkingsudo systemctldisablenetworking
6.3 日志輸出規(guī)范確保服務進程的日志輸出到 stdout/stderr,而非直接寫入文件。Systemd 會通過 journalctl 捕獲日志:
journalctl-u my_service -f
7. 總結步驟命令/操作目的創(chuàng)建腳本sudo nano /etc/init.d/my_service定義服務行為賦予執(zhí)行權限sudo chmod +x /etc/init.d/my_service確保腳本可執(zhí)行啟用服務sudo systemctl enable my_service設置開機自啟驗證 Systemd 兼容性systemctl cat my_service檢查自動生成的單元文件管理服務生命周期systemctl start/stop/restart my_service控制服務運行狀態(tài)通過遵循上述步驟,您可以在 Systemd 系統(tǒng)中安全地使用 SysV Init 腳本,同時享受 Systemd 的監(jiān)控和管理功能。但長期來看,仍建議遷移到原生 Systemd 服務單元(.service 文件),以充分利用資源控制、依賴管理和自動重啟等高級特性。
?EM系列儲能邊緣智能網關
EM系列儲能邊緣智能網關是ZLG致遠電子專為新能源儲能系統(tǒng)設計的一款高性能、多接口通訊管理設備,可在儲能系統(tǒng)應用中作為邊緣EMS(能源管理系統(tǒng))總控、通訊管理機、規(guī)約轉換器或BAU(電池管理總控)使用。該系列產品集成豐富的外設接口,支持各類BMS、PCS、空調、電表、屏顯等設備的通訊傳輸,且軟件上支持RT-Linux、Ubuntu等操作系統(tǒng),支持IEC-61850/IEC-104/EtherCAT等專用協(xié)議,可廣泛滿足各類儲能系統(tǒng)的本地能源管理應用需求。
-
嵌入式
+關注
關注
5177文章
20013瀏覽量
325830 -
腳本
+關注
關注
1文章
406瀏覽量
28997 -
Ubuntu系統(tǒng)
+關注
關注
0文章
93瀏覽量
4490
發(fā)布評論請先 登錄
Linux使用Systemd管理進程服務
如何在 Linux 上從 NetworkManager 切換為 systemd
腳本引擎編寫
現(xiàn)代 Linux 的五大初始化系統(tǒng)(1992-2015)
i.M8XMQ開發(fā)板如何通過Systemd服務實現(xiàn)應用自啟
Linux重啟命令介紹
怎樣寫一個shell腳本以實現(xiàn)Android7.1.2源碼的自動編譯呢
如何將imx8mpevk板的默認Systemd - Init Manager更改為Sysvinit?
走進Linux之systemd啟動過程
Linux項目開發(fā),你必須了解Systemd服務!
Systemd是什么?Systemd Service配置文件詳解
systemd journal收集日志的三種方式

【技術分享】正確編寫SysV Init腳本以實現(xiàn)Systemd兼容(上)
評論