feat(ql3): bind offline adopted target images

This commit is contained in:
whyour
2026-08-30 19:50:24 +08:00
parent 38d85952e7
commit 0f4b6b43fb
15 changed files with 345 additions and 23 deletions
+1
View File
@@ -32,6 +32,7 @@
| D-424 Console Secret-backed 自动化切片 | current-only metadata、强认证 AES-256-GCM create/rotate 与 Task pinned `SecretRef` 绑定已完成;真实 SQLite/loopback、本地与远端门、同源双架构 Console milestone 及离线 auditor 均通过 | Cluster 不复用 Local proof/custody;不提供明文读取、删除或历史浏览;仍不是正式发布或生产升级 |
| D-425 2.x 升级就绪盘点 | 同源 v6 Trial Kit 已交付 amd64/arm64 headless 阶段实物;canonical `upgrade-readiness.sh` 把 2.x root 只读挂载,在 128 MiB/无网络边界内由 exact Operator 生成 SQLite 与完整目录两个计划;artifact job 实跑、bundle auditor 与 milestone v3 均闭合 | 只完成 inspect,不授权 stage、activation、cutover 或 rollback;不是 Public Release |
| D-426a Side-by-side 暂存 | 同源 v7 Trial Kit 已交付 amd64/arm64 headless 阶段实物;reviewed-plan `upgrade-rehearsal.sh` 在新的私有 root 中执行 SQLite stage/verify/activation 与完整目录 stage/verifylegacy root 始终只读,summary 固定 `cutover=not_authorized`exact artifact job 实跑且 milestone v4 离线审计闭合 | 不执行 transform/apply、目标启动、cutover 或回退;仍不是 Public Release |
| D-426b1 离线 adopted target 权威 | 源码候选已支持 registry digest 与 Trial Kit local image ID 两类强绑定,并可生成 Application v4 + `docker-target.json`;正式 Compose catalog 权威未放宽 | 尚未生成新的双架构 artifacttransform/apply、真实 start/stop、clean `rollback_candidate` 等待 D-426b2 exact-bundle 门,当前不可称为阶段实物 |
D-421 已关闭 D-420 记录的“Web Task mutation 必须独立设计”缺口,而且没有改名复用 run `33173769047` 的旧 archive。修复提交 `dc1686bd6fb3505174dd9a14098ae5c2c92a1a7f` 的普通主 CI [run 33229592307](https://github.com/whyour/qinglong/actions/runs/33229592307) 为 41 success/3 expected artifact-finalizer skip/0 fail,同源 Kubernetes deployment [run 33229592293](https://github.com/whyour/qinglong/actions/runs/33229592293) 成功;随后显式 Local Console milestone [run 33230227006](https://github.com/whyour/qinglong/actions/runs/33230227006) 为 42 success/2 scope skip/0 fail。由此 Web 创建能力已进入新的阶段实物,而不再只是候选源码。
+38 -2
View File
@@ -222,7 +222,7 @@ D-64 全部完成,也不得自动重启 2.x。
### 2.3 Docker adopted target 启动与重启屏障
ADR-0310 已补齐上述段落中的 Docker target barrierADR-0313 又补齐 Docker `manual_required` 的实例级
lineage、只读诊断与双阶段新 ceremony 授权。写后回退仍未完成。target 容器必须由 operator 预先创建但保持停止,并满足:完整 ID、不可变 digest image
lineage、只读诊断与双阶段新 ceremony 授权。写后回退仍未完成。target 容器必须由 operator 预先创建但保持停止,并满足:完整 ID、受审核镜像引用和精确 Docker content ID
`restart=no`、read-only rootfs、非 privileged、`no-new-privileges`,以及能把宿主机 Application v3 config、
legacy commitment、activation 和 source 精确映射到 config 中路径的唯一读写 bind mount。自动重启策略
`unless-stopped`/`always` 会绕过每代 Legacy recheck,因此 adopted target 不允许使用。
@@ -245,12 +245,19 @@ legacy commitment、activation 和 source 精确映射到 config 中路径的唯
"instanceId": "router-edge-1",
"activationPath": "/opt/qinglong/private/qinglong3-activation.json",
"legacySourcePath": "/opt/qinglong/data/database.sqlite",
"targetDatabasePath": "/opt/qinglong/data/database.ql3.sqlite",
"recoveryPath": "/opt/qinglong/data/database.recovery.sqlite",
"manifestPath": "/opt/qinglong/private/qinglong3-adoption.json",
"expectedLegacyDatabasePath": "/ql/data/database.sqlite",
"expectedActivationDigest": "REPLACE_WITH_64_HEX_ACTIVATION_DIGEST",
"expectedLegacyCommitmentDigest": "REPLACE_WITH_64_HEX_COMMITMENT_DIGEST",
"expectedLegacyContainerId": "REPLACE_WITH_FULL_64_HEX_LEGACY_ID",
"expectedTargetContainerId": "REPLACE_WITH_FULL_64_HEX_TARGET_ID",
"expectedTargetImage": "registry.example/qinglong3@sha256:REPLACE_WITH_64_HEX_DIGEST",
"targetImage": {
"authority": "registry-digest",
"reference": "registry.example/qinglong3@sha256:REPLACE_WITH_64_HEX_DIGEST",
"imageId": "sha256:REPLACE_WITH_DOCKER_IMAGE_CONTENT_ID"
},
"applicationConfigPath": "/opt/qinglong3/local-application.json",
"expectedTargetApplicationConfigPath": "/var/lib/qinglong3/local-application.json",
"expectedTargetCommitmentPath": "/var/lib/qinglong3/service/cutovers/router-edge-1-ql3/0002-legacy-stopped.json",
@@ -266,6 +273,12 @@ ql3-local-deploy cutover-target-start \
--command-file /secure/operator/qinglong3-target-start.json
```
正式 registry 部署必须使用 `authority=registry-digest``reference` 仍只接受不可变
`name@sha256:...``imageId` 从创建目标容器的同一 Docker daemon 读取。下载型 Alpha Trial Kit
没有可诚实声称的 registry RepoDigest,必须改用 `authority=local-image-id`、bundle manifest 中的
本地 image reference 和 exact image ID。两种模式都会同时核对 `docker inspect`
`Config.Image``.Image`,不会把 mutable local tag 单独当作权威。
controller 先写固定的 `0003-target-start-decision.json`,其中状态为
`target_start_requested`,然后至多调用一次 `docker container start <exact-id>`。只有同一容器处于
running、identity/mount/config digest 不漂移,且 Application 写出一个校验通过的新 Linux startup receipt
@@ -299,6 +312,29 @@ Legacy container 必须再次证明与 `0002` 相同的完整 identity/source bi
generation60 条 target journal record),达到上限后必须进入新的受审 cutover/recovery ceremony,不能清理
旧记录腾位置。
### 2.3.1 离线 Docker adopted target descriptor
`local.deployment.adopted.prepare|verify` 的 service 现在可以显式选择:
```json
{
"kind": "docker-target",
"targetImage": {
"authority": "local-image-id",
"reference": "qinglong3-local-application:ci-amd64",
"imageId": "sha256:REPLACE_WITH_TRIAL_KIT_IMAGE_ID"
},
"allowRootService": false
}
```
它生成 `service/docker-target.json` 和同一份 Application v4 配置,固定 numeric UID:GID、
`restart=no`、无网络、read-only rootfs、drop ALL、no-new-privileges、Profile memory/PID 上限、
deployment root 可写 mount 与 legacy source 只读 mount。该 descriptor 是内容绑定的创建输入,
不是启动授权;operator 仍须先按 descriptor 创建并保持容器停止,再把容器完整 ID 和同一个
`targetImage` 交给 `target-start`。因此离线 Trial Kit 不需要伪造 GHCR catalog/release selection
正式 Compose 路径也不因 Alpha 便利性而放宽。
### 2.4 `manual_required` 诊断与双阶段新 Ceremony
每个实例的当前 cutover 由以下私有 CAS head 固定: