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

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