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 和单元日志。