systemd

最後更新: 2024-04-14 21:45:03 +0800 +0800
tags: Linux | Systemd
原文以英文撰寫。您正在閱讀AI翻譯版本。

systemd 是服務管理器,也是 Linux 系統管理元件套件。 系統管理器以 PID 1 執行;每位使用者的管理器則以 systemd --user 執行。 這兩類管理器都會載入單元、計算作業交易,並透過 Linux 控制群組監督處理程序群組。

單元、作業與生命週期狀態 #

單元代表管理器已知的資源。常見的單元類型如下:

後綴資源
.service處理程序或常駐程式
.socket用於啟用的 IPC 或網路通訊端
.target同步與分組節點
.mount、.automount、.swap儲存體設定
.device、.path、.timer以裝置或事件為基礎的啟用
.slice、.scopecgroup 組織與外部啟動的處理程序

作業是所要求的單元狀態變更,例如 start、stop 或 reload。啟動一個單元可能會帶入其他作業;管理器會將它們合併為一個交易,檢查排序循環與衝突作業,然後平行派送彼此獨立的工作。

單元狀態具有多個維度。LoadState 記錄定義是否已載入;ActiveState 回報 inactive、activating、active、deactivating 或 failed 等高階狀態;SubState 提供類型特定的詳細資訊。已載入的服務不一定正在執行,已 enable 的服務也不一定已載入或處於 active 狀態。enable 會變更開機或啟用連結;start 會建立執行階段作業。

sh
systemctl show sshd.service \
  --property=LoadState,ActiveState,SubState,UnitFileState
systemctl status sshd.service
systemctl list-jobs
systemctl --failed

需求相依性與排序相依性 #

需求邊決定哪些單元會進入交易:

  • Requires= 會帶入另一個單元,並傳播選定的 start 失敗或 stop;
  • Wants= 較弱,因為被要求的單元可能失敗,但要求方不一定會失敗;
  • Requisite= 要求另一個單元已經處於 active 狀態,否則會失敗;
  • BindsTo= 將活動狀態更緊密地繫結至可能消失的資源;
  • Conflicts= 會排程停止衝突的單元。

排序邊決定順序。After= 與 Before= 不會將另一個單元帶入交易,而 Requires= 或 Wants= 不會建立順序。若兩種關係都需要,請同時表達:

ini
[Unit]
Wants=network-online.target
After=network-online.target

關機時的排序評估方式不同:如果同一交易中,一個單元被排序在另一個單元之後且兩者都要停止,前者會先停止。

管理器會根據單元類型與設定加入隱含和預設相依性。例如,mount 單元會取得與父掛載點的關係,而許多 service 單元會取得相對於基本啟動和關機 target 的預設排序。generator 會在管理器啟動早期建立或修改單元定義;systemd-fstab-generator 會轉換 /etc/fstab,其他 generator 則處理核心命令列和相容性輸入。不要假設每條邊都會以字面形式出現在某個檔案中,應檢查計算後的圖:

sh
systemctl list-dependencies example.service
systemctl list-dependencies --reverse example.service
systemctl show example.service --property=Wants,Requires,Before,After
systemd-analyze critical-chain

探索、命名與覆寫 #

單元名稱會在後綴中編碼類型。從路徑衍生的名稱使用 systemd 跳脫:/var/lib 會變成 var-lib.mount,而 / 會變成 -.mount。worker@.service 這類範本名稱會建立 worker@blue.service 這類實例;%i 會展開為已跳脫的實例,%I 則展開為未跳脫的形式。

管理器會搜尋編譯時定義的單元載入路徑。/etc/systemd/system 中的管理員定義優先於通常安裝在 /usr/lib/systemd/system 或 /lib/systemd/system 下的供應商定義;暫時性和產生的目錄在相同搜尋順序中也有定義的位置。由於不同發行版可能有所差異,請查詢執行中的管理器:

sh
systemd-analyze unit-paths
systemd-analyze --user unit-paths
systemctl cat example.service
systemctl list-unit-files 'example*'

別名是另一個有效的單元名稱,可透過符號連結或 enable 時的 Alias= 實作。.wants/ 和 .requires/ 目錄會編碼相依性連結。WantedBy= 和 RequiredBy= 等 [Install] 設定會告訴 systemctl enable 要建立哪些連結;管理器在啟動單元時不會解讀 [Install]。

