# 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-out：affected 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 rollout：Argo 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 task，runtime-ready P50 约 249s。 |
| `v0.2` pre-mirror 9-build | 27 | 391s | 92s | 92s | 9 个保留服务 build task，GitHub/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-build，source+catalog mirror | 2 | 143.5s | 37.5s | 0s | `prepare-source` 的 source clone 和 GitOps catalog lookup/fetch 都走 mirror；9 个 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.1s；GitOps catalog 读取若仍走 canonical GitHub SSH 约 9s；catalog 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/relay，GitHub 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.12s；UniDesk 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-35s；heavy build 从 120-220s 降到约 45-90s；full rebuild 预计节省 1-3m。 |
| P0 | 为服务镜像增加生成式 `.dockerignore` 或 pruned BuildKit context，排除 `.git`、prepared `node_modules`、无关 generated files 和可排除的无关 service directories。 | 降低 context transfer 和 cache invalidation。小型 build 预计节省 10-40s，heavy build 预计节省 30-90s，同时降低磁盘压力。 |
| P1 | 将 unchanged services 从 BuildKit-shaped tasks 拆出。可让 `plan-artifacts` 直接输出 catalog-backed service results，或给 reused service 使用无 sidecar 的轻量 task，changed 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 证明。
