Files
pikasTech-HWLAB/docs/reference/spec-v02-cicd.md
T
2026-05-31 15:05:29 +08:00

63 KiB
Raw Blame History

v0.2 CI/CD 规格

本文是 HWLAB v0.2 在 G14 上接入 CI/CD 的长期规格。目标是把 v0.2 作为独立加法 lane 接入现有 G14 k3s、Tekton、GitOps 和 Argo CD 体系,同时保持 G14 DEV/PROD 发布面稳定。

实施跟踪见 pikasTech/HWLAB#530,env 容器复用、三变量启动和 git mirror 加速设计见 pikasTech/HWLAB#572。原 docs/plan/hwlab-v02-namespace-cicd.md 阶段计划全文已迁入 #530 评论。本文只记录稳定规格、边界和判定标准;不要把一次性执行记录、排障流水账或临时证据写入本文。

在系统中的职责划分

v0.2 CI/CD 是 G14 上的加法 lanesource branch、GitOps branch、runtime namespace、artifact catalog、Argo Application、Tekton Pipeline 和 FRP 入口均独立于 DEV/PROD。它共享 G14 k3s、Tekton controller、Argo CD controller、本地 registry 和构建工具,但不能复用 DEV/PROD runtime path、namespace、Application 或公网端口作为 v02 发布证据。code-only fast lane 必须消费独立 devops-infra 集群提供的 git mirror/relay;该 mirror/relay 是跨项目 DevOps 基础设施,不属于 hwlab-v02 runtime namespace,也不改变当前 G14 registry 的部署位置或镜像引用真相。

内部架构

CI/CD 内部由 UniDesk 手动触发入口、PipelineRun、component planner、BuildKit publish、GitOps promotion、Argo sync、GitHub flush 和公网验收构成。v0.2 不设置 branch poller、control-plane reconciler 或其他 CronJobsource branch 只保存源码和人写配置;v0.2-gitops branch 保存 catalog 和 rendered runtime desired statelive runtime 是最终通过证据。

v0.2 的 GitOps 写路径采用真正写 mirrorpromotion 先把 v0.2-gitops 写入 devops-infra 本地 git mirror/relayArgo CD 从本地 mirror/relay 读取该 revision 并 rolloutCI 关键路径不等待 GitHub push。GitHub pikasTech/HWLAB 仍是长期源码与归档上游,但对 v0.2-gitops 来说是由 mirror/relay 负责 flush 的异步上游,不再是 promotion task 的同步写入目标。

API 接口说明

接口 说明
scripts/g14-gitops-render.mjs --lane v02 v02 GitOps render 入口,负责 namespace、runtime path、catalog 和 endpoint 固定。
Tekton hwlab-v02-ci-image-publish 构建 affected images、复用 unchanged digest,并 promotion 到 v0.2-gitops
devops-infra git mirror/relay 读写 v0.2 allowlist refsCI 读 source/catalog、写 v0.2-gitops,并通过手动 CLI flush 到 GitHub。
Argo argocd/hwlab-g14-v02 devops-infra 本地 mirror/relay 的 v0.2-gitops:deploy/gitops/g14/runtime-v02 同步到 hwlab-v02
http://74.48.78.17:19666/ v02 Cloud Web 公网入口。
http://74.48.78.17:19667/health/live v02 API/live 公网验收入口。

规格目标

  • v0.2 固定作为 G14 上的新增 CI/CD lane,不改写现有 G14 DEV/PROD lane。
  • v0.2 source branch 只保存源码、人写配置、模板、脚本和文档;CI/CD 生成物只进入 v0.2-gitops
  • hwlab-v02 是唯一 runtime namespace74.48.78.17:19666/19667 是唯一公网验收入口。
  • 共享 G14 k3s、Tekton controller、Argo CD controller、本地 registry、工具镜像和脚本库;隔离分支、catalog、runtime path、Application、Pipeline、ServiceAccount、SecretRef、PVC 和 FRP 入口。
  • 旧 DEV/D601/main 门禁不得进入 v0.2 发布调用链;新增检查只覆盖固定 branch、namespace、catalog、runtime path、GitOps branch、Argo destination 和公网入口这些硬边界。

固定命名

对象 v0.2 规格
Source branch v0.2
Source workspace G14:/root/hwlab-v02
GitOps branch v0.2-gitops
Artifact catalog v0.2-gitops:deploy/artifact-catalog.v02.json
Runtime path v0.2-gitops:deploy/gitops/g14/runtime-v02
Runtime namespace hwlab-v02
Tekton Pipeline hwlab-ci/hwlab-v02-ci-image-publish
Manual trigger UniDesk CLI bun scripts/cli.ts hwlab g14 control-plane trigger-current --lane v02 --confirm
Scheduler/CronJob 不创建、不保留 v02 CronJob;发布只由手动 CLI 创建 commit-pinned PipelineRun
Tekton ServiceAccount hwlab-ci/hwlab-v02-tekton-runner
PipelineRun prefix hwlab-v02-ci-poll-<short12>
Argo CD AppProject argocd/hwlab-v02
Argo CD Application argocd/hwlab-g14-v02
FRP Deployment hwlab-v02/hwlab-v02-frpc
Web entry http://74.48.78.17:19666/
API/live entry http://74.48.78.17:19667/health/live
Git mirror/relay 独立 devops-infra 集群读写服务;不设 CronJob;读 source/catalog,写 v0.2-gitops,按需由 UniDesk CLI 手动 sync/flush
Registry 维持当前 G14 hwlab-ci/hwlab-registry

scripts/g14-gitops-render.mjs --lane v02 是当前 v0.2 GitOps render 入口。该 lane 必须把默认 source branch 改为 v0.2、GitOps branch 改为 v0.2-gitops、catalog 改为 deploy/artifact-catalog.v02.json、runtime endpoint 改为 19667、web endpoint 改为 19666,并使用完整 source commit 作为 image tag。

真相源

