Skip to Content
Building Os啟動指令碼

啟動指令碼

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" } ] } }

欄位是 descriptioncommand,不是舊的 script 欄位。run_asafter 也使用 snake_case。after 是一個 systemd 單元字串,不是陣列。

模式最多接受 32 筆記錄和有上限的命令大小。校驗會拒絕空命令和 NUL 位元組,但不會讓 shell 內容變得安全或冪等。

為重試和部分失敗做設計

開機可能在部分副作用已經發生後被中斷。撰寫指令碼,使再次呼叫能安全完成,或以可檢查的明確狀態結束。

良好模式包括:

  • 寫入暫存檔,驗證後再原子重新命名;
  • 檢查使用者、目錄或設定項是否已經存在;
  • 使用 install 明確擁有者和模式;
  • 套用 set -Eeuo pipefail,並有意處理預期的非零結果;
  • 使用有上限的網路逾時和有限的重試次數; 以及
  • 僅在所有必要步驟成功後寫入就緒標記。

不要把 sleep 當作就緒檢查。探測真正的相依性。

外部下載

避免 curl ... | sh。如果首次開機必須取得產物:

  1. 使用帶憑證驗證的 HTTPS;
  2. 固定期望的產物或來源版本;
  3. 在執行前驗證密碼摘要或已核准的簽章;
  4. 設定連線逾時和總逾時;
  5. 驗證失敗時以關閉失敗結束; 以及
  6. 避免記錄憑證或帶簽章的 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 和單元日誌。