5.2 KiB
ADR-0194:可重放的本机部署准备与 Supervisor 描述符
- 状态:Accepted(systemd、OpenRC、Compose 部署准备器与真实 fresh setup 已实现)
- 日期:2026-07-29
- 关联 RFC:QL-RFC-0001 D-05、D-06、D-40、D-62、D-175、D-183、 D-184
- 关联 ADR:ADR-0063、ADR-0066、ADR-0086、ADR-0088、ADR-0185、 ADR-0193
背景
ADR-0193 已关闭 fresh 数据库与常驻 application 的语义缺口,但操作员仍需手工创建 八个私有目录、复制两份 JSON、选择资源上限并自行拼接 supervisor 命令。手工步骤 容易产生宽权限目录、host/container 路径混用、可变镜像 tag、错误的停止信号或把 初始化命令误当成常驻进程。
直接在 CLI 中调用 systemctl enable、rc-update 或 docker compose up 又会引入
宿主机全局副作用。服务管理器调用没有与 SQLite mutation 相同的事务和精确重放
语义,也会迫使测试以 root 权限修改真实系统状态。
决策
1. 部署准备仍属于现有短生命周期 Owner CLI
@qinglong/local-owner-cli/local-deployment 与 ql3-local-deploy 负责部署文件
准备,不新增 workspace package。入口只接受:
ql3-local-deploy prepare --command-file /absolute/private-command.json
command file 继续复用 @qinglong/local-command-file 的 canonical、当前 UID、
0600、no-follow 协议。命令必须是 exact
local.deployment.prepare,固定 Profile、instance、deployment root、D-183
mutation identity 和三种 service 之一。
实现保留在同一个 package 中,并按 contract validation、文件发布事务、 descriptor rendering 与薄 orchestration 四个内部模块组织。内部模块不是独立 发布或依赖边界,避免为了文件数量继续拆 workspace package,也避免部署协议、 文件事务和 supervisor 模板重新堆积为单个巨型源文件。
2. 文件事务无覆盖且可恢复
准备器以当前 POSIX UID/GID 创建并复核固定的 0700 deployment、pepper、
backup、receipt、Artifact、Plugin staging/activation 与 service 目录。随后:
- 复用 D-183
executeLocalSetup收敛 migration 与 key authority; - 生成 exact
qinglong/local-application-process@v2fresh 配置; - 生成 systemd、OpenRC 或 Compose 中唯一一种描述符;
- 使用同目录 deterministic stage、完整写入、
fsync、hard-link no-replace、 directoryfsync和 stage cleanup 发布; - 已有目标只能在 owner、mode、link count、size 和完整字节全部一致时返回
existing,否则失败关闭。
在执行 setup 前先检查已有 config/descriptor 与遗留 stage;已存在内容漂移不会先 改变数据库或密钥。崩溃发生在 stage、link 或 cleanup 窗口时,同一命令可以继续 收敛;不得生成新 mutation ID 来重试。
3. 三种描述符是显式 Profile contract
systemd/OpenRC 只接受 canonical regular Node executable 与 application entrypoint;
文件必须由 root 或当前 UID 拥有且不能 group/world writable。描述符固定
SIGTERM、30 秒停止预算、0077 umask 和前台监督:
- Edge:128 MiB、64 PID、1024 fd;
- Standalone:256 MiB、256 PID、4096 fd。
Compose 只接受完整 @sha256 image reference,并固定:
- numeric current UID:GID;
- read-only root filesystem;
- bind mount 唯一 deployment root;
network_mode: none(fresh 默认 AI excluded);- drop all capabilities 与
no-new-privileges; - 16 MiB noexec tmpfs、30 秒停止预算及同一 Profile memory/PID 上限。
container application config 使用 /var/lib/qinglong3 内部路径;host setup 仍对
bind source 执行。两套路径不能混写。
若当前 UID 为 0,命令必须显式写
allowRootService: true;非 root 必须为 false。这只是明确风险,不把 root
执行宣传为推荐配置。
4. 准备不等于系统启用
准备器不执行以下行为:
- 不复制文件到
/etc; - 不调用 service manager 或 Docker daemon;
- 不拉取或构建镜像;
- 不签发、claim 或恢复 Owner;
- 不启用 AI、网络、Plugin online fetch;
- 不修改已存在的不同配置。
operator 必须检查 bundle,再显式安装和启动。发布镜像、系统包、签名、升级回滚与 真机 supervisor evidence 具有独立供应链和权限责任。
验收
- systemd fresh deployment 首次
prepared、原命令existing; - 八个目录均为当前 UID
0700,application/unit 为0600; - 真实 SQLite
integrity_check=ok; - OpenRC 使用
supervise-daemon、TERM/KILL 有界停止和0077; - Compose 使用 digest image、read-only、network none、cap-drop、no-new- privileges 与 Profile 上限;
- command widening、mutable tag、root 未确认、权限或内容漂移均拒绝;
- CLI stdout/stderr 不包含路径、image、digest、material、token 或 secret;
local-owner-clipackage test 全量通过。
未包含
- 正式可发布的本机 OCI image 与 SBOM/provenance/signature;
- deb/rpm/apk/opkg 等系统包;
systemctl、OpenRC、Compose 的真实安装/升级/回滚控制器;- systemd/OpenRC 多发行版、rootless container 与 Linux x64/arm64 live matrix;
- 路由器断电、ENOSPC、只读文件系统与闪存写放大报告。