啟動指令碼
os.startup_scripts 為產生的映像建立有上限的 systemd 一次性工作。每筆記錄宣告一條 shell 命令、所需套件、執行使用者和排序單元。
除非 run_as 另有說明,啟動指令碼都是具備 root 能力的程式碼。它們必須接受與任何安裝指令碼相同的審查。
規範形狀
{
"os": {
"startup_scripts": [
{
"name": "write-build-marker",
"description": "Create a local readiness marker after networking is available.",
"command": "set -Eeuo pipefail\ninstall -d -m 0755 /var/lib/example\nprintf '%s\\n' ready > /var/lib/example/build-ready",
"packages": [],
"run_as": "root",
"after": "network-online.target"
}
]
}
}欄位是 description 和 command,不是舊的 script 欄位。run_as 和 after 也使用 snake_case。after 是一個 systemd 單元字串,不是陣列。
模式最多接受 32 筆記錄和有上限的命令大小。校驗會拒絕空命令和 NUL 位元組,但不會讓 shell 內容變得安全或冪等。
為重試和部分失敗做設計
開機可能在部分副作用已經發生後被中斷。撰寫指令碼,使再次呼叫能安全完成,或以可檢查的明確狀態結束。
良好模式包括:
- 寫入暫存檔,驗證後再原子重新命名;
- 檢查使用者、目錄或設定項是否已經存在;
- 使用
install明確擁有者和模式; - 套用
set -Eeuo pipefail,並有意處理預期的非零結果; - 使用有上限的網路逾時和有限的重試次數; 以及
- 僅在所有必要步驟成功後寫入就緒標記。
不要把 sleep 當作就緒檢查。探測真正的相依性。
外部下載
避免 curl ... | sh。如果首次開機必須取得產物:
- 使用帶憑證驗證的 HTTPS;
- 固定期望的產物或來源版本;
- 在執行前驗證密碼摘要或已核准的簽章;
- 設定連線逾時和總逾時;
- 驗證失敗時以關閉失敗結束; 以及
- 避免記錄憑證或帶簽章的 URL。
若要真正離線或可重現,把經過審查的內容放進映像或已核准的套件儲存庫,而不是在首次開機時下載。
機密
切勿把明文憑證嵌入配方、命令、URL 或產生的標記。配方 JSON 和建置日誌會被保留為證據,並可能對操作員可見。使用已核准的部署時登錄或機密投遞機制,並把得到的憑證限定到目標。
執行身分
優先使用無特權服務帳戶。如果必須使用 root,把命令縮小到最小特權步驟,並設定明確的檔案擁有權。確認 run_as 指向在單元啟動之前已建立的帳戶。
驗證
測試結果,而不只是單元的結束狀態:
{
"type": "file_contains",
"description": "The startup unit wrote its readiness marker.",
"params": {
"path": "/var/lib/example/build-ready",
"content": "ready"
}
}還要測試第二次開機、不可用的相依性,以及從中斷的首次執行中復原。失敗時檢查 systemctl status 和單元日誌。