v0.2 的发布真相按以下顺序判断:

  1. live runtimehwlab-v02 namespace 中 Deployment/StatefulSet template、Pod ready、事件、日志和 19666/19667 公网 health。
  2. Argo desired stateargocd/hwlab-g14-v02 的 revision、sync、health、source branch 和 runtime path。
  3. devops-infra mirror/relay 中的 GitOps branchv0.2-gitops 中的 deploy/artifact-catalog.v02.jsondeploy/gitops/g14/runtime-v02/**
  4. Tekton 执行证据:UniDesk trigger-current 返回的 PipelineRun、TaskRun result、gitops-promote 终态。
  5. GitHub 上游归档状态:mirror/relay flush 后的 origin/v0.2-gitopsorigin/v0.2
  6. 干净 source workspaceorigin/v0.2deploy/deploy.json、模板、render 脚本和 --no-write 输出。

旧 commit 记忆、G14/G14-gitops DEV/PROD 产物、D601 legacy 路径、GitHub 上游尚未 flush 的短暂落后、source branch 中历史 generated 文件和临时 worktree 只能作为线索,不能作为 v0.2 发布通过证据。

Source 与 GitOps 分层

v0.2 source branch 可以包含:

  • 源码、测试、文档、人写配置和模板。
  • deploy/deploy.json 或等价 lane 配置。
  • k8s 模板、render 脚本、CI/CD helper 和 catalog schema。

v0.2 source branch 不得跟踪:

  • deploy/artifact-catalog.v02.json
  • deploy/gitops/g14/runtime-v02/**
  • Tekton/Argo 的 rendered runtime desired state。
  • image digest、publish state、reuse evidence 或 CI 生成的 rollout metadata。

v0.2-gitops branch 必须包含:

  • deploy/artifact-catalog.v02.json,记录 image tag、digest、source commit、component identity、publish/reuse 状态。
  • deploy/gitops/g14/runtime-v02/**,作为 Argo CD 实际消费的 desired state。
  • 必要的 generated metadata,但不得包含 Secret 值。

首次初始化时,如果 v0.2-gitops:deploy/artifact-catalog.v02.json 尚不存在,只允许由 v0.2 lane 的正式初始化步骤创建第一版 catalog。不得 fallback 到 G14 source catalog、G14-gitops catalog、DEV runtime path 或 source branch 生成物。

CI/CD 链路

标准链路如下:

  1. UniDesk CLI hwlab g14 control-plane trigger-current --lane v02 --confirm 解析当前 origin/v0.2 完整 source commit SHA,先复核 devops-infra mirror 的 localV02 ref,必要时自动执行一次 bounded manual git-mirror sync Job,再创建 commit-pinned hwlab-v02-ci-poll-<short12> PipelineRun;默认 --dry-run 只返回将要创建的 manifest 和 mirror pre-sync 计划。
  2. prepare-source 通过 devops-infra mirror checkout v0.2 source,并从 mirror 中的 v0.2-gitops 读取上一版 deploy/artifact-catalog.v02.json
  3. CI/CD 校验只保留最小构建、TypeScript 语义检查、自动单元测试、打包和必要冒烟检查;旧 DEV/D601/main gate、运行时内部证明型校验、健康诊断重断言和历史预检不进入 lane。
  4. planner 根据 component input 判断 affected/reused services。
  5. affected service 通过 BuildKit 发布到 G14 本地 registryreused service 复用 catalog digest。 所有 selected service 的 build TaskRun 都只依赖 plan-artifacts,不按 service 串行排队,也不设置 8 并发或其他 Pipeline 级限流。 实际并发由 Tekton controller、G14 节点资源、PVC I/O、BuildKit sidecar 和本地 registry 承载能力决定。 hwlab-cloud-webhwlab-device-pod 必须使用 env-reuse-git-mirror-checkout。 只有 package/runtime/env 输入变化时才构建 <service>-env 镜像。 纯前端源码、Device Pod 源码或 boot code 变化只更新三变量和 GitOps desired state 不再重新构建业务镜像。
  6. promotion 刷新 deploy/artifact-catalog.v02.jsonrender deploy/gitops/g14/runtime-v02/**,只推送到 devops-infra mirror/relay 的 v0.2-gitops
  7. hwlab-g14-v02 从本地 mirror/relay 的 v0.2-gitops:deploy/gitops/g14/runtime-v02 同步到 hwlab-v02
  8. UniDesk CLI 或 mirror/relay flush 操作把本地 v0.2-gitops 推送到 GitHub canonical remoteflush 不在 CI runtime-ready 的关键路径内,但必须可查询 pending、lastFlushed 和 failure。
  9. 验收只观察 hwlab-v02 runtime 和 19666/19667

v0.2 可以复用 G14 的 registry、proxy、BuildKit、工具镜像和脚本库;不得复用 hwlab-g14-ci-image-publishhwlab-g14-branch-pollerhwlab-g14-control-plane-reconcilerG14-gitops runtime path 或 DEV/PROD Argo Application 作为 v0.2 发布入口。运行时不得为每个版本硬编码 namespace、catalog、runtime path 或健康判断;版本差异只通过 deploy.json.lanes[profile]、GitOps render 输入和实际 runtime 对象表达,新增版本不得新增运行时代码分支。

v0.2 不设自动轮询发布。历史上若存在 hwlab-v02-branch-pollerhwlab-v02-control-plane-reconciler 或等价 CronJob,均视为迁移残留,应由 UniDesk control-plane apply 清理;后续发布、重跑、暂停和恢复都通过手动 CLI 触发或停止创建新的 PipelineRun 完成,不新增替代 CronJob。

devops-infra git mirror/relay 同样不设周期 CronJob。标准触发命令 bun scripts/cli.ts hwlab g14 control-plane trigger-current --lane v02 --confirm 会在创建 PipelineRun 前按需同步 mirrorbun scripts/cli.ts hwlab g14 git-mirror sync --confirm 只作为显式 mirror 维护或诊断入口。promotion 成功后可执行 bun scripts/cli.ts hwlab g14 git-mirror flush --confirm 把本地 v0.2-gitops 推送到 GitHub。git-mirror apply 维护 mirror 的 PVC、读服务、写服务、同步/flush 脚本和旧 CronJob 清理;git-mirror sync 创建一次性 Job,只同步 allowlist refs v0.2v0.2-gitopsG14G14-gitops,先 fetch 到隐藏 staging refs,校验 commit/tree/object closure,再用 update-ref 发布到公开 refs。这样 mirror read path 与 GitOps write path 都落在本地磁盘和集群网络,同时避免 CI 看到 ref 已更新但对象还不可 checkout 的半发布窗口。

hwlab-cli 不属于 v0.2 CI/CD service matrix。它是 G14:/root/hwlab-v02 固定 repo 内的短连接源码 client,只用 Bun 直接调用 Cloud Web 同源 API;不得加入 PipelineRun services 参数、artifact catalog、BuildKit publish、runtime desired state、Deployment、Service、Job 或 image build。若出现 build-hwlab-cli TaskRun、hwlab-cli artifact service、CLI 镜像或 CLI 常驻服务,均视为旧门禁/旧断言残留,直接删除并回到 docs/reference/spec-v02-hwlab-cli.md 的短连接 client 口径。

rpt004:mvp:e2erunner:issue-visibility:preflightdev-base-image:preflight 不属于 v0.2 最小 CI/CD 校验入口;它们代表旧验收、旧 runner 可见性预检或旧镜像基础预检口径。v0.2 check/validate 不再引用这些任务,若它们重新进入默认 check plan、package script 或 PipelineRun,应直接删除该入口,而不是为其补兼容逻辑。

最小测试/校验机制

v0.2 最小校验的目标是拦截高确定性低级错误,不恢复旧重型门禁。hwlab-cloud-web 源码、模板或浏览器 bundle 输入发生变化时,CI 必须在镜像发布和 GitOps promotion 前执行 Cloud Web source check。该 check 至少包含实际 bundle 输入集合的 TypeScript 语义检查、自动发现的单元测试、bundle build 和 dist freshness 校验。

语法检查和 Bun build 不能证明浏览器运行路径安全。node --check 只解析语法,Bun.build() 只转译和打包,二者都可能放过 isRequestTraceEvent is not defined 这类未绑定标识符;因此 Cloud Web check 必须用实际参与 bundle 的 app.tsapp-device-pod.tsapp-conversation.tsapp-trace.tsapp-helpers.ts 生成同一入口并运行 TypeScript semantic check,例如 tsc --noEmit 或等价 Bun/TS checker。该检查失败时不得继续发布 hwlab-cloud-web 镜像。

Cloud Web 单元测试必须自动发现并执行 repo-owned web/hwlab-cloud-web/**/*.test.ts,不能只依赖手写文件清单。新增 app-trace、markdown、auth、status 或 device-pod 前端纯逻辑测试后,应天然进入 bun run --cwd web/hwlab-cloud-web check。trace 渲染核心路径必须有不依赖浏览器、Playwright、公网或真实 provider 的轻量单测,直接构造 runnerTrace.events 并调用 trace row/render helper,确保请求事件、setup 事件、tool command summary、assistant markdown 和 completion row 不会因未定义 helper 或数据形态漂移在浏览器运行时崩溃。

默认 v0.2 CI 不启动 Playwright、布局 smoke、移动端截图、旧 quick prompt 检查、旧 M3 evidence 检查或历史 DEV/D601 browser gate。这些检查只能作为显式人工诊断或专项验收命令存在,不能重新进入最小 CI/CD 关键路径。新增测试也必须只表达当前 v0.2 目标行为;发现旧 UI/旧路由/旧门禁断言阻碍当前目标时,删除旧断言而不是维护兼容分支。

写 mirror 的一致性模型是 local-first、manual-flush。promotion task 只能持有 mirror/relay 写凭证,不持有 GitHub deploy keyGitHub deploy key 只存在于 devops-infra mirror/relay sync/flush 边界。mirror/relay 必须在本地 receive 期间完成 object closure、目标 branch allowlist、non-fast-forward 拒绝和 changed-path 最小校验;receive 成功后本地 ref 即为 Argo 可消费事实。flush 失败不得回滚已经 rollout 的本地 GitOps revision,但必须保留 pending/outbox 状态,下一次手动 flush 可重试并输出 last error,不得静默丢弃。

性能预算与回归判定

v0.2 fast lane 的性能目标是让 code-only/env-reuse 场景主要受 G14 集群调度、PVC 和本地磁盘 I/O 限制,而不是受 GitHub 网络、重复依赖安装或无效 runtime 等待限制。性能预算只用于发现退化和指导排障,不新增发布门禁;发现退化时先按本节做现场热探测,再决定是否需要完整 CI/CD 复跑。

