76 KiB
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,PR 合并后自动 CD 迁移计划见 pikasTech/HWLAB#848,CI 无锁并发与 CD latest-only 迁移见 pikasTech/HWLAB#866。原 docs/plan/hwlab-v02-namespace-cicd.md 阶段计划全文已迁入 #530 评论。本文只记录稳定规格、边界和判定标准;不要把一次性执行记录、排障流水账或临时证据写入本文。
在系统中的职责划分
v0.2 CI/CD 是 G14 上的加法 lane:source 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 受控触发入口、CI/CD 专用 source repo、devops-infra git mirror、PipelineRun、component planner、BuildKit publish、GitOps promotion、Argo sync、GitHub flush 和公网验收构成。标准触发方式是 UniDesk CLI 合并 base=v0.2 PR 后自动进入 v02 CD;trigger-current 手动入口和 auto-cd --once 类补偿入口保留用于人工重跑、漏触发修复和迁移期验证。v0.2 不设置 k8s branch poller、control-plane reconciler 或其他 CronJob;source branch 只保存源码和人写配置;v0.2-gitops branch 保存 catalog 和 rendered runtime desired state;live runtime 是最终通过证据。固定开发 workspace 只服务人工开发和短连接源码工具,不参与 CI/CD source commit 选择。
首期自动化不要求 GitHub webhook。PR 创建、预检和 merge 已由 UniDesk CLI 控制时,merge 成功后的同一受控流程应直接解析最新 origin/v0.2 head 并调用现有 v02 control-plane。若未来接入 webhook,它只能作为唤醒信号;发布 source commit 仍必须由 /root/hwlab-v02-cicd.git fetch 到的 refs/remotes/origin/v0.2 决定,不能直接信任 webhook payload 创建 PipelineRun。
v0.2 的 GitOps 写路径采用真正写 mirror:promotion 先把 v0.2-gitops 写入 devops-infra 本地 git mirror/relay,Argo CD 从本地 mirror/relay 读取该 revision 并 rollout,CI 关键路径不等待 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 固定。 |
| UniDesk v02 PR auto-CD monitor | 观察并合并 base=v0.2 的 ready PR,merge 后调用现有 trigger-current、定点 status 和 git-mirror flush。 |
Tekton hwlab-v02-ci-image-publish |
构建 affected images、复用 unchanged digest,并 promotion 到 v0.2-gitops。 |
devops-infra git mirror/relay |
读写 v0.2 allowlist refs;CI 读 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,不改写现有G14DEV/PROD lane。v0.2source branch 只保存源码、人写配置、模板、脚本和文档;CI/CD 生成物只进入v0.2-gitops。hwlab-v02是唯一 runtime namespace;74.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 |
| Development workspace | G14:/root/hwlab-v02,仅用于人工开发、短连接源码工具和可见性对照,不作为 CI/CD source commit 选择入口 |
| CI/CD source repo | G14:/root/hwlab-v02-cicd.git bare repo,由 UniDesk control-plane 自动 fetch origin/v0.2,再从 commit-pinned detached worktree render/apply 控制面 |
| 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 |
| PR merge auto-CD | UniDesk CLI v02 PR monitor 合并 base=v0.2 PR 后自动调用 trigger-current,并定点观察 merge head |
| Manual trigger | UniDesk CLI bun scripts/cli.ts hwlab g14 control-plane trigger-current --lane v02 --confirm,仅作为人工重跑和迁移期补偿入口 |
| Reconcile fallback | UniDesk CLI v02 auto-cd --once 或等价补偿入口,对齐当前 origin/v0.2 head、PipelineRun、GitOps 和 mirror flush 状态 |
| Scheduler/CronJob | 不创建、不保留 v02 k8s CronJob;PipelineRun 只能由 UniDesk CLI PR monitor、manual trigger 或 once reconcile 创建 |
| 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 的发布真相按以下顺序判断:
- live runtime:
hwlab-v02namespace 中 Deployment/StatefulSet template、Pod ready、事件、日志和19666/19667公网 health。 - Argo desired state:
argocd/hwlab-g14-v02的 revision、sync、health、source branch 和 runtime path。 - CI/CD source refs:UniDesk control-plane 专用 bare repo
refs/remotes/origin/v0.2、devops-infra mirror/relay 的refs/heads/v0.2与refs/mirror-stage/heads/v0.2必须共同指向最新 source commit。 - devops-infra mirror/relay 中的 GitOps branch:
v0.2-gitops中的deploy/artifact-catalog.v02.json与deploy/gitops/g14/runtime-v02/**。 - Tekton 执行证据:UniDesk
trigger-current返回的 PipelineRun、TaskRun result、gitops-promote终态。 - GitHub 上游归档状态:mirror/relay flush 后的
origin/v0.2-gitops与origin/v0.2。 - 固定开发 workspace:
/root/hwlab-v02的HEAD、dirty 状态和origin/v0.2只作为人工开发对照线索;即使 workspace 脏或落后,也不得影响 CI/CD source commit 选择。
旧 commit 记忆、G14/G14-gitops DEV/PROD 产物、D601 legacy 路径、GitHub 上游尚未 flush 的短暂落后、source branch 中历史 generated 文件、固定开发 workspace 脏状态和临时 worktree 只能作为线索,不能作为 v0.2 发布通过证据。
Workspace 与 CI/CD 分离
v0.2 开发 workspace 和 CI/CD repo 必须分离。/root/hwlab-v02 是人工开发、短连接 hwlab-cli 和问题复现的固定 workspace;它允许出现并行任务产生的 untracked .worktree/、本地 dirty 文件或临时落后状态。CI/CD 不从该 checkout 的 HEAD、工作树 clean 状态或本地 branch 读取待发布 commit,也不得因为该 workspace 脏而跳过、误判或复用旧 PipelineRun。
UniDesk control-plane 必须使用独立 bare repo /root/hwlab-v02-cicd.git 作为 CI/CD source repo:每次 status、apply、git-mirror apply 和 trigger-current 先自动 fetch origin/v0.2 到 refs/remotes/origin/v0.2,再用目标 commit 创建 detached temp worktree 运行 scripts/g14-gitops-render.mjs --lane v02。该 repo 没有业务工作树,因此不会被人工开发 dirty 状态污染;如果它不可用,应以 v02-head-unresolved 或等价结构化错误失败,而不是回退到固定 workspace HEAD。
devops-infra git mirror 仍是 PipelineRun 和 Argo CD 的集群内读写源。trigger-current --lane v02 --confirm 在创建 PipelineRun 前必须比较 expectedSourceHead 与 mirror localV02,不一致时自动执行 bounded git-mirror sync Job。git-mirror status 必须分别暴露 localV02、githubV02、localGitops、githubGitops、sourceInSync、gitopsInSync 和 pendingFlush;githubInSync 不得再被理解为只代表 GitOps branch。
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 链路
标准链路如下:
- PR open/update 阶段只运行 source CI、检查和 PR preflight,不修改
hwlab-v02runtime,也不写v0.2-gitops。 - UniDesk CLI v02 PR monitor 只观察
pikasTech/HWLABbase=v0.2的 ready PR;ready PR 不因为其他 commit 的 PipelineRun 仍在运行而阻塞 merge。merge 成功后重新 fetch/root/hwlab-v02-cicd.git的origin/v0.2,以 fetch 后的完整 source commit SHA 作为待发布目标。 - monitor 调用现有
hwlab g14 control-plane trigger-current --lane v02 --confirm。该入口自动复核devops-inframirror 的localV02ref,必要时执行一次 boundedgit-mirror syncJob,再创建 commit-pinnedhwlab-v02-ci-poll-<short12>PipelineRun;同一 source commit 已有 PipelineRun 时只复用现有状态,不删除重建。默认--dry-run只返回将要创建的 manifest 和 mirror pre-sync 计划。人工重跑和auto-cd --once补偿必须复用同一入口,不得直接创建 PipelineRun。 prepare-source通过devops-inframirror checkoutv0.2source,并从 mirror 中的v0.2-gitops读取上一版deploy/artifact-catalog.v02.json。- CI/CD 校验只保留最小构建、TypeScript 语义检查、自动单元测试、打包和必要冒烟检查;旧 DEV/D601/main gate、运行时内部证明型校验、健康诊断重断言和历史预检不进入 lane。
- planner 根据 component input 判断 affected/reused services。
- affected service 通过 BuildKit 发布到 G14 本地 registry;reused service 复用 catalog digest。
所有 selected service 的 build TaskRun 都只依赖
plan-artifacts,不按 service 串行排队,也不设置 8 并发或其他 Pipeline 级限流。 实际并发由 Tekton controller、G14 节点资源、PVC I/O、BuildKit sidecar 和本地 registry 承载能力决定。hwlab-cloud-web和hwlab-device-pod必须使用env-reuse-git-mirror-checkout。 只有 package/runtime/env 输入变化时才构建<service>-env镜像。 纯前端源码、Device Pod 源码或 boot code 变化只更新三变量和 GitOps desired state, 不再重新构建业务镜像。 - promotion 刷新
deploy/artifact-catalog.v02.json,renderdeploy/gitops/g14/runtime-v02/**,只在本 PipelineRun 的 source commit 仍是当前origin/v0.2head 时推送到devops-inframirror/relay 的v0.2-gitops;若 source branch 已推进,本轮输出 superseded/no-op,写出runtime-ready-required=false,不得回写旧 GitOps revision。 hwlab-g14-v02从本地 mirror/relay 的v0.2-gitops:deploy/gitops/g14/runtime-v02同步到hwlab-v02。- UniDesk CLI auto-CD 观察定点
control-plane status --lane v02 --source-commit <merge-head>或--pipeline-run <name>,确认 PipelineRun、Argo、runtime workload、public probes 和 planArtifacts build/reuse 摘要。历史 merge head 若因后续origin/v0.2推进而被 superseded,PR 评论以 superseded 收口;最新 head 仍必须继续收敛到 runtime。 - UniDesk CLI 或 mirror/relay flush 操作把本地
v0.2-gitops推送到 GitHub canonical remote;flush 不在 CI runtime-ready 的关键路径内,但自动 CD 收口必须查询 pending、lastFlushed 和 failure,必要时执行git-mirror flush --confirm并等待pendingFlush=false。 - 验收只观察
hwlab-v02runtime 和19666/19667,并把 source commit、PipelineRun、GitOps revision、build/reuse 摘要、Argo/runtime/public probe 状态写回 PR 或关联 issue。
trigger-current --lane v02 --confirm 默认返回异步 job,不等同于 PipelineRun 已经创建完成。调用方必须先运行返回的 job status <jobId>,等 progress.stage=create-pipelinerun 且 progress.pipelineCreated=true 后,再用 control-plane status --lane v02 --pipeline-run <name> 做定点发布观察。progress.pipelineRun 可以在 control-plane refresh 或 mirror pre-sync 阶段提前给出预期名称;此时如果重型 status 报 target-pipelinerun-not-found-or-unreadable,只能说明 PipelineRun 尚未创建,不能作为发布失败、mirror 失败或 runtime 回归结论。
定点发布观察优先使用 --pipeline-run <name> 或 --source-commit <full-sha>,避免 branch 后续推进导致历史 run 被最新 head 口径误判。control-plane status 会同时做 source/mirror/TaskRun/Argo/runtime/web asset 汇总,可能比普通只读查询慢;高频轮询时先看异步 job progress 和 TaskRun 条件摘要,只在阶段收口或异常定位时再跑完整 status。
GitOps promotion 成功后,本地 mirror/relay 的 v0.2-gitops 可立即被 Argo 消费;GitHub 上游 flush 是归档与跨节点同步步骤,不在 runtime-ready 关键路径内。git-mirror status.pendingFlush=true 时自动 CD 和人工收口都应运行 git-mirror flush --confirm,再用该 flush job 的 job status 或 git-mirror status 确认 pendingFlush=false、localGitops=githubGitops。不要把 pending flush 误判为 runtime 未发布,也不要在 flush job 仍运行时反复做全量 status。
v0.2 可以复用 G14 的 registry、proxy、BuildKit、工具镜像和脚本库;不得复用 hwlab-g14-ci-image-publish、hwlab-g14-branch-poller、hwlab-g14-control-plane-reconciler、G14-gitops runtime path 或 DEV/PROD Argo Application 作为 v0.2 发布入口。运行时不得为每个版本硬编码 namespace、catalog、runtime path 或健康判断;版本差异只通过 deploy.json.lanes[profile]、GitOps render 输入和实际 runtime 对象表达,新增版本不得新增运行时代码分支。
v0.2 不设 k8s 自动轮询发布。历史上若存在 hwlab-v02-branch-poller、hwlab-v02-control-plane-reconciler 或等价 CronJob,均视为迁移残留,应由 UniDesk control-plane apply 清理。PR 合并后的自动 CD 只能由 UniDesk CLI monitor 或一次性 reconcile job 驱动,并且必须复用 trigger-current、定点 status 和 git-mirror flush。暂停发布时停止 UniDesk monitor 或停止创建新的 PipelineRun;不要通过新增 CronJob 维持重试。
v02 auto-CD 必须采用 CI 无锁并发与 CD latest-only 语义。不同 source commit 的 PipelineRun 可以并发运行;monitor 不等待旧 run 空闲,也不取消旧 run。同一个 source commit 已有 PipelineRun 时不得删除重建。GitOps promotion 是唯一写入点,必须在写 v0.2-gitops 前重新读取 origin/v0.2 head:只有当前 PipelineRun commit 仍是最新 head 才允许写入;旧 commit 继续跑完 CI 后必须 superseded/no-op 收口,不能把 runtime 或 GitOps branch 滚回旧 commit。auto-cd --once 或等价补偿入口用于处理人工 GitHub merge、直接 push、monitor 重启或上次触发失败:它比较最新 origin/v0.2 head、PipelineRun、Argo/GitOps 和 mirror flush 状态,缺什么补什么,但仍不绕过标准 control-plane 入口。
devops-infra git mirror/relay 同样不设周期 CronJob。标准触发命令 bun scripts/cli.ts hwlab g14 control-plane trigger-current --lane v02 --confirm 会在创建 PipelineRun 前按需同步 mirror;bun 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.2、v0.2-gitops、G14 和 G14-gitops,先 fetch 到隐藏 staging refs,校验 commit/tree/object closure,再用 update-ref 发布到公开 refs。这样 mirror read path 与 GitOps write path 都落在本地磁盘和集群网络,同时避免 CI 看到 ref 已更新但对象还不可 checkout 的半发布窗口。
mirror 的 HTTP upload-pack 必须允许按精确 commit SHA 拉取已存在对象:uploadpack.allowReachableSHA1InWant=true 且 uploadpack.allowAnySHA1InWant=true。v0.2 Code Agent 通过 AgentRun 传递 resourceBundleRef.commitId 来复现实验时的源码身份,runner 会执行等价的 git fetch --depth=1 origin <commitId>;如果 mirror 只允许 advertised refs,旧 runtime commit、GitOps 已推进后的 commit 或隐藏 staging 已验证对象会返回 Server does not allow request for unadvertised object 并表现为 git fetch failed with code 128。这不是把 AgentRun 降级成浮动 branch fetch 的理由,修复点是 mirror read service 的 upload-pack 策略。
hwlab-cli 不属于 v0.2 CI/CD service matrix。它是 G14:/root/hwlab-v02 和 v0.2 worktree 内的短连接源码 client,只用 Bun 直接调用 Cloud Web 同源 API;不得加入 PipelineRun services 参数、artifact catalog、BuildKit publish、runtime desired state、Deployment、Service、Job 或 image build。CLI-only source 变更推送到 origin/v0.2 后,trigger-current --lane v02 应表现为 build=0 reuse=<runtime-services> 的 source-only fast path,用于证明 source/mirror/GitOps 没有产生旧 runtime artifact 副作用。若出现 build-hwlab-cli TaskRun、hwlab-cli artifact service、CLI 镜像或 CLI 常驻服务,均视为旧门禁/旧断言残留,直接删除并回到 docs/reference/spec-v02-hwlab-cli.md 的短连接 client 口径。
rpt004:mvp:e2e、runner:issue-visibility:preflight 和 dev-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.ts、app-device-pod.ts、app-conversation.ts、app-trace.ts 和 app-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/旧路由/旧门禁断言阻碍当前目标时,删除旧断言而不是维护兼容分支。
远端验证短连接规则
G14 host、worktree、k3s 控制面或 pod 内的验证命令必须按短连接可见性设计。通过 UniDesk ssh/tran route 执行 npm run web:check、npm run web:layout、Playwright、Tekton/Argo 观察、镜像构建、发布等待或其他可能超过单次维护桥预算的动作时,不得让 SSH 连接长时间阻塞等待完整输出。标准做法是用一次短连接创建后台 job、PipelineRun、Tekton task 或显式脚本 job,把 stdout/stderr、exit code、开始/结束时间和关键元数据写入 /tmp、.state 或 CI artifact;随后用有界短连接轮询 status、tail、exit.code、TaskRun result 或 Argo summary。
如果一次远端验证已经触发 UNIDESK_SSH_RUNTIME_TIMEOUT、日志尾部缺失、exit code 不可见或浏览器/CI 进度不可见,必须先把该验证改成后台 job 加短轮询,再继续排障或发布。禁止把 60s 维护桥断开当作测试失败、测试通过或外部依赖不可用;也禁止通过加大本地等待、重复长连接、全量日志 dump 或改回原生 SSH 绕过来处理。长期 CLI/CI 能力不足时,优先补 UniDesk CLI 的异步 job/status/tail 子命令,再用该入口完成验证。
写 mirror 的一致性模型是 local-first、manual-flush。promotion task 只能持有 mirror/relay 写凭证,不持有 GitHub deploy key;GitHub 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 约 11s;gitops-promote 约 7s;runtime-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.json 的 scripts、旧门禁入口、短连接 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 | buildServices 或 rolloutServices 非空但本轮只改 CI/CD 文档/脚本时,先查 component input 与 catalog 是否加载。 |
collect-artifacts |
约 6-8s | 未输出运行时服务矩阵的 artifact_reuse 或全部 runtime services reuse 时,先查 catalog digest、PipelineRun services 参数和 service identity;hwlab-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-gitops,Argo 也从 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 %p;Tekton GIT_SSH_COMMAND、git-mirror sync/flush 和其他容器内 git@github.com 或 ssh://git@ssh.github.com:443 路径必须使用 repo-owned Node HTTP CONNECT ProxyCommand,并保留短 ConnectTimeout 与 ServerAlive*。只改 HTTP_PROXY/HTTPS_PROXY 对 OpenSSH 无效;BusyBox nc 不支持 -X connect,不得再把 ssh.github.com:443 当作等价 proxy 或让 GitHub SSH 直连反复 60s 超时。
env image 复用把系统依赖和业务代码身份分离。environmentDigest 表示可复用运行环境,HWLAB_BOOT_REPO、HWLAB_BOOT_COMMIT 和 HWLAB_BOOT_SH 表示本次代码启动身份。code-only 变更只更新 boot metadata 和 runtime identity,不发布新 env image;只有真实 env 输入变化或缺少可复用 env digest 时才进入 env rebuild。AgentRun v0.1 是 HWLAB 外部共享执行基础设施,hwlab-agent-worker 不再作为 v0.2 service image 或 suspended Job template 参与 planner、BuildKit、artifact catalog 或 GitOps render。package.json 只按 dependency/runtime 字段参与 env/runtime hash,scripts 只属于开发入口,不得因为清理旧门禁脚本而重建所有 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>.json。
collect-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
Pending、Unschedulable、OOMKilled、Evicted或 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-infragit 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 真正消费的子目录才影响对应 runtime;device-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 事件,包含 observedCount、workloadCount、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.id、statusCommand、stdout/stderr 路径。
同步调试使用 --wait 时,stderr 必须输出 hwlab.v02.trigger.progress JSON 事件。
事件至少覆盖 control-plane-refresh、git-mirror-pre-sync、delete-existing-pipelinerun 和 create-pipelinerun。
每个阶段都要有 started 与 succeeded 或 failed,并携带足够定位的信息,例如 mirror sync job、mode、PipelineRun name 或耗时。
异步 job 的 stderr tail 也必须能看到同一类进度事件。
如果 trigger 卡住但只有一条启动命令或空日志,应先修 UniDesk CLI 可见性,不要把问题推给 Tekton 或反复重跑 Pipeline。
Pipeline 内部的 no-op fast lane 必须形成完整证据链。
prepare-source 输出 source-clone 与 catalog-fetch timing。
plan-artifacts 输出 g14-ci-plan,其中 buildServices=[]、rolloutServices=[] 且 runtime service 全部 reuse。
gitops-promote 输出 skipped-runtime-unchanged、runtime-identity-only,并把 gitops-commit 与 gitops-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 超时但日志里没有 started、progress、argo-refresh、argo-sync-health、workload-ready 或 observedCount,先按可见性回归修复日志和观察集合。
再讨论 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-refresh、git-mirror-pre-sync、delete-existing-pipelinerun 和 create-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 status;PipelineRun 创建后才进入 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-unchanged、gitops-commit 和 gitops-push 为 skipped,并且 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-plan 的 affectedServices、buildServices、rolloutServices、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=false 和 skipped-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 后才输出一条日志 |
是否缺少 started、progress、workload-ready 或 observedCount |
这是可见性回归;先修日志和观察集合,不要先加大 timeout。 |
mirror pendingFlush=true 长期存在 |
bun scripts/cli.ts hwlab g14 git-mirror status 和最近一次 flush 错误 |
手动 git-mirror flush --confirm;flush 不影响已 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 task;startTime 严格一个接一个且没有 Pod Pending 证据。 |
修 render 和 live Pipeline,恢复 build task 只依赖 plan-artifacts。 |
| 控制面或调度排队 | plan-artifacts 完成后 TaskRun/Pod 创建分散,event 出现调度等待。 |
查 Tekton controller、scheduler、API latency 和 node 可用资源。 |
| 节点资源压力 | Pod Pending、OOMKilled、Evicted、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 必须失败。
HWLAB_BOOT_REF 是由 lane 的 source branch 派生的 mirror transport hint,
不属于发布身份三变量,也不得作为人工 OPS 参数。env-reuse launcher 必须先通过
HWLAB_BOOT_REF 读取 mirror 中可广告的分支/ref,再 checkout HWLAB_BOOT_COMMIT;
不得直接 git fetch <sha> 依赖 smart HTTP 对 unadvertised object 的支持。
这样可以稳定支持历史 commit rollout、Argo 回滚和 env image 复用,
同时保持发布身份仍由 HWLAB_BOOT_REPO、HWLAB_BOOT_COMMIT、HWLAB_BOOT_SH 三变量表达。
推荐启动形态是 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 私有 emptyDir;main container 复用同一 env image,并执行 checkout 后代码目录里的 $HWLAB_BOOT_SH。env image 只承载系统依赖、runtime、launcher、git client 和通用工具,不把业务代码或旧 boot script 当作运行真相。
code-only 变更时,planner 必须输出 envChanged=false、codeChanged=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-checkout、environmentImage、environmentDigest、environmentInputHash、bootRepo、bootCommit、bootSh、codeInputHash和三变量写入证据。 - 同一 source commit 对同一 service 应生成同一镜像;lane 差异放在 manifest、env、SecretRef、namespace、FRP 和 DB 配置中,不 bake 进镜像。
deploy/deploy.json只承载人写 runtime intent,不承载 digest、publish state 或 reuse evidence。
Kubernetes 与 Argo 边界
hwlab-v02namespace 只能由v0.2GitOps lane 管理。argocd/hwlab-v02AppProject destination 只能包含hwlab-v02。argocd/hwlab-g14-v02source 必须指向devops-infra本地 mirror/relay 中的v0.2-gitops:deploy/gitops/g14/runtime-v02,destination 必须是hwlab-v02。hwlab-v02-frpc只能暴露19666/19667,不能复用17666/17667或18666/18667。v0.2Secret、DB 凭据、PVC、ServiceAccount 和 runtime config 必须独立命名或独立 namespace scope;文档、issue、trace 和 report 只记录 SecretRef 名称与 key,不记录值。v0.2初期不新增自动 registry GC;后续如启用清理,selector 必须带 lane/profile 标签,registry digest 保护集必须同时覆盖G14-gitops与v0.2-gitops。
硬边界
以下边界是 v0.2 CI/CD 的最小硬约束:
- source branch 必须是
v0.2。 - PR 自动 CD 只能观察和合并 base=
v0.2的 PR;其他 base branch 不得触发 v02 runtime rollout。 - 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.json或deploy/gitops/g14/runtime-v02/**变更。 - GitOps promotion 的 changed paths 只能落在
deploy/artifact-catalog.v02.json与deploy/gitops/g14/runtime-v02/**及必要的 v02 Argo/GitOps 元数据。 - 公网验收只能使用
19666/19667。 v0.2不得创建或依赖 k8s CronJob;hwlab-v02-branch-poller、hwlab-v02-control-plane-reconciler或同类调度器出现时应清理,而不是接入发布链路。- GitHub webhook 不是 v02 首期自动 CD 的必需入口;若未来接入,只能作为唤醒信号,不能直接决定发布 commit 或创建 PipelineRun。
- 自动 CD、手动 trigger 和 once 补偿都必须复用 UniDesk
trigger-current、定点status和git-mirror flush;不得绕到裸kubectl、Argo、Tekton 或手写 GitHub API。 - 旧 DEV/D601/main gate、fallback、legacy mode 和双路径兼容不得进入
v0.2调用链。 - env 容器复用 fast lane 中,
HWLAB_BOOT_REPO、HWLAB_BOOT_COMMIT和HWLAB_BOOT_SH必须由 CI/CD 自动推导并写入 GitOps desired state,不得作为人工发布参数或 runtime 临时 patch。 deploy/deploy.json只保存人写运行意图,不得被 auto-CD、promotion 或 flush 回写commitId、serviceimage、HWLAB_COMMIT_ID、HWLAB_IMAGE或HWLAB_IMAGE_TAG等发布产物字段。- git mirror/relay 必须来自独立
devops-infra服务;hwlab-v02runtime 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 path,promotion 断言 GitOps branch/changed paths,Argo spec 断言 destination,验收断言端口和 runtime identity。不要为每条设计约定再新增独立 preflight、guard、gate 或报告生成器。
G14 DEV/PROD 不变边界
接入 v0.2 不得改变以下对象:
G14source branch 的 poller/reconciler 语义。G14-gitopsDEV/PROD catalog 与 runtime desired state。hwlab-dev与hwlab-prodnamespace。hwlab-g14-dev与hwlab-g14-prodArgo Application。- DEV
17666/17667与 PROD18666/18667FRP 入口。 - D601 legacy 回溯路径和旧运行面边界。
如果 v0.2 接入失败,回滚或暂停只能作用于 hwlab-v02 lane:停止 UniDesk v02 monitor、停止手动触发新的 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-publish和hwlab-v02-tekton-runner;不存在 v02 CronJob。hwlab-v02-branch-poller与hwlab-v02-control-plane-reconciler不再作为 v02 标准对象,若历史残留应由 UniDesk control-plane apply 清理。- base=
v0.2的 ready PR 由 UniDesk CLI 合并后,会自动触发对应 merge head 的 v02 PipelineRun;其他 commit 的运行中 PipelineRun 不阻塞 ready PR merge 或 CI 启动。 - 同一个 source commit 已有 PipelineRun 时不重复创建,也不删除重建;失败 run 的人工重试必须走后续显式 retry 策略,不恢复默认 delete/create。
- 自动 CD 在旧 run 运行期间遇到新
origin/v0.2head 时,新 head 可直接触发自己的 PipelineRun;旧 run 继续完成 CI,但 promotion 必须在写 GitOps 前发现 stale head 并 superseded/no-op,不能回写旧v0.2-gitops或回滚 runtime。 - 最新
v0.2source commit 对应的 PipelineRun 完成,且 promotion 写入v0.2-gitops。 v0.2-gitops中存在deploy/artifact-catalog.v02.json与deploy/gitops/g14/runtime-v02/**。argocd/hwlab-g14-v02指向devops-infra本地 mirror/relay 的v0.2-gitops:deploy/gitops/g14/runtime-v02,sync revision 与目标 GitOps revision 对齐。hwlab-v02中长驻 workload ready,没有把 DEV/PROD namespace 当成v0.2通过证据。gitops-promote推送本地 mirror/relay 的v0.2-gitops后应触发argocd/hwlab-g14-v02hard refresh,减少 GitOps push 与 Argo 仓库发现之间的漂移窗口;refresh 触发失败只作为低噪声事件输出,最终通过仍由runtime-ready判定。- mirror/relay status 必须能显示本地
v0.2-gitopsrevision、GitHub 已 flush revision、pending flush revision 和最近一次 flush 错误;CI 通过不要求 GitHub flush 已完成,但 auto-CD 收口必须在pendingFlush=true时触发 flush 并最终观察到pendingFlush=false。 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-infragit mirror/cache miss、commit ancestry 拒绝或 boot script 校验失败必须导致本轮 rollout fail closed,不得隐式回退到 GitHub 或 env image 内旧代码。http://74.48.78.17:19666/返回v0.2Cloud Web。http://74.48.78.17:19667/health/live返回v0.2runtime health,payload 中的 namespace、revision 或 runtime identity 能与hwlab-v02/v0.2对齐。trigger-current的异步 job 或--wait输出必须能显示 trigger 阶段进度;若 control-plane refresh、mirror pre-sync 或 delete/create PipelineRun 卡住,日志必须能定位阶段名和状态。- 自动 CD 回写 PR 或关联 issue 的 rollout 评论必须包含 source commit、PipelineRun、GitOps revision、planArtifacts build/reuse 摘要、Argo/runtime/public probe 状态和耗时;该评论不能替代需要用户原入口验收的问题关闭证据。
- 自动 CD 过程中 source branch 的
deploy/deploy.json不得出现commitId、serviceimage、HWLAB_COMMIT_ID、HWLAB_IMAGE或HWLAB_IMAGE_TAG回写。 - no-op env-reuse fast lane 必须输出完整证据链:
g14-ci-plan全复用、skipped-runtime-unchanged、gitops-commit/gitops-pushskipped、runtime-readyskipped。 不能只用 PipelineRunCompleted或总耗时证明没有退化。 - 真实 rollout 的
runtime-ready必须输出started、周期性progress和最终argo-refresh/argo-sync-health/workload-ready类事件;缺少这些事件时应按可见性回归处理。 - Bun 语法检查和测试入口必须分开:
bun --check <file.ts>只用于非测试 TypeScript 源文件语法/转译检查;*.test.ts、*.test.mts或其他使用test(...)的文件必须用bun test <file>或 repo-owned package script 执行。不得再用bun --check直接跑.test.ts,该命令会在测试运行器外求值并报Cannot use test outside of the test runner,这不是业务回归证据。
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.json 或 deploy/gitops/g14/runtime-v02/** 生成物。
T2
阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:查询 Argo hwlab-g14-v02,确认 source repo 为 devops-infra 本地 mirror/relay,branch/path 为 v0.2-gitops:deploy/gitops/g14/runtime-v02,destination namespace 为 hwlab-v02,sync 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/live 中 codeAgent=ready 证明 provider 鉴权通过。
T5
阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:对启用 env 容器复用的服务触发一次 code-only commit,确认 PipelineRun 标记 envChanged=false、复用上一版 env digest、catalog 与 Pod template 写入 HWLAB_BOOT_REPO、HWLAB_BOOT_COMMIT、HWLAB_BOOT_SH,runtime 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/relay,Argo 从本地 mirror/relay rollout;再执行 git-mirror flush --confirm,确认 GitHub origin/v0.2-gitops 快进到同一 revision,status 中 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 与单元测试。
T10
阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:用一个低风险 base=v0.2 PR 验证 UniDesk v02 PR monitor 的端到端链路,确认 merge 后自动触发对应 merge head 的 hwlab-v02-ci-poll-<short12>,定点 status 通过,pendingFlush=true 时自动 flush,PR 或关联 issue 评论包含 source commit、PipelineRun、GitOps revision、build/reuse 摘要、Argo/runtime/public probe 状态和耗时,且 deploy/deploy.json 没有发布产物回写。
规格的实现情况
| 规格项 | 状态 | 说明 |
|---|---|---|
| v02 独立 source/GitOps/runtime lane | 已实现 | v0.2、v0.2-gitops、hwlab-v02 和 runtime-v02 已固定。 |
| 手动 CLI trigger/pipeline/promotion | 已实现 | 通过 UniDesk trigger-current 创建 commit-pinned PipelineRun;v02 不设 CronJob,由 hwlab-v02-ci-image-publish 与 GitOps promotion 管理。 |
| PR merge 后自动 CD | 待迁移 | 目标见 #848:UniDesk CLI v02 PR monitor 合并 base=v0.2 PR 后复用 trigger-current、定点 status 和 git-mirror flush;首期不要求 GitHub webhook,也不创建 k8s CronJob。 |
| v02 runtime readiness fail-closed | 已实现 | gitops-promote 推送后触发 Argo hard refresh;runtime-ready 读取 workload Pod template source commit,timeout、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_REPO、HWLAB_BOOT_COMMIT、HWLAB_BOOT_SH;code-only rollout 复用 env image digest,只更新代码身份。 |
devops-infra git mirror/relay 加速 |
已实现/持续约束 | source/catalog/runtime checkout 读路径和 GitOps promotion 写路径均使用独立基础设施集群 mirror/relay;Argo source 指向本地 mirror,GitHub flush 由 UniDesk CLI 手动触发,不设置 CronJob。runtime namespace 不持有 GitHub deploy key,registry 保持 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_KEY,Secret 更新后必须滚动 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/live 中 codeAgent=ready、codexStdio=ready 只能证明运行时结构、二进制、workspace、token boundary 和会话 supervisor 就绪;它不证明真实 provider 鉴权可用。涉及 Code Agent 的扩容验收必须追加一次真实短连接聊天闭环:用 Prefer: respond-async 和 X-HWLAB-Short-Connection: 1 提交 /v1/agent/chat,再轮询 /v1/agent/chat/result/<traceId>,只有 status=completed 且 assistant reply 非空才算通过。
如果 trace 里出现 Authentication Fails、upstream stream error 或 codex_stdio_provider_retry,先按 profile 分层判断:deepseek profile 走 hwlab-deepseek-proxy.<namespace>.svc.cluster.local:4000/v1/responses 和 Moon Bridge;codex-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/live 的 environment、endpoint、关键 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/CD:source 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 证明可行的配置和源码。