diff --git a/docs/reference/spec-v02-cicd.md b/docs/reference/spec-v02-cicd.md index 9df3fed3..c2208fcf 100644 --- a/docs/reference/spec-v02-cicd.md +++ b/docs/reference/spec-v02-cicd.md @@ -136,6 +136,10 @@ Cloud Web 单元测试必须自动发现并执行 repo-owned `web/hwlab-cloud-we `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 存储后,必须重新测量并更新本表的预算口径。 | 场景 | 关键路径总耗时 | 主要阶段表现 | 判定口径 | @@ -143,7 +147,7 @@ Cloud Web 单元测试必须自动发现并执行 repo-owned `web/hwlab-cloud-we | 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 | 约 37s | `prepare-source` 约 10s;`plan-artifacts` 约 6s;`collect-artifacts` 约 7s;`gitops-promote` 约 8s;`runtime-ready` 跳过 | source-only 且 runtime identity-only 变化时的目标预算。 | +| 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。 @@ -221,12 +225,44 @@ P1 no-op runtime skip 只跳过无实际 runtime 变化的等待。planner 输 `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`。 + +```bash +bun scripts/cli.ts job status --tail-bytes 30000 +``` + +如果 trigger job stderr 没有进度事件,不要直接反复触发 CI/CD。 +先修 trigger 可见性或查询 `.state/jobs/.stderr.log`,让等待点重新暴露出来。 +mirror pre-sync 慢时看 mirror sync job 与 `git-mirror status`;PipelineRun 创建后才进入 Tekton 排障。 + 先看一次 PipelineRun 总览,确认是否是性能退化、构建退化还是 runtime 收敛失败: ```bash @@ -258,8 +294,12 @@ for task in prepare-source plan-artifacts collect-artifacts gitops-promote runti 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 "skipped-runtime-unchanged|runtime-ready-required|runtime-identity-only|g14-cicd-timing|git-operation|g14-ci-plan|artifact_reuse|buildSkippedCount|gitops-commit|gitops-push" || true + grep -E "$pattern" || true done ' ``` @@ -275,6 +315,8 @@ done | 多 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 ` 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。 | @@ -451,6 +493,10 @@ registry 与 git mirror/relay 分属不同基础设施边界。registry 保持 - `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 health,payload 中的 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-unchanged`、`gitops-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 通过。