不要為了本機政策編輯已封裝的供應商檔案。請建立 drop-in:

sh
systemctl edit example.service
systemctl daemon-reload
systemctl restart example.service
systemd-delta

名稱為 *.conf 的 drop-in 會依字典順序合併。純量設定會取代較早的值,而清單設定可能累積,因此取代前可能需要先進行空指派:

ini
[Service]
ExecStart=
ExecStart=/usr/local/bin/example --foreground

systemctl revert 會移除為單元建立的本機覆寫。在重新啟動正式環境服務前,請使用 systemctl cat 檢閱合併後的定義。

服務追蹤與 cgroup #

systemd 會將服務處理程序置於單元 cgroup 中。即使經過 double-fork,後代處理程序仍會與服務保持關聯,因此 PID 檔案不是根本的追蹤機制。slice 會以階層方式組織服務與 scope cgroup;CPUWeight=、MemoryMax= 和 TasksMax= 等資源設定會透過主機上可用的核心 cgroup 控制器套用。

sh
systemctl status example.service
systemd-cgls
systemctl show example.service --property=ControlGroup,MainPID,TasksCurrent

Type=simple 將 ExecStart 處理程序視為主要處理程序,且不會等待 readiness 通訊協定。Type=exec 會等待執行成功。Type=notify 會等待實作通知通訊協定的服務傳送 READY=1。Type=forking 支援傳統的自行 daemon 化程式,而 Type=oneshot 會等待命令結束。請選擇符合該常駐程式的 readiness 契約;將某服務排序在 simple 服務之後,只能證明其處理程序已啟動。

target、開機與相容性 #

default.target 是正常的開機目標。核心的 systemd.unit= 引數可以為一次開機選取另一個 target;否則會使用已設定的預設值:

sh
systemctl get-default
systemctl set-default multi-user.target
systemctl isolate rescue.target

isolate 會停止 target 不需要的單元,並可能終止工作階段,因此從遠端使用前應檢查 target 相依性。emergency.target 和 rescue.target 提供受限的復原環境。

target 會將工作分組,但本身不會強制順序。因此,開機效能與失敗診斷會同時使用作業圖和時間戳記:

sh
systemd-analyze time
systemd-analyze blame
systemd-analyze critical-chain
journalctl -b -p warning

SysV 相容性取決於發行版。generator 可以將舊式 init 指令稿包裝為 service 單元,而 shutdown 等熟悉的命令也可能是指向 systemd 工具的連結。原生單元提供更精確的相依性、cgroup 追蹤、啟用與沙箱化;不要假設 init 指令稿會取得所有原生服務語意。

logind 與使用者管理器 #

systemd-logind 使用核心與使用者空間的裝置/工作階段資訊追蹤 seat、登入工作階段、使用者和 inhibitor lock。loginctl 可檢查這些狀態:

sh
loginctl list-sessions
loginctl session-status
loginctl user-status "$USER"

PAM 登入通常會啟動執行使用者管理器的 user@UID.service。使用者單元遵循獨立的載入路徑,並以 systemctl --user 控制。預設情況下,管理器的生命週期遵循登入政策。loginctl enable-linger USER 會要求在開機時啟動,並在最後一個工作階段結束後持續執行;請審慎使用,因為 lingering 使用者服務即使沒有互動式登入也會消耗資源。

系統管理器與使用者管理器具有分離的權限和匯流排。使用者服務不能僅藉由宣告單元選項取得系統管理器權限;除非這種耦合是刻意設計的,否則系統服務也不應依賴暫時的桌面工作階段。

作業檢查 #

請使用管理器自身的介面,而不要僅從檔案推斷狀態:

sh
systemctl list-units --all
systemctl list-unit-files
systemctl cat example.service
systemctl show example.service
systemd-analyze verify /etc/systemd/system/example.service
journalctl --unit=example.service --boot

在 systemctl edit 之外變更單元檔案後,執行 systemctl daemon-reload;此命令會重新解析定義,但不會重新啟動服務。請先驗證,再 reload,檢查合併後的單元,然後重新啟動或 reload 受影響範圍最小的單元。上游手冊 systemd.unit(5)、systemd.service(5)、systemd.special(7) 和 systemd.generator(7) 定義了主機上安裝版本的行為。

評論

在 GitHub 上閱讀或評論(發表評論需要登入)