可见性优先于性能数字。 任何优化如果让触发阶段、mirror pre-sync、GitOps promotion、Argo refresh 或 runtime-ready 重新变成黑盒等待,即使总耗时暂时更短,也视为 P0 回归。 性能预算必须和日志契约一起判断:每个长等待都要能定位到具体阶段、目标 revision、等待对象和 pending/blocked 摘要。

代表性 env-reuse 场景的对比基线如下。后续更换 runner、PVC、Tekton controller、Argo repo server 或 mirror 存储后,必须重新测量并更新本表的预算口径。

场景 关键路径总耗时 主要阶段表现 判定口径
env-reuse + mirror-write 初始路径 约 108s prepare-source 约 56s;包含无效 npm ci 和多余探针;runtime wait 仍执行 只作为旧基线,不应回归。
移除 prepare-source 中的 npm ci 约 76s prepare-source 降到约 21s;其余路径仍有多余探针和 runtime wait 不应再恢复依赖安装。
剪裁 fast-path 探针 约 50s prepare-source 约 11sgitops-promote 约 7sruntime-ready 约 17s runtime 有实际变化时的合理预算。
P1 no-op runtime skip 约 37-40s 固定阶段预算见下文;runtime-ready 跳过 source-only 且 runtime identity-only 变化时的目标预算;当前代表性实测为 38s。

