Files
qinglong/docs/adr/ADR-0360-production-worker-kubernetes-session-lifecycle-evidence.md
T

5.7 KiB
Raw Blame History

ADR-0360Production Worker Kubernetes Session 生命周期实证门

  • 状态:Accepted
  • 日期:2026-08-11
  • 关联:QL-RFC-0001 D-272、ADR-0234、ADR-0235、ADR-0239、ADR-0241

上下文

ADR-0239 的第一版 K3s 门使用有界 shell actor 证明了 Secret/Deployment resourceVersion CAS、Recreate 顺序、PVC journal 延续与 identity generation,但它没有在 Kubernetes 中运行产品 Worker 进程,也不能证明 Cluster Worker ingress、mTLS、Session 心跳和 graceful drain 的组合行为。ADR-0235/0236 在 Docker/PostgreSQL 纵切面证明了产品 Session 与 Run,却没有覆盖 Kubernetes PID 1、Pod termination、init materialization、RWO PVC 和 Recreate 的真实边界。

首次把产品 Worker 镜像放入该门时,进程完成 register 并输出 active 后以 exit code 0 退出,Pod 进入 CrashLoopBackOff。根因不是 Session 或 KubernetesJavaScript pending Promise 本身不会保持 Node event loop;进程虽然等待 OS signal,却没有一个 ref'ed 生命周期句柄。这说明单元测试中主动投递 SIGTERM 不能替代真实容器 PID 1 证据。

决策

  1. runProductionWorkerProcess 在取得 signal authority 后必须持有一个低唤醒频率的 ref'ed lifecycle handle,直到成功 stop 或失败清理才释放。它不新增 watcher、listener、 网络连接或每任务 timer;最长 interval 只负责 process ownership,正常执行 cadence 仍由既有 product application 独占。
  2. qinglong/worker-kubernetes-rollout-live-contract@v2 保留第一阶段真实 CoreV1/AppsV1 CAS、四个审批计划、caller-driven executor Job、exact replay、Recreate journal 与 PVC 恢复证据;随后必须从当前源码构建 Cluster Admin、Cluster Control 和 Worker 三个镜像。
  3. 产品阶段在同一 K3s 内部署真实 Cluster Worker ingress 与真实 Worker。Control 使用 专用 ql3_worker_ingress PostgreSQL role、TLS 1.3 server identityWorker 使用独立 mTLS client identity、ql3w credential、无 ServiceAccount token、non-root/read-only root 和同一 RWO PVC。
  4. 门禁必须依次证明初始 Session、第四代 credential rollout 后的新 Session、client identity rollout 后的新 Session。每个 Session 都必须先有 durable online 和至少一条 heartbeat audit,替换或最终 scale-to-zero 后必须留下 draining、offline;三代 generation 严格递增。
  5. 证据只在显式 QL3_WORKER_KUBERNETES_ROLLOUT_LIVE=1 时运行。完整报告必须写入调用方 提供的绝对新路径,拒绝覆盖和 symlink parent,以 mode 0600 产生;stdout 只输出低敏 pass envelope。独立 auditor 必须使用 exact keys、精确计数、唯一 identity、全部 true gate、固定 limitation 和 secret-material scan 复核报告。
  6. K3s 固定为 rancher/k3s:v1.34.3-k3s1 index digestPostgreSQL 固定为 postgres:18.4-bookworm index digest。GitHub Actions 只允许手工触发,不进入默认 CI 不改变 Edge/Standalone artifact 或路由设备部署成本。

不采用方案

  • 在 CLI 末尾增加永久空循环:会绕过 application stop ownership,难以测试和释放; 生命周期句柄应由拥有 signal/drain 的 process application 管理。
  • CrashLoopBackOff 当成可接受重注册:会快速增加 Session generation,旧 Session 来不及 drain,并把成功退出伪装成健康容器。
  • 降低 heartbeat 断言或依赖时间碰巧经过:门禁必须逐 Session 等待 durable heartbeat 不能用 >=0 或最终总数推断每代存活。
  • 继续使用 shell actor 代表产品 Worker:它只能证明 Kubernetes 编排顺序,不能证明 production image、mTLS ingress、startup reconciliation 和 Session protocol。
  • 进入默认 CI 或 Edge 制品:真实 K3s、三个源码镜像与 PostgreSQL 是 Cluster 发布证据, 不是低配设备运行依赖。

结果

2026-08-11 arm64 真实门禁通过。报告使用 K3s v1.34.3+k3s1、锁定摘要的 PostgreSQL 18.4、当前源码构建的三类镜像和 53 版数据库 contract。四个 plan/approval/dispatch/ successful execution/credential/publication 与 16 条管理审计全部精确收敛;三个主机动作的 fresh execution + exact replay 共执行 9 次授权复验,独立 executor Job 使用一次 600 秒 projected token,重放不再请求 token。

生产 Worker 产生 3 个不同 Pod UID、3 个不同 Session ID 和严格递增 generation 1 → 2 → 3。每个 Session 都被观察到 online、draining、offline;最终有 3 条 register、 6 条 transition、3 条 heartbeat auditcredential 明文未进入 PostgreSQL。最终 drain 耗时 616 ms360 秒 termination grace 保持;所有 21 项具体 gate 为 true。

私有报告为 8,087 bytes、mode 0600SHA-256 cd59efd53abfaf18cb959b3381eb96651cea5327f7df9b68770e555c1b5d492c;独立审计器返回 findings=[]compatible=true,相关 K3s/PostgreSQL Docker container 零残留。

限制保持显式:单节点 local-path PVC 不是多节点 CSI detach/attach;强制删 Pod 不是物理 节点断电;产品阶段只证明 Session 生命周期,Remote Run 仍由独立 Worker PostgreSQL live gate 所有;确定性本地 strong-User ceremony 不是生产外部 IdP。

验证

mkdir -m 0700 /absolute/private/ql3-worker-evidence
QL3_WORKER_KUBERNETES_ROLLOUT_LIVE=1 \
QL3_KUBECTL_BIN=/absolute/path/to/kubectl \
pnpm test:worker-kubernetes-rollout-live:ql3 \
  --report=/absolute/private/ql3-worker-evidence/report.json

pnpm audit:worker-kubernetes-rollout-live:ql3 \
  --report=/absolute/private/ql3-worker-evidence/report.json

手工 CI workflow 为 .github/workflows/ql3-worker-kubernetes-rollout-live.yml