Files
pikasTech-HWLAB/docs/reference/node-cicd-performance.md
T
2026-06-08 22:19:30 +08:00

185 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# G14 CI/CD 性能分析
本文是 HWLAB G14 CI/CD 性能优化的长期参考,覆盖 `G14` source branch、`v0.2` 加法 lane、Tekton PipelineRun、per-service BuildKit 镜像发布、GitOps promotion、Argo CD sync 和 runtime health。D601 legacy CI/CD、Code Queue runner 和 host 侧临时构建路径不属于本文范围。
## 性能模型
G14 CI/CD 耗时必须按阶段测量,不能只看一个 PipelineRun 总时长:
1. Source trigger`G14` source commit 被 `hwlab-node-branch-poller` 发现。
2. Source preparation`prepare-source` clone source、checkout 精确 revision、导入最新 GitOps artifact catalog,并安装必要 npm 依赖。
3. Primitive validation`repo-reports-guard``node-contract-check``codex-api-forwarder-check` 从准备好的 workspace 并行运行。
4. Artifact planning`plan-artifacts` 根据 component input hash 和上一轮 catalog 判断 affected/reused services。
5. Per-service fan-outaffected services 通过 BuildKit 发布镜像;reused services 复用 catalog identity,不能改变 workload pod template。
6. Artifact collection`collect-artifacts` 汇总 per-service results 并验证 publish report。
7. GitOps promotion`gitops-promote` 刷新 catalog、render desired state、commit 并 push `G14-gitops`
8. Argo rolloutArgo CD 消费 `G14-gitops`,同步 runtime namespace,并让公网 health 对新 desired state 生效。
每次性能报告必须标注运行类型:
- `reuse-only`:没有服务镜像需要重建。
- `single-component-build`:一个服务镜像重建,其余服务复用。
- `multi-component-build`:多个但不是全部服务镜像重建。
- `full-rebuild`:共享输入或 build-system 输入变化导致全部服务镜像重建。
## Timing 输出合同
G14 Tekton 日志中的分段耗时统一使用 JSON 行事件:`event="node-cicd-timing"``schemaVersion="v1"``stage``status``durationMs`,并尽量携带 `pipelineRun``taskRun``task``revision``serviceId`。后续性能对比只消费这些稳定字段,不从自然语言日志里反推耗时。
当前稳定 stage 名称:`source-clone``catalog-fetch``npm-ci``buildkit-context-transfer``dependency-install``cache-import``cache-export``gitops-render``gitops-clone``gitops-commit``gitops-push``argo-refresh``workload-ready`
`argo-refresh``hwlab-dev` workload 的 `hwlab.pikastech.local/source-commit` 元数据收敛作为观测点,不要求 Tekton 跨 namespace patch Argo Application。`workload-ready``hwlab-dev` 的 Deployment/StatefulSet observed generation、ready replicas 和 updated replicas 为准;权限不足或超时必须用 `status` 明确输出,不得静默吞掉。
## 当前基线
当前 G14 pipeline 已具备关键架构优化:一分钟 source polling、组件级 lazy build、per-service fan-out、G14 本地 registry、本地 base image、BuildKit-only publish、GitOps/Argo 分离。`v0.2` 进一步引入手动 CLI trigger、专用 CI/CD source repo、`devops-infra` git mirror/relay 读写路径、env image 复用和 code-only boot commit rollout。剩余耗时主要集中在固定开销、GitOps promotion、runtime-ready 等待和镜像构建机制上。
## v0.2 实测对比
以下对比来自 G14 k3s 内 Tekton `PipelineRun`/`TaskRun` 真实对象与 prepare-source JSON timing。按成功样本分组统计,失败样本只用于诊断,不纳入端到端成功基线。`git mirror` 纯读性能用同一 CI tools image 的临时 pod 在集群内测量。
| 场景 | 成功样本 | PipelineRun P50 | `prepare-source` P50 | build wall P50 | 说明 |
| --- | ---: | ---: | ---: | ---: | --- |
| `G14` legacy full build,无 mirror | 8 | 512s | 114s | 23s | 14 个 build taskruntime-ready P50 约 249s。 |
| `v0.2` pre-mirror 9-build | 27 | 391s | 92s | 92s | 9 个保留服务 build taskGitHub/GitOps 读路径仍混在 prepare 阶段。 |
| `v0.2` mirror 9-build | 1 | 277s | 51s | 75s | source clone 走 mirror,样本量低,只作为趋势样本。 |
| `v0.2` env-reuse code-only/no-build | 3 | 172s | 49s | 0s | 8 个 task 成功、9 个 build branch skipped;只更新 boot commit/code identity。 |
| `v0.2` env-reuse code-only/no-buildsource+catalog mirror | 2 | 143.5s | 37.5s | 0s | `prepare-source` 的 source clone 和 GitOps catalog lookup/fetch 都走 mirror9 个 build branch skipped。 |
同口径 P50 加速效果:`v0.2` pre-mirror 9-build 到 env-reuse code-only 约 `2.27x``v0.2` pre-mirror 9-build 到 source+catalog mirror env-reuse code-only 约 `2.73x``v0.2` mirror 9-build 到 source+catalog mirror env-reuse code-only 约 `1.93x``G14` legacy full build 到 source+catalog mirror env-reuse code-only 约 `3.57x`。这些倍率只描述已观测的运行类型,不外推到 DB migration、Secret 变更或 runtime 架构变更。
git mirror 本身不是 50 秒级瓶颈。集群内临时 pod 对 `http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/HWLAB.git` 的早期实测结果为:`git ls-remote refs/heads/v0.2` P50 约 19ms`git clone --no-checkout` P50 约 787ms`git checkout --detach` P50 约 64ms。修复 atomic/manual sync 后,对已发布 commit 的 `git ls-remote` 为 49-53ms`git cat-file <commit>^{tree}` 为 40-43ms。Tekton `prepare-source` 的 37-65s wall time 是混合耗时,包含 entrypoint/PVC/workspace 启动、proxy/npm probe、source clone、GitOps catalog 读取、`npm ci` 和脚本收尾,不能直接归因给 mirror。
已观测的 prepare-source 内部分段:source clone 经 mirror 后约 0.9-1.1sGitOps catalog 读取若仍走 canonical GitHub SSH 约 9scatalog lookup/fetch 改走 mirror 后,`catalog-ls-remote` 为 47-58ms`catalog-fetch` 为 92-113ms`catalog-fetch` JSON timing 总计 277-348ms`npm ci --ignore-scripts` 约 15-18s;剩余为 Tekton entrypoint、PVC/workspace、探针和 shell/Node 启动固定开销。只读 catalog lookup/fetch 与 source clone 一样走 `git-read-url` mirror`v0.2` GitOps promotion 写入 `devops-infra` 本地 mirror/relayGitHub flush 异步完成,不在 CI 关键路径直接 push canonical remote。
`devops-infra` git mirror sync/flush 是 mirror 边界维护成本,不是 CI 读路径成本。mirror 不设 CronJob`trigger-current --lane v02` 会在创建 PipelineRun 前按需执行一次 bounded pre-sync`bun scripts/cli.ts hwlab g14 git-mirror sync --confirm``git-mirror flush --confirm` 只作为显式 mirror 维护或诊断入口。代表性手动 sync 样本中,Job 脚本内 total 为 12.1s,其中 GitHub fetch 4.6s、object closure validate 6.0s、publish update-ref 1.1s、fsck 0.12sUniDesk route 从创建 Job 到返回日志总计约 18.9s。这个 12-19s 不代表 mirror clone 速度,而是 GitHub SSH fetch、对象校验、Kubernetes Job 启动/轮询和日志采集的总成本。
当前滚动基线量级:
| 阶段 | 典型范围 | 说明 |
| --- | --- | --- |
| Source trigger | 0-60s 或手动触发开销 | G14 poller 每分钟运行一次,平均等待应接近 30s;`v0.2` 不设 poller,由 UniDesk 手动 trigger 自动 fetch 专用 CI/CD repo 并按需 pre-sync mirror。 |
| `prepare-source` | 37-175s | source+catalog mirror 的 code-only 样本为 37-38s;旧路径、多 build 或未优化样本可到 75-175s。当前主要固定成本已转为 Tekton/PVC/entrypoint 和 `npm ci`。 |
| Primitive validation | 每项 5-10s | source 准备后并行运行,目前不是主要瓶颈。 |
| `plan-artifacts` | 6-10s | 当前可接受,重点是保持只读和确定性。 |
| Reused service TaskRun | 每项 8-12s | fan-out wall time 接近最慢复用 task,但 unchanged services 仍会启动 build-shaped pod。 |
| Fast affected service build | 25-35s | 小型 Node 服务且 cache 命中时的常见范围。 |
| Heavy affected service build | 120-220s | 依赖面宽或重建 Codex 相关层的服务可能达到该范围。 |
| `collect-artifacts` | 8-10s | 当前可接受,主要是校验和 report assembly。 |
| `gitops-promote` | 50-105s | 主要由 render/check、GitOps clone/checkout、tree copy、commit、push 构成。 |
| Argo sync 到 DEV Healthy | 10-220s | 受 repository refresh timing 和 workload 是否真实滚动影响较大。 |
当前端到端预期范围:
| 运行类型 | PipelineRun | source commit 后到 DEV Healthy |
| --- | --- | --- |
| `reuse-only` | 3-4.5m | 3.5-6m |
| `single-component-build` | 3.2-5.5m | 4-7.5m |
| `full-rebuild` | 6-7m | 6.5-9m |
这些值是性能基线,不是发布 SLO。任何 CI/CD 优化变更都应按同一种运行类型做 before/after 对比。
## 根本原因
### Source Preparation 冷启动
`prepare-source` 每次 PipelineRun 都执行 fresh source clone、精确 checkout、GitOps catalog lookup 和 `npm ci`。当前 tools image 已避免运行时安装系统包,但没有消除每轮 npm install 成本。npm 或 GitHub 延迟上升时,后续 validation 和 build task 都会被这个共享 workspace 阻塞。
根因:source preparation 被当成无状态冷启动处理,但实际工作负载反复使用同一个小型依赖图和同一个私有仓库。
### Build Context 过宽且重复处理 Runtime 依赖
服务镜像由 `scripts/artifact-publish.mjs` 生成 Dockerfile。该 Dockerfile 安装 production npm dependencies,然后复制 `internal``cmd``scripts``web``tools``skills``deploy` 等大范围目录。per-service Tekton task 还会先把 prepared source repo 复制到 service work directory,再调用 BuildKit。
根因:BuildKit 接收到 monorepo-shaped context,并重复执行本应预烘或按服务裁剪的 dependency-layer 工作。
### Reuse 路径仍启动 Build-Shaped Pod
组件级 lazy build 已能正确把 unchanged services 标成 reused,但每个服务仍有一个带 BuildKit sidecar wiring 的 `build-*` TaskRun。reused services 会很快写出 Tekton results 并退出,但 Kubernetes 仍要承担 pod scheduling、sidecar setup、entrypoint setup 和 result collection 开销。
根因:Tekton result wiring 绑定在 service task 上,reuse 被实现为 build-shaped task 内部的快速分支,而不是更轻量的 catalog-result 路径。
### GitOps Promotion 做了完整 Workspace 工作
`gitops-promote` 做 source freshness check、artifact catalog refresh、desired state render、render check、GitOps branch clone、generated state copy、commit 和 push。这保证了 release truth 清晰,但当前 repository 和文件树操作比必要量更重。
根因:GitOps promotion 语义正确,但没有针对 shallow/sparse branch operation 或 incremental generated-state update 做优化。
### Argo Repository Discovery 带来变量延迟
`gitops-promote` push `G14-gitops` 后,Argo CD 不一定立刻发现新 revision。对于 reused-image 或小镜像变更,workload rollout 本身可能很快,repository discovery 反而变成端到端耗时里的显著部分。
根因:CI push 和 Argo refresh 是松耦合的;GitOps 仍是真相,但运行态观察会滞后于 push。
### Retention Cleanup 对排障噪声覆盖不足
retention cleaner 会删除超过保留窗口的 completed PipelineRuns,但近期 failed PipelineRuns、failed TaskRuns 和 orphan Error pods 仍可能堆在 `hwlab-ci`。这通常不会给 pipeline 增加分钟级耗时,但会拖慢诊断并制造 API/list 噪声。
根因:retention policy 更偏向长期清理,不是针对已知 bad-run burst 后的近期失败对象治理。
## 改进建议
| 优先级 | 建议 | 预期效果 |
| --- | --- | --- |
| P0 | 增加稳定的分段 timing 输出,覆盖 source clone、catalog fetch、`npm ci`、BuildKit context transfer、dependency install、cache import/export、GitOps clone、render、commit、push、Argo refresh、workload ready。 | 直接加速很小,但能让后续优化具备可比数据,避免把网络、npm、BuildKit、Argo 延迟混为一谈。 |
| P0 | 给 `prepare-source` 使用 npm dependency cache,或在 CI tools image 里预装 repo dependencies,同时保留对 `package-lock.json` 精确性的校验。 | 将 `prepare-source` 从 75-175s 降到约 35-70s。单轮 PipelineRun 预计节省 40-100s。 |
| P0 | 构建并使用包含 production `node_modules`、Codex package 和平台专用 Codex binary 的 runtime base image。 | 减少服务镜像重复依赖工作。fast build 维持约 20-35sheavy build 从 120-220s 降到约 45-90sfull rebuild 预计节省 1-3m。 |
| P0 | 为服务镜像增加生成式 `.dockerignore` 或 pruned BuildKit context,排除 `.git`、prepared `node_modules`、无关 generated files 和可排除的无关 service directories。 | 降低 context transfer 和 cache invalidation。小型 build 预计节省 10-40sheavy build 预计节省 30-90s,同时降低磁盘压力。 |
| P1 | 将 unchanged services 从 BuildKit-shaped tasks 拆出。可让 `plan-artifacts` 直接输出 catalog-backed service results,或给 reused service 使用无 sidecar 的轻量 taskchanged services 保持 BuildKit。 | reuse-only 和 single-component fan-out 预计节省 10-30s,并显著减少 sidecar/pod 噪声;主要收益是稳定性和可观测性。 |
| P1 | 优化 `gitops-promote`G14 DEV/PROD 对 `G14-gitops` 使用 shallow/sparse checkout`v0.2``devops-infra` mirror/relay 使用最小写入,并复用已 render 的输出做 check,避免复制或提交未变化的 generated paths。 | 将 `gitops-promote` 从 50-105s 降到约 20-45s。每轮 promotion 预计节省 30-60s。 |
| P1 | GitOps push 成功后触发 Argo hard refresh,再用短轮询观察 sync。 | 当 workload 本身健康时,CI succeeded 到 DEV Healthy 从 10-220s 降到约 10-60s。 |
| P1 | 扩展 failed-run retention:给 failed PipelineRuns 和 orphan Error pods 设置明确的短保留窗口,同时禁止删除 active PipelineRuns 和 runtime namespaces。 | 对 pipeline 直接加速有限,但能显著降低 bad-run burst 后的诊断噪声和 API/list 噪声。 |
| P2 | 保持一分钟 polling,除非 source-trigger wait 成为主瓶颈;在固定开销降低前不要优先引入 GitHub webhook 复杂度。 | 理论平均最多节省约 30s;当前收益低于 `prepare-source`、BuildKit 和 GitOps promotion。 |
| P2 | 在 context 和 base image 优化落地后,再调 BuildKit CPU/memory requests 与 cache export mode。 | 可能额外提升 build 10-20%,但在 build context 和 dependency layer 仍过宽时过早调资源不可靠。 |
## 高优先级改进后的预期效果
高优先级改进指 P0 项,加上 P1 的 GitOps promotion 优化和 Argo refresh coupling。它不要求改变当前 Tekton/GitOps/Argo truth model,也不需要回退到 shell runner。
预期高优先级优化后范围:
| 运行类型 | PipelineRun | source commit 后到 DEV Healthy |
| --- | --- | --- |
| `reuse-only` | 1.8-2.6m | 2.2-3.5m |
| `single-component-build` | 2.0-3.2m | 2.5-4m |
| `full-rebuild` | 3.8-5.2m | 4.3-6m |
这是第一阶段务实目标:保持当前发布真相模型,优先消除普通 PR rollout 中占比最高的固定成本。
## 全部建议落地后的预期效果
全部建议包括高优先级项、reuse task 拆分、failed-run retention 改进,以及后续 BuildKit resource tuning。
预期全部优化后范围:
| 运行类型 | PipelineRun | source commit 后到 DEV Healthy |
| --- | --- | --- |
| `reuse-only` | 1.2-1.8m | 1.5-2.5m |
| `single-component-build` | 1.6-2.6m | 2-3.2m |
| `full-rebuild` | 3-4.5m | 3.5-5m |
剩余下限是真实工作:私有 source 访问、validation、immutable image publication、GitOps truth update、Argo sync 和 live runtime health。不要为了追求亚分钟 full CI/CD 而折叠这些边界。
## 实施顺序
1. 增加低噪声 timing instrumentation。
2.`prepare-source` 增加 npm/prepared-dependency cache。
3. 构建包含依赖和 Codex binary 的 production runtime base。
4. 裁剪 BuildKit context,并增加生成式 `.dockerignore` 保护。
5. 优化 `gitops-promote` clone/render/copy/push 机制。
6. GitOps push 后触发 Argo refresh,并测量 CI-success 到 DEV-health 耗时。
7. 将 reuse path 从 BuildKit-shaped service tasks 中拆出。
8. 扩展 failed-run retention cleanup。
9. 在 build graph 变小后再调 BuildKit resources。
## 验收标准
任何优化变更只有在给出同运行类型 before/after 数据,并保持以下不变量时,才算可交付:
- Source commit 仍是唯一 artifact identity。
- 镜像仍使用 commit tag 和 digest 作为发布身份。
- G14 DEV/PROD 的 `G14-gitops``v0.2` 的本地 mirror/relay `v0.2-gitops` 仍是 Argo CD 消费的 desired-state truth。
- Unchanged services 不会因为全局 source commit 变化而滚动。
- Failed/stale PipelineRun cleanup 不触碰 `hwlab-dev``hwlab-prod`、Argo runtime state、registry storage 或 active PipelineRuns。
- Runtime success 仍由 Argo Application revision、workload readiness 和必要公网 health 证明。