当前预算判定:source-only、所有 service 都复用 artifact、GitOps runtime 只发生 source identity 变化时,总耗时应接近 40s;超过 50s 需要先查是否误触发 runtime-ready、是否发生 GitHub 直连、是否恢复了 npm ci 或无效 preflight。真正需要 rollout 的 code-only 变更允许约 50s,因为 runtime-ready 必须等待 Argo 与 workload 收敛。涉及 BuildKit publish、env image rebuild、registry push 或真实 runtime 滚动时,不适用 40s 预算,应按 affected service 的 build 耗时单独测量。混合变更必须按 service 作用域裁剪:只改 package.jsonscripts、旧门禁入口、短连接 CLI、CLI 测试、非 runtime 文档或 device-pod host asset 时,不得触发无关 runtime service 全量 build;若同一变更确实同时改了 internal/cloud/**、device-pod code 和 skill bundle,则只允许对应 service build/rollout,其他 service 必须复用 catalog digest。

真实 rebuild 场景必须按全并行 fan-out 判定性能。 plan-artifacts 之后所有 affected service build task 应同时进入 Tekton 调度队列,collect-artifacts 只做 fan-in 等待全部 build task 写入 service report。 不得为了稳定表面耗时在 Pipeline 拓扑上重新串行化,也不得引入固定 8 并发上限。 全量 rebuild 的关键路径应接近最慢 service build 耗时加上 source、planning、collect、promotion 和 runtime-ready 固定开销,而不是所有 service build 耗时求和。 若全并行导致节点 CPU、内存、PVC I/O、BuildKit sidecar 或 registry 竞争,先通过 TaskRun duration、Pod scheduling、node pressure、registry latency 和 BuildKit 日志定位容量瓶颈。 除非已经证明控制面无法承载,否则不要把容量问题回退成 service 串行依赖。

关键阶段预算如下:

阶段 正常预算 退化信号
prepare-source 约 10-12s 超过 20s、出现 npm ci、访问 GitHub canonical remote、catalog fetch 超过数秒。
source-clone 约 1-2s 超过 5s 通常说明没有命中 devops-infra mirror 或 PVC/网络异常。
catalog-fetch 小于 1s 超过 3s 先查 mirror refs、object closure 和 catalog branch。
plan-artifacts 约 5-7s buildServicesrolloutServices 非空但本轮只改 CI/CD 文档/脚本时,先查 component input 与 catalog 是否加载。
collect-artifacts 约 6-8s 未输出运行时服务矩阵的 artifact_reuse 或全部 runtime services reuse 时,先查 catalog digest、PipelineRun services 参数和 service identityhwlab-cli 不应出现在 build/reuse 统计中。
gitops-promote no-op 约 7-9s 未输出 skipped-runtime-unchanged,或写入了 v0.2-gitops,说明 runtime 比对未命中。
runtime-ready no-op 应跳过;真实 rollout 约 15-20s no-op 场景出现 TaskRun 即为 P1 退化;真实 rollout 超时则按 Argo/workload 排障。

真实 rollout 若超过约 20s,先区分是 workload 本身启动慢,还是 runtime-ready 观察集合过大。正常日志应带 observedCount,且该值应接近本轮 rolloutServices 数量加上明确连带依赖;如果 workloadCount 很大但 observedCount 缺失,或 FRP、Postgres、device-pod 在无关 cloud-web/cloud-api 变更中重启,通常说明 render 把复用服务的 Pod template 绑定到了全局 source commit。修复方向是收窄 runtime-ready 观察集合,并把复用服务 template identity 改成 artifact commit、boot commit、config hash 或 migration hash,而不是加大 timeout 或恢复全 namespace 等待。

性能优化原理

prepare-source 不安装依赖。该 task 只负责 checkout source、读取上一版 catalog、输出 source identity 和基础文件,不运行 npm ci、不探测 npm registry、不做与后续 task 重复的工具链检查。需要依赖的语法检查、render test 或 build task 必须使用各自镜像内已有工具或在专属阶段处理,不能把全仓依赖安装塞回 source 准备阶段。

Git 读写都走 devops-infra 本地 mirror/relay。读路径用 HTTP mirror checkout v0.2 source 和 v0.2-gitops catalog;写路径把 promotion 推到 mirror/relay 的 v0.2-gitopsArgo 也从 mirror/relay 读取。这样 source clone、catalog fetch、GitOps clone/push 都落在集群内网络和本地磁盘,GitHub 只通过手动 sync/flush 进入或离开本地 mirror,不在 CI 关键路径内。

任何仍需要访问 GitHub canonical remote 的 SSH 操作都必须显式走 G14 proxy。Host SSH config 可以使用 OpenBSD nc -X connect -x 127.0.0.1:10808 %h %pTekton GIT_SSH_COMMAND、git-mirror sync/flush 和其他容器内 git@github.comssh://git@ssh.github.com:443 路径必须使用 repo-owned Node HTTP CONNECT ProxyCommand,并保留短 ConnectTimeoutServerAlive*。只改 HTTP_PROXY/HTTPS_PROXY 对 OpenSSH 无效;BusyBox nc 不支持 -X connect,不得再把 ssh.github.com:443 当作等价 proxy 或让 GitHub SSH 直连反复 60s 超时。

env image 复用把系统依赖和业务代码身份分离。environmentDigest 表示可复用运行环境,HWLAB_BOOT_REPOHWLAB_BOOT_COMMITHWLAB_BOOT_SH 表示本次代码启动身份。code-only 变更只更新 boot metadata 和 runtime identity,不发布新 env image;只有真实 env 输入变化或缺少可复用 env digest 时才进入 env rebuild。package.json 只按 dependency/runtime 字段参与 env/runtime hashscripts 只属于开发入口,不得因为清理旧门禁脚本而重建所有 service 或重建 env image。

BuildKit publish 采用 service 级全并行 fan-out。 每个 service build task 拥有独立 BuildKit sidecar、独立 service workdir 和独立 report 文件,均从同一 plan-artifacts 结果判断是否需要执行。 跳过的 task 由 Tekton when 表达式裁剪,执行的 task 并行写入 /workspace/source/service-results/<serviceId>.jsoncollect-artifacts 只从 report 目录收敛结果,不再通过 tasks.build-*.results 直接依赖某个前序 task 输出,因此全并行不会改变 artifact 身份语义。

全并行不是无限资源承诺,而是 DAG 不主动限流。 CI/CD 拓扑只表达依赖:prepare-source 输出 source/catalog,轻量检查并行完成后进入 plan-artifacts。 所有被选中的 build-* task 只依赖 plan-artifacts,最后由 collect-artifacts fan-in。 实际同一时刻运行的 Pod 数由 Tekton controller、Kubernetes scheduler、G14 node 资源、PVC I/O、BuildKit sidecar 和本地 registry 共同决定。 如果这些节点因为容量不足自然排队,可以接受真实并发低于 selected service 数。 不允许为了掩盖排队把 Pipeline YAML 改回服务串行链或固定并发上限。

限制全并行的关键节点如下:

  • Tekton controller 与 Kubernetes API 负责把 selected build task 展开成 TaskRun/Pod。 控制面慢会让 TaskRun 创建或状态更新延迟;退化信号是 plan-artifacts 已完成但 build TaskRun 创建时间分散。
  • Kubernetes scheduler 与 G14 node 决定 Pod 是否能同时落到节点。 CPU、内存、ephemeral storage 和 image pull 会限制实际并行度;退化信号是 Pod PendingUnschedulableOOMKilledEvicted 或 node pressure event 增多。
  • shared workspace PVC 与本地磁盘承载 source 读取、service workdir 复制、report 写入和 BuildKit 层数据。 退化信号是 build step 开始慢、cp/tar/workspace 操作耗时异常、Pod I/O wait 高或 PVC/local-path event。
  • 每个 TaskRun 的 BuildKit sidecar 独立运行,但同时消耗 CPU、内存、overlayfs、socket readiness 和 layer cache I/O。 退化信号是 buildkitd 启动慢、socket unavailable、build context upload 慢、sidecar OOM 或 build step 等待 daemon。
  • hwlab-ci 本地 registry 是全并行 rebuild 后半段的共享写点,承载所有 affected service 的 layer 和 manifest push。 退化信号是 push 耗时拉长、连接 reset、5xx、blob upload timeout 或 registry Pod CPU/I/O 压力。
  • devops-infra git mirror/relay 影响 prepare-source、catalog fetch 和 gitops-promote 的固定开销。 它通常不在 build fan-out 中;退化信号是 clone/catalog 超过预算、promotion push 慢或 mirror pending/outbox 堆积。

并发回归的高风险修改必须提前识别。 build-* task 之间新增 runAfter 会把关键路径改成服务耗时求和。 把所有 build 写到同一个 report 或共享 workdir 会产生覆盖和竞态。 直接依赖 tasks.build-*.results 会让 skipped task 的结果解析变脆。 在 build task 内修改 /workspace/source/repo 会污染其他并发 task 的输入。 对不同 service 复用同一 image repo/tag 会造成 registry tag 覆盖。 把容量抖动误判为拓扑问题会导致重新串行化。 正确做法是保持 source tree 只读、每个 service 独立 workdir 和 report、每个 service 独立 image repo。 先按容量节点定位真实瓶颈,再决定是否增加资源或修 sidecar/registry/mirror。

planner 必须按 service component model 裁剪 build。tools/ 下的短连接 CLI 源码不是 runtime service 输入;skills/ 只有 agent runtime 或 skills bundle 真正消费的子目录才影响对应 runtimedevice-pod host CLI asset 属于 skills bundle 或 host 侧分发输入,不得让 cloud-api、agent-worker、gateway、edge-proxy 等服务重建。CI 读取 artifact catalog 时支持 repo 相对路径和绝对路径,便于用真实 catalog 做本地热探测;catalog 缺失才允许 fail closed 到 rebuild,不得把“诊断命令没读到 catalog”误判为生产路径必须全量构建。

P1 no-op runtime skip 只跳过无实际 runtime 变化的等待。planner 输出 buildServices=[]rolloutServices=[] 后,gitops-promote 会在写入前对旧 runtime-v02 与新 render 结果做归一化比较:忽略 source commit、artifact source commit、boot commit 和等价 commit env/annotation 这类 identity-only 字段。如果归一化结果相同,promotion 输出 skipped-runtime-unchanged,把 Tekton result runtime-ready-required=false 写出,并跳过 GitOps commit、push、Argo hard refresh 和 runtime-ready。如果 workload spec、image digest、env image、SecretRef、Service、Ingress、FRP、ConfigMap 或 rollout service 有实际变化,必须保持 runtime-ready-required=true 并等待 runtime 收敛。

runtime-ready 只能观察本轮 rolloutServices 对应的 workload readiness,不能把整个 hwlab-v02 namespace 的全量 workload 都绑定到当前 source commit 后等待。复用 service 的 Deployment metadata 可以记录本次 source commit 作为 GitOps revision 线索,但 Pod template identity 必须来自该 service 的 artifact/runtime commit、boot commit 或配置内容 hash;否则 catalog 复用会被误转成不必要 rollout,runtime-ready 会被无关服务拖慢。hwlab-cloud-api 的 rollout 允许连带观察 hwlab-deepseek-proxy,因为 deepseek bridge 复用 cloud-api 镜像作为运行载体;其他连带关系必须有明确运行依赖后再加入观察集合。基础对象如 FRP、Postgres 的 Pod template 不得写入全局 source commit,应用配置 hash 或 migration hash 表达真实重启边界。

runtime-ready 的可见性优先级高于耗时优化。Task 启动后必须立即输出 runtime-ready started 事件,明确 readinessMode、观察服务数和当前 revision;等待 Argo、source commit refresh 或 workload ready 时必须周期性输出 progress 事件,包含 observedCountworkloadCount、pending/blocked 摘要或 Argo sync/health 状态。service rollout 场景继续用 rolloutServices 对应的 Pod template source commit 判定;rolloutServices=[] 但 GitOps runtime 真实变化的 infra-only 场景不得黑盒等待 source commit,应改为等待 Argo Application Synced/Healthy 和 workload generation ready,并输出 argo-sync-health 事件。禁止再出现 runtime-ready 只在 240s timeout 后才输出一条日志的不可观察状态。

触发侧也必须可见。 hwlab g14 control-plane trigger-current --lane v02 --confirm 默认作为异步 job 返回 job.idstatusCommand、stdout/stderr 路径。 同步调试使用 --wait 时,stderr 必须输出 hwlab.v02.trigger.progress JSON 事件。 事件至少覆盖 control-plane-refreshgit-mirror-pre-syncdelete-existing-pipelineruncreate-pipelinerun。 每个阶段都要有 startedsucceededfailed,并携带足够定位的信息,例如 mirror sync job、mode、PipelineRun name 或耗时。 异步 job 的 stderr tail 也必须能看到同一类进度事件。 如果 trigger 卡住但只有一条启动命令或空日志,应先修 UniDesk CLI 可见性,不要把问题推给 Tekton 或反复重跑 Pipeline。

Pipeline 内部的 no-op fast lane 必须形成完整证据链。 prepare-source 输出 source-clonecatalog-fetch timing。 plan-artifacts 输出 g14-ci-plan,其中 buildServices=[]rolloutServices=[] 且 runtime service 全部 reuse。 gitops-promote 输出 skipped-runtime-unchangedruntime-identity-only,并把 gitops-commitgitops-push 标为 skipped。 PipelineRun 的 skipped tasks 中必须包含 runtime-ready。 这条证据链缺一项时,不能只看总耗时通过,应先确认是日志缺失、planner 误判还是 GitOps runtime 比对退化。

真实 rollout 的 runtime-ready 必须 fail-closed 且可观察。 service rollout 只能等待本轮 rolloutServices 对应 workload 的 Pod template source commit 与 readiness。 infra-only runtime change 只能等待 Argo Application Synced/Healthy 和 workload generation ready。 若 runtime-ready 超时但日志里没有 startedprogressargo-refreshargo-sync-healthworkload-readyobservedCount,先按可见性回归修复日志和观察集合。 再讨论 timeout、性能或容量问题。

Kubernetes label 里的配置 hash 必须使用短 hash,完整 64 位 sha256 只能放 annotation。FRP config-sha256、Postgres migration-sha256 这类字段如果进入 Pod template label,长度必须小于 Kubernetes label value 的 63 字节上限;annotation 保留完整 hash 用于排障和人工比对。Argo sync 报 must be no more than 63 bytes 时,优先检查是否把完整 sha256 写入 label,不要通过删除 hash、放宽 sync 或忽略 OutOfSync 绕过。

快速优化不能绕过 fail-closed 语义。mirror miss、commit ancestry 不合法、boot script 缺失、digest 缺失、Argo observer RBAC 不足、workload 未 ready 或公网 health 不一致,都不能为了追求耗时而降级为 warning。允许跳过的只有已经证明 runtime desired state 没有实际变化的等待。

快速排障

触发后先看异步 job 状态,确认卡点在 UniDesk trigger、mirror pre-sync、PipelineRun 创建,还是 Tekton 内部阶段。 正常触发日志应出现 hwlab.v02.trigger.progress 事件,且阶段至少包括 control-plane-refreshgit-mirror-pre-syncdelete-existing-pipelineruncreate-pipelinerun

bun scripts/cli.ts job status <trigger-job-id> --tail-bytes 30000

如果 trigger job stderr 没有进度事件,不要直接反复触发 CI/CD。 先修 trigger 可见性或查询 .state/jobs/<jobId>.stderr.log,让等待点重新暴露出来。 mirror pre-sync 慢时看 mirror sync job 与 git-mirror statusPipelineRun 创建后才进入 Tekton 排障。

先看一次 PipelineRun 总览,确认是否是性能退化、构建退化还是 runtime 收敛失败:

bun scripts/cli.ts ssh G14:k3s script -- 'set -eu
ns=hwlab-ci
pr=<pipeline-run-name>
kubectl get pipelinerun -n "$ns" "$pr" \
  -o jsonpath="status={.status.conditions[0].status}{\"\\n\"}reason={.status.conditions[0].reason}{\"\\n\"}message={.status.conditions[0].message}{\"\\n\"}start={.status.startTime}{\"\\n\"}done={.status.completionTime}{\"\\n\"}"
echo taskruns
kubectl get taskrun -n "$ns" -l tekton.dev/pipelineRun="$pr" \
  -o jsonpath="{range .items[*]}{.metadata.name}{\"\\t\"}{.metadata.labels.tekton\\.dev/pipelineTask}{\"\\t\"}{.status.conditions[0].status}{\"\\t\"}{.status.conditions[0].reason}{\"\\t\"}{.status.startTime}{\"\\t\"}{.status.completionTime}{\"\\n\"}{end}" | sort -k2,2
echo skipped
kubectl get pipelinerun -n "$ns" "$pr" \
  -o jsonpath="{range .status.skippedTasks[*]}{.name}{\"\\n\"}{end}" | sort
'

再抓关键日志。正常 no-op fast lane 应看到 source-clone 约 1-2s、catalog-fetch 小于 1s、所有 runtime services reuse、skipped-runtime-unchangedgitops-commitgitops-pushskipped,并且 runtime-ready 出现在 skipped tasks 中。输出中不应出现 build-hwlab-cli

bun scripts/cli.ts ssh G14:k3s script -- 'set -eu
ns=hwlab-ci
pr=<pipeline-run-name>
for task in prepare-source plan-artifacts collect-artifacts gitops-promote runtime-ready; do
  tr=$(kubectl get taskrun -n "$ns" \
    -l tekton.dev/pipelineRun="$pr",tekton.dev/pipelineTask="$task" \
    -o jsonpath="{.items[0].metadata.name}" 2>/dev/null || true)
  [ -n "$tr" ] || { echo "--- $task skipped/no-taskrun ---"; continue; }
  pod=$(kubectl get pod -n "$ns" -l tekton.dev/taskRun="$tr" \
    -o jsonpath="{.items[0].metadata.name}")
  echo "--- $task $pod selected logs ---"
  pattern="skipped-runtime-unchanged|runtime-ready-required|runtime-identity-only"
  pattern="$pattern|g14-cicd-timing|git-operation|g14-ci-plan|artifact_reuse|buildSkippedCount"
  pattern="$pattern|gitops-commit|gitops-push|runtime-ready|progress|argo-refresh"
  pattern="$pattern|argo-sync-health|workload-ready|observedCount"
  kubectl logs -n "$ns" "$pod" --all-containers=true | \
    grep -E "$pattern" || true
done
'

常见故障按以下顺序处理:

现象 优先检查 处理原则
prepare-source 回到 20s 以上 日志是否出现 npm ci、npm registry probe、GitHub URL、SSH setup 或长时间 catalog fetch 拆掉无效依赖安装和重复探针;读路径必须回到 mirror。
source-clone 超过 5s PipelineRun 参数 git-read-url、mirror service、PVC I/O、git-mirror status 不要改回 GitHub 直连;先修 mirror/read service。
catalog 缺失导致全量 build prepare-source 是否从 v0.2-gitops 取到 deploy/artifact-catalog.v02.json git-mirror sync --confirm;必要时查 mirror refs/object closure。
buildSkippedCount 偏低或突然变成 0 g14-ci-planaffectedServicesbuildServicesrolloutServices、catalog 加载状态、package.json 字段 diff 和 service component path 真实业务变更可以 build;脚本清理、CLI/测试/文档、host asset 或 code-only env-reuse 变更不应误触发全量 build。
多 service rebuild 仍串行执行 tekton-v02/pipeline.yaml 中所有 build-* task 的 runAfter,以及 TaskRun startTime 是否都紧跟 plan-artifacts build task 只能依赖 plan-artifacts;发现 build-B 依赖 build-A 时直接修 render 脚本和生成物,不保留串行兼容路径。
全并行 rebuild 变慢或不稳定 TaskRun duration、Pod Pending/Unschedulable、node pressure、PVC I/O、BuildKit sidecar 日志、本地 registry push latency 优先定位资源容量或 registry/BuildKit 瓶颈;不要先把 Pipeline 拓扑改回串行或固定 8 并发。
no-op 仍执行 runtime-ready gitops-promote 是否输出 runtime-ready-required=falseskipped-runtime-unchanged 查 runtime 归一化比较;不要直接删除 runtime-ready,只修 no-op 判定。
trigger 或 mirror pre-sync 黑盒等待 job status <trigger-job-id> stderr 是否输出 hwlab.v02.trigger.progress 先恢复 trigger 进度事件;不要重复触发或手工创建 PipelineRun 绕过。
runtime-ready timeout 后才输出一条日志 是否缺少 startedprogressworkload-readyobservedCount 这是可见性回归;先修日志和观察集合,不要先加大 timeout。
mirror pendingFlush=true 长期存在 bun scripts/cli.ts hwlab g14 git-mirror status 和最近一次 flush 错误 手动 git-mirror flush --confirmflush 不影响已 rollout 本地 revision,但不能静默积压。
Argo Synced/Healthy 但公网不通 hwlab-v02-frpc 日志、master frps allowlist、19666/19667 修 FRP allowlist 或 frpc;不要把 DEV/PROD 入口当作 v02 证据。
runtime-ready 超时 Argo app revision、workload Pod template source commit、Pod events、observer RBAC 真实 rollout 必须 fail closed;先定位 Argo 或 workload,不要降低等待为 warning。

全并行故障定位先判定是拓扑退化、调度排队、资源压力还是共享写点瓶颈。 不要用一次 PipelineRun 总耗时直接得出“并发失败”结论。 必须同时看 plan-artifacts 完成时间、每个 build TaskRun 创建时间、Pod startTime、container finishTime 和 build/push 日志。

检查 live Pipeline DAG,确认所有 build task 没有互相依赖:

bun scripts/cli.ts ssh G14:k3s script -- 'set -eu
ns=hwlab-ci
pipeline=hwlab-v02-ci-image-publish
kubectl get pipeline -n "$ns" "$pipeline" \
  -o jsonpath="{range .spec.tasks[*]}{.name}{\"\\t\"}{.runAfter}{\"\\n\"}{end}" | \
  grep "^build-"
'

检查一次 PipelineRun 的真实并发时间线:

bun scripts/cli.ts ssh G14:k3s script -- 'set -eu
ns=hwlab-ci
pr=<pipeline-run-name>
kubectl get taskrun -n "$ns" -l tekton.dev/pipelineRun="$pr" \
  -o custom-columns=START:.status.startTime,DONE:.status.completionTime,\
STATUS:.status.conditions[0].status,REASON:.status.conditions[0].reason,\
TASK:.metadata.labels.tekton\\.dev/pipelineTask,NAME:.metadata.name \
  --no-headers | \
  grep -E "build-|plan-artifacts" | sort
'

检查调度和节点压力:

bun scripts/cli.ts ssh G14:k3s script -- 'set -eu
ns=hwlab-ci
pr=<pipeline-run-name>
kubectl get pod -n "$ns" -l tekton.dev/pipelineRun="$pr" -o wide
kubectl get events -n "$ns" --sort-by=.lastTimestamp | tail -80
kubectl describe node | grep -E "Name:|Pressure|Allocatable|Allocated resources|cpu|memory|ephemeral-storage" || true
'

检查 BuildKit 和 registry 共享写点。 先用 TaskRun 找到对应 Pod,再分别看 build step、BuildKit sidecar 和 registry Pod 日志。 如果 build step 卡在 push 或 sidecar 等待,优先处理 registry/BuildKit/PVC,而不是修改 Pipeline 并发拓扑。

bun scripts/cli.ts ssh G14:k3s script -- 'set -eu
ns=hwlab-ci
pr=<pipeline-run-name>
task=<build-task-name>
tr=$(kubectl get taskrun -n "$ns" \
  -l tekton.dev/pipelineRun="$pr",tekton.dev/pipelineTask="$task" \
  -o jsonpath="{.items[0].metadata.name}")
pod=$(kubectl get pod -n "$ns" -l tekton.dev/taskRun="$tr" \
  -o jsonpath="{.items[0].metadata.name}")
kubectl logs -n "$ns" "$pod" --all-containers=true | \
  grep -E "buildkit|daemon|socket|push|manifest|blob|timeout|reset|no space|OOM|killed" || true
kubectl get pod -n "$ns" -o name | grep -E "registry|hwlab-registry" || true
'

并发相关故障按下表归类,避免把不同问题混成“并行不稳定”:

故障类型 判定信号 修复方向
拓扑退化 build TaskRun 的 runAfter 出现其他 build taskstartTime 严格一个接一个且没有 Pod Pending 证据。 修 render 和 live Pipeline,恢复 build task 只依赖 plan-artifacts
控制面或调度排队 plan-artifacts 完成后 TaskRun/Pod 创建分散,event 出现调度等待。 查 Tekton controller、scheduler、API latency 和 node 可用资源。
节点资源压力 Pod PendingOOMKilledEvicted、ephemeral storage 不足或 node pressure。 增加/释放资源、调整单 task resource request,不能靠串行化掩盖。
PVC 或本地磁盘瓶颈 build step 在复制 source、上传 context、写 layer 或写 report 时集体变慢。 减少共享写、确认 source tree 只读、必要时优化 service workdir 和 BuildKit 存储。
BuildKit sidecar 竞态 step 日志出现 daemon/socket not ready、sidecar OOM 或 buildkitd 异常退出。 修 sidecar readiness、资源和日志;不要把问题转成 build task 互相依赖。
registry 写瓶颈 多个 build 同时 push 时出现 5xx、reset、blob timeout 或 registry Pod 压力。 查 registry Pod、存储和网络;必要时提升 registry 资源或存储能力。
report fan-in 异常 collect-artifacts 找不到某个 service report,或多个 service 报告内容互相覆盖。 确认 report 文件名按 serviceId 隔离,失败 task 能输出明确失败报告。
skipped task 误判 selected service 正确跳过,但 collect 误读为失败或缺 digest。 保持 collect 读 catalog+report 目录,不恢复 tasks.build-*.results 硬依赖。
下游 promotion 慢 build 全部完成后才慢,日志集中在 mirror push、Argo refresh 或 runtime-ready。 按 mirror/GitOps/runtime 排障;这不是 build 并发问题。

性能退化排障结束后,只把可复用的预算、原理和入口更新到本文;一次性 PipelineRun 名称、Pod 名称、日志全文和临时证据放到 issue 或 PR,不写入长期规格。

Env 容器复用与三变量启动

v0.2 code-only fast lane 的 runtime desired state 由三类输入组成:可复用 env image digest、自动推导的 code boot metadata、以及既有 service runtime config。开发者仍按当前 DEV/OPS 流程提交 v0.2 source commit 和维护 deploy/deploy.json;发布入口不得要求人工填写 repo、commitId 或 boot script 路径。

code boot metadata 固定映射到三个启动环境变量:

变量 自动推导来源 约束
HWLAB_BOOT_REPO v0.2 lane 的 canonical GitHub source repo 配置 必须是 canonical GitHub URL;用于身份记录,运行时读取由 resolver 自动分流到 mirror/cache。
HWLAB_BOOT_COMMIT UniDesk trigger-current 解析到的 origin/v0.2 完整 source commit SHA,也就是 PipelineRun revision 必须是完整 40 位 commit SHA;禁止 branch、tag、latest 或人工覆盖。
HWLAB_BOOT_SH service model 或 deploy/deploy.json 中 serviceId 到 boot script 的映射,默认形态为 deploy/runtime/boot/<serviceId>.sh 必须是 repo 内相对路径;禁止绝对路径、.. 越界和从 env image 中隐式寻找旧脚本。

CI/CD 必须把三变量同时写入 deploy/artifact-catalog.v02.json、rendered workload Pod template env/annotation 和 runtime health identity。三变量是由 lane 自动推导的发布事实,不是人工 OPS 参数;如果自动推导缺失或无法证明 HWLAB_BOOT_COMMIT 属于 v0.2 允许 ancestry,本轮 promotion 必须失败。

推荐启动形态是 initContainer + emptyDir + generic env image。initContainer 或 env image 内的 launcher 读取三变量,通过 resolver 把 HWLAB_BOOT_REPO 的只读 fetch/checkout 自动分流到 devops-infra git mirror/cache,按 HWLAB_BOOT_COMMIT checkout 到 Pod 私有 emptyDirmain container 复用同一 env image,并执行 checkout 后代码目录里的 $HWLAB_BOOT_SH。env image 只承载系统依赖、runtime、launcher、git client 和通用工具,不把业务代码或旧 boot script 当作运行真相。

code-only 变更时,planner 必须输出 envChanged=falsecodeChanged=true,跳过 BuildKit image publish,复用上一版 env image digest,只更新 catalog 和 workload Pod template 中的 HWLAB_BOOT_COMMIT、code identity annotation 与相关 health metadata。Kubernetes 原生 Deployment/StatefulSet rolling update 仍由 Pod template hash 变化触发;不需要在容器内长期驻留 watcher,也不把 git pull 结果作为运行真相。

devops-infra git mirror/relay 是 allowlisted、PVC-backed 或等价持久化服务,负责缓存 GitHub 对象并承接 v0.2-gitops 本地写入。只有 mirror/relay sync/flush 边界持有 GitHub 远端凭证;hwlab-v02、AgentRun 和其他业务 namespace 只能访问只读 mirror/cache endpoint,不持有 GitHub deploy key。runtime checkout 失败、mirror miss 超过明确等待窗口、commit ancestry 不满足 lane 约束或 boot script 校验失败时,Pod 必须启动失败或 NotReady,不得回退到 env image 内旧代码,也不得在业务 namespace 直连 GitHub 拉取。

git mirror/relay 接入方式遵循“CI 写本地、GitHub 异步归档、读自动加速”。GitOps 和 deploy spec 中的 repo 字段仍记录 canonical GitHub URL 作为身份字段;launcher 或只读 runtime image 内的 resolver 负责读路径自动分流。需要 push v0.2-gitops 的 promotion task 必须 push devops-infra 本地 mirror/relay,不得在 CI 关键路径直接 push GitHub canonical remote。

registry 与 git mirror/relay 分属不同基础设施边界。registry 保持当前 G14 hwlab-ci/hwlab-registry,继续通过 repository prefix 服务 HWLAB、AgentRun 和后续 lane;新增 devops-infra git mirror/relay 不触发 registry 迁移,也不要求在 devops-infra 复制 registry。

Artifact 与镜像身份

  • v0.2 镜像 tag 使用完整 40 位 source commitId。
  • runtime manifest 必须使用 digest pin 作为部署身份。
  • catalog 必须记录 lane/profile、source branch、GitOps branch、source commitId、serviceId、image tag、digest、component identity 和 publish/reuse 状态;启用 env 容器复用时还必须记录 runtimeMode=env-reuse-git-mirror-checkoutenvironmentImageenvironmentDigestenvironmentInputHashbootRepobootCommitbootShcodeInputHash 和三变量写入证据。
  • 同一 source commit 对同一 service 应生成同一镜像;lane 差异放在 manifest、env、SecretRef、namespace、FRP 和 DB 配置中,不 bake 进镜像。
  • deploy/deploy.json 只承载人写 runtime intent,不承载 digest、publish state 或 reuse evidence。

Kubernetes 与 Argo 边界

  • hwlab-v02 namespace 只能由 v0.2 GitOps lane 管理。
  • argocd/hwlab-v02 AppProject destination 只能包含 hwlab-v02
  • argocd/hwlab-g14-v02 source 必须指向 devops-infra 本地 mirror/relay 中的 v0.2-gitops:deploy/gitops/g14/runtime-v02destination 必须是 hwlab-v02
  • hwlab-v02-frpc 只能暴露 19666/19667,不能复用 17666/1766718666/18667
  • v0.2 Secret、DB 凭据、PVC、ServiceAccount 和 runtime config 必须独立命名或独立 namespace scope;文档、issue、trace 和 report 只记录 SecretRef 名称与 key,不记录值。
  • v0.2 初期不新增自动 registry GC;后续如启用清理,selector 必须带 lane/profile 标签,registry digest 保护集必须同时覆盖 G14-gitopsv0.2-gitops

硬边界

以下边界是 v0.2 CI/CD 的最小硬约束:

  • source branch 必须是 v0.2
  • GitOps branch 必须是 v0.2-gitops
  • runtime namespace 必须是 hwlab-v02
  • artifact catalog 必须是 deploy/artifact-catalog.v02.json
  • runtime path 必须是 deploy/gitops/g14/runtime-v02
  • Argo Application 必须是 hwlab-g14-v02,且只能部署到 hwlab-v02
  • source branch publish 后不得出现 deploy/artifact-catalog.v02.jsondeploy/gitops/g14/runtime-v02/** 变更。
  • GitOps promotion 的 changed paths 只能落在 deploy/artifact-catalog.v02.jsondeploy/gitops/g14/runtime-v02/** 及必要的 v02 Argo/GitOps 元数据。
  • 公网验收只能使用 19666/19667
  • v0.2 不得创建或依赖 CronJobhwlab-v02-branch-pollerhwlab-v02-control-plane-reconciler 或同类调度器出现时应清理,而不是接入发布链路。
  • 旧 DEV/D601/main gate、fallback、legacy mode 和双路径兼容不得进入 v0.2 调用链。
  • env 容器复用 fast lane 中,HWLAB_BOOT_REPOHWLAB_BOOT_COMMITHWLAB_BOOT_SH 必须由 CI/CD 自动推导并写入 GitOps desired state,不得作为人工发布参数或 runtime 临时 patch。
  • git mirror/relay 必须来自独立 devops-infra 服务;hwlab-v02 runtime namespace 不部署 mirror、不持有 GitHub deploy key、不在 mirror miss 时直连 GitHub fallback。
  • GitOps promotion 必须写入 devops-infra 本地 mirror/relay 的 v0.2-gitops;除 mirror/relay flush 外,不得在 CI 关键路径直接 push GitHub canonical remote。
  • mirror/relay write 必须只允许 allowlist refs,拒绝 non-fast-forward,拒绝越界 changed paths,并在 receive 成功前完成 object closure 校验。

这些硬边界优先在自然写入点做最小内联断言:render 断言 namespace/runtime pathpromotion 断言 GitOps branch/changed pathsArgo spec 断言 destination,验收断言端口和 runtime identity。不要为每条设计约定再新增独立 preflight、guard、gate 或报告生成器。

G14 DEV/PROD 不变边界

接入 v0.2 不得改变以下对象:

  • G14 source branch 的 poller/reconciler 语义。
  • G14-gitops DEV/PROD catalog 与 runtime desired state。
  • hwlab-devhwlab-prod namespace。
  • hwlab-g14-devhwlab-g14-prod Argo Application。
  • DEV 17666/17667 与 PROD 18666/18667 FRP 入口。
  • D601 legacy 回溯路径和旧运行面边界。

如果 v0.2 接入失败,回滚或暂停只能作用于 hwlab-v02 lane:停止手动触发新的 v02 PipelineRun、暂停或删除 hwlab-g14-v02、回滚 v0.2-gitops runtime path、关闭 hwlab-v02-frpc 或清理 hwlab-v02 namespace 资源;不得通过新增 CronJob 维持重试,也不得重启、删除或回滚 DEV/PROD 运行面。

验收标准

v0.2 CI/CD 通过必须同时满足:

  • hwlab-ci 中存在 hwlab-v02-ci-image-publishhwlab-v02-tekton-runner;不存在 v02 CronJob。hwlab-v02-branch-pollerhwlab-v02-control-plane-reconciler 不再作为 v02 标准对象,若历史残留应由 UniDesk control-plane apply 清理。
  • 最新 v0.2 source commit 对应的 PipelineRun 完成,且 promotion 写入 v0.2-gitops
  • v0.2-gitops 中存在 deploy/artifact-catalog.v02.jsondeploy/gitops/g14/runtime-v02/**
  • argocd/hwlab-g14-v02 指向 devops-infra 本地 mirror/relay 的 v0.2-gitops:deploy/gitops/g14/runtime-v02sync revision 与目标 GitOps revision 对齐。
  • hwlab-v02 中长驻 workload ready,没有把 DEV/PROD namespace 当成 v0.2 通过证据。
  • gitops-promote 推送本地 mirror/relay 的 v0.2-gitops 后应触发 argocd/hwlab-g14-v02 hard refresh,减少 GitOps push 与 Argo 仓库发现之间的漂移窗口;refresh 触发失败只作为低噪声事件输出,最终通过仍由 runtime-ready 判定。
  • mirror/relay status 必须能显示本地 v0.2-gitops revision、GitHub 已 flush revision、pending flush revision 和最近一次 flush 错误;CI 通过不要求 GitHub flush 已完成,但运维观察必须能看到上游是否落后。
  • runtime-ready 必须以 workload Pod template 的 source commit 判断 Argo 刷新,并在 Argo 刷新超时、observer RBAC 不足或 workload 未就绪时失败;不得把 CrashLoop、未刷新或公网不可用的 runtime 标成绿色。
  • 启用 env 容器复用的服务必须在 catalog、Pod template annotation/env 和 /health/live 或等价 runtime identity 中同时暴露 env image digest 与 HWLAB_BOOT_REPO/HWLAB_BOOT_COMMIT/HWLAB_BOOT_SH;只暴露镜像 digest 不能证明 code-only rollout 已生效。
  • code-only rollout 的 PipelineRun 必须能证明没有发布新 env image、复用了上一版 env digest、只更新 boot commit/code identity,并由 Kubernetes Pod template hash 触发滚动。
  • devops-infra git mirror/cache miss、commit ancestry 拒绝或 boot script 校验失败必须导致本轮 rollout fail closed,不得隐式回退到 GitHub 或 env image 内旧代码。
  • http://74.48.78.17:19666/ 返回 v0.2 Cloud Web。
  • http://74.48.78.17:19667/health/live 返回 v0.2 runtime healthpayload 中的 namespace、revision 或 runtime identity 能与 hwlab-v02/v0.2 对齐。
  • trigger-current 的异步 job 或 --wait 输出必须能显示 trigger 阶段进度;若 control-plane refresh、mirror pre-sync 或 delete/create PipelineRun 卡住,日志必须能定位阶段名和状态。
  • no-op env-reuse fast lane 必须输出完整证据链:g14-ci-plan 全复用、skipped-runtime-unchangedgitops-commit/gitops-push skipped、runtime-ready skipped。 不能只用 PipelineRun Completed 或总耗时证明没有退化。
  • 真实 rollout 的 runtime-ready 必须输出 started、周期性 progress 和最终 argo-refresh/argo-sync-health/workload-ready 类事件;缺少这些事件时应按可见性回归处理。

GitOps branch 已更新、source branch render 通过、PipelineRun 名称存在或 G14 DEV/PROD health 正常,都不能单独代表 v0.2 CI/CD 通过。

测试规格

T1

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:确认 origin/v0.2 最新 commit 对应的 PipelineRun 完成,promotion 只写入 v0.2-gitops,且 source branch 没有跟踪 deploy/artifact-catalog.v02.jsondeploy/gitops/g14/runtime-v02/** 生成物。

T2

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:查询 Argo hwlab-g14-v02,确认 source repo 为 devops-infra 本地 mirror/relaybranch/path 为 v0.2-gitops:deploy/gitops/g14/runtime-v02destination namespace 为 hwlab-v02sync revision 与目标 GitOps revision 对齐。

T3

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:访问 http://74.48.78.17:19666/http://74.48.78.17:19667/health/live,确认公网入口、payload environment、revision 和 runtime identity 都指向 v02,不把 DEV/PROD health 当作 v02 证据。

T4

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:涉及 Code Agent 时使用短连接 submit/result/trace 轮询,确认 status=completed 且 assistant reply 非空;不得只用 /health/livecodeAgent=ready 证明 provider 鉴权通过。

T5

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:对启用 env 容器复用的服务触发一次 code-only commit,确认 PipelineRun 标记 envChanged=false、复用上一版 env digest、catalog 与 Pod template 写入 HWLAB_BOOT_REPOHWLAB_BOOT_COMMITHWLAB_BOOT_SHruntime health 同时暴露 env digest 和 boot commit,且 HWLAB_BOOT_COMMIT 来自完整 origin/v0.2 source commit SHA。

T6

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:在不打印任何 GitHub 凭证的前提下确认 runtime checkout 读路径命中 devops-infra git mirror/cache,业务 namespace 没有 GitHub deploy key;模拟 mirror miss 或非法 commit 时 rollout fail closed,不回退到 GitHub 直连或 env image 内旧代码。

T7

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:触发一次 v0.2 code-only promotion,确认 gitops-promote 只 push 到 devops-infra 本地 mirror/relayArgo 从本地 mirror/relay rollout;再执行 git-mirror flush --confirm,确认 GitHub origin/v0.2-gitops 快进到同一 revisionstatus 中 pending 清空。

T8

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:在 v0.2 source checkout 或对应 PipelineRun primitive validation 日志中确认 bun run --cwd web/hwlab-cloud-web check 会在 hwlab-cloud-web 镜像发布前执行,并且该 check 包含实际 bundle 输入集合的 TypeScript 语义检查、自动发现的 *.test.ts 单元测试、bundle build 和 dist freshness 校验。

T9

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:确认默认 v0.2 CI 没有重新加入 Playwright、旧 layout smoke、旧 quick prompt、旧 M3 evidence 或 DEV/D601 browser gate;若这些旧门禁重新进入最小 check plan 或 PipelineRun,应直接删除入口并保留 Cloud Web semantic check 与单元测试。

规格的实现情况

规格项 状态 说明
v02 独立 source/GitOps/runtime lane 已实现 v0.2v0.2-gitopshwlab-v02runtime-v02 已固定。
手动 CLI trigger/pipeline/promotion 已实现 通过 UniDesk trigger-current 创建 commit-pinned PipelineRunv02 不设 CronJob,由 hwlab-v02-ci-image-publish 与 GitOps promotion 管理。
v02 runtime readiness fail-closed 已实现 gitops-promote 推送后触发 Argo hard refreshruntime-ready 读取 workload Pod template source committimeout、observer RBAC 不足或未就绪会让 PipelineRun 失败。
v02 裁撤服务不进入发布面 已实现 v02 Tekton build service set、artifact catalog 和 runtime render 只包含保留服务;v02 Argo 开启 prune 清理旧 live 对象;裁撤服务仍可保留在 DEV legacy 源码中。
Argo v02 Application 已实现 hwlab-g14-v02 指向 v02 GitOps path 和 namespace。
FRP 19666/19667 入口 已实现 hwlab-v02-frpc 与 master frps allowlist 共同提供。
SecretRef 独立与 provider 验收 已实现/持续约束 SecretRef 已独立;验收必须做真实短连接聊天。
env 容器复用三变量启动 已实现/持续约束 device-pod fast lane 已由 CI/CD 自动推导 HWLAB_BOOT_REPOHWLAB_BOOT_COMMITHWLAB_BOOT_SHcode-only rollout 复用 env image digest,只更新代码身份。
devops-infra git mirror/relay 加速 已实现/持续约束 source/catalog/runtime checkout 读路径和 GitOps promotion 写路径均使用独立基础设施集群 mirror/relayArgo source 指向本地 mirrorGitHub flush 由 UniDesk CLI 手动触发,不设置 CronJob。runtime namespace 不持有 GitHub deploy keyregistry 保持 G14 hwlab-ci/hwlab-registry
hwlab-cli 不进 CI/CD service matrix 已实现/持续约束 CLI 是固定 repo 短连接 client,不发布镜像、不生成 artifact、不创建 build-hwlab-cli TaskRun;相关旧入口出现时直接删除。
CI/CD fast lane 性能预算 已实现/持续约束 env-reuse no-op 目标约 40s;真实 runtime rollout 目标约 50s;不得恢复 prepare-source 依赖安装、GitHub 关键路径写入或 no-op runtime 等待。
Service build 全并行 fan-out 已实现/持续约束 selected services 的 build TaskRun 全部只依赖 plan-artifacts,不设置 8 并发或其他 Pipeline 级限流;collect-artifacts 通过 service report 目录 fan-in。
自动 registry GC 未实现 初期不启用自动 GC,后续需 lane/profile 保护集。

平行 lane 运维边界

后续新增 v0.x 或其他平行 runtime lane 时,优先复用本节的判定顺序和排障边界,避免把一次性补丁沉淀成新的宽泛门禁。本节只保留可复用的运维边界;具体执行记录、排障流水和一次性证据应放在 issue 或 PR 中。

Secret 导入与重启边界

平行 lane 的 Secret 必须独立命名,不能在 runtime 里直接引用 DEV Secret。允许把 DEV 当前值一次性导入到目标 lane 的独立 Secret 名,但验证只能输出 Secret 对象、key、字节数和哈希指纹,不能打印 Secret value、token 片段、完整 DB URL 或 auth.json 内容。

v0.2 至少需要独立维护以下 SecretRef:

  • hwlab-v02-postgres/POSTGRES_PASSWORD
  • hwlab-cloud-api-v02-db/database-url
  • hwlab-v02-code-agent-provider/openai-api-key
  • hwlab-v02-code-agent-codex-auth/auth.json

Code Agent 的 Secret 修复不是只改一个 Secret 对象就结束。hwlab-cloud-api 通过 env 读取 OPENAI_API_KEYSecret 更新后必须滚动 hwlab-v02/hwlab-cloud-api。DeepSeek profile 还通过 hwlab-deepseek-proxy 的 initContainer 把 DEEPSEEK_API_KEY 渲染进 Moon Bridge 配置,Secret 更新后也必须滚动 hwlab-v02/hwlab-deepseek-proxy,否则 proxy 仍会使用旧配置并返回上游鉴权失败。

Code Agent 验收

/health/livecodeAgent=readycodexStdio=ready 只能证明运行时结构、二进制、workspace、token boundary 和会话 supervisor 就绪;它不证明真实 provider 鉴权可用。涉及 Code Agent 的扩容验收必须追加一次真实短连接聊天闭环:用 Prefer: respond-asyncX-HWLAB-Short-Connection: 1 提交 /v1/agent/chat,再轮询 /v1/agent/chat/result/<traceId>,只有 status=completed 且 assistant reply 非空才算通过。

如果 trace 里出现 Authentication Failsupstream stream errorcodex_stdio_provider_retry,先按 profile 分层判断:deepseek profile 走 hwlab-deepseek-proxy.<namespace>.svc.cluster.local:4000/v1/responses 和 Moon Bridgecodex-api profile 走 Pod-local loopback forwarder。不要用 codex-api readiness 掩盖 DeepSeek 专用凭证或 Moon Bridge 配置问题。

长耗时 smoke 不应通过 UniDesk SSH 长连接等待完整 Codex turn。Codex 首 token 可能超过短查询窗口,验证应使用短连接 submit/result/trace 轮询,避免把控制通道超时误判成 provider 失败。

GitOps 与 runtime 收敛

GitOps promotion 成功不等于 runtime 已经运行新版本。验收必须等待 argocd/hwlab-g14-v02 的 sync revision 对齐最新 v0.2-gitops revision,并确认 19667/health/liveenvironmentendpoint、关键 SecretRef 和 service revision 与目标 lane 对齐。

Argo Synced/Healthy 也不能单独替代公网验证。FRP server 侧 allowPorts 缺失时,hwlab-v02-frpc 会反复报告 port not allowed;这种问题应修 master 侧 frps allowlist 并只重启 hwlab-frps-dev,不要改 DEV/PROD GitOps、Service 或 v02 runtime path。修复后必须同时验证新增 19666/19667 和既有 DEV 17666/17667

后续扩容建议

下一条平行 lane 建议先列一张最小资源映射表,再落地 CI/CDsource branch、GitOps branch、runtime namespace、runtime path、Argo Application、FRP ports、artifact catalog、Postgres Secret、Cloud API DB Secret、Code Agent provider Secret、Codex auth Secret、DeepSeek proxy restart 对象和公网验收 URL。映射表是执行清单,不是新 gate;只有 branch、namespace、runtime path、GitOps branch、Argo destination、SecretRef 名称和公网端口这些硬边界需要内联断言。

Secret、FRP 和 Argo 问题都应先在目标运行面做最小真实闭环,再进入完整 CI/CD 复跑。不要用完整 PipelineRun 反复探索 Secret 值、FRP allowlist 或 provider 鉴权;CI/CD 只负责固化已经在目标 namespace 证明可行的配置和源码。