34 KiB
G14 GitOps CI/CD
G14 是 HWLAB 当前 DEV/PROD 原生 k8s 与 GitOps 运行面目标。G14 CI/CD 必须只作用于 G14 k3s,不接管 D601 legacy 运行面,不使用 UniDesk Code Queue 作为调度器,也不把 UniDesk backend、provider-gateway 或 microservice proxy 当作 HWLAB runtime。
目标模型
- Source of truth:业务版本以 Git source commit 为唯一身份;镜像 tag、OCI labels、runtime annotation 和 Argo CD desired state 都必须记录同一个 source commit。
- CI:Tekton 在 G14 k3s 内运行
hwlab-g14-ci-image-publishPipeline,由scripts/g14-gitops-render.mjs直接生成原生 task;最小校验固定为repo-reports-guard、g14-contract-check、codex-api-forwarder-check,随后按 component plan 做 per-service BuildKit publish 与 GitOps promote;没有CI.jsonrunner、DIND 单任务发布或 Docker fallback。 - Artifact:镜像使用 commit tag,例如
127.0.0.1:5000/hwlab/hwlab-cloud-api:<shortCommit>;digest 由 registry 返回,CI report 只作为审计证据,不作为 CD 真相。发布态 artifact catalog 由 Tekton 写入G14-gitops:deploy/artifact-catalog.dev.json。 - Branch split:
G14是源码监控分支,只保存人写源码、声明和 seed contract;G14-gitops是 Tekton promotion 写入的生成分支,保存deploy/artifact-catalog.dev.json与deploy/gitops/g14/**desired state。CI/CD 不再把 catalog promotion commit 写回G14。 - CD:Argo CD 只消费
G14-gitops:deploy/gitops/g14/runtime-dev与deploy/gitops/g14/runtime-prod的 Git desired state,不重新构建镜像,不读取 D601 状态,不获取 legacy DEV CD Lease。 - FRP:G14 DEV 通过
hwlab-dev/hwlab-g14-frpc暴露17666/17667,G14 PROD 通过hwlab-prod/hwlab-g14-prod-frpc暴露18666/18667;master frps 的deploy/frp/frps.dev.toml与实际/etc/frp/frps.toml必须同时放行这四个 G14 端口。 - 并行性:不同 source commit 的 CI build 不共享发布锁;并行安全由 immutable commit tag/digest 和 Git desired state 保证。最终运行版本由 Argo CD 当前同步的 Git revision 决定。
生成入口
scripts/g14-gitops-render.mjs 是 G14 专用转换器:
-
架构迁移时,过时的自检、预检、guard、gate 优先删除,不在旧门禁上叠加例外或复杂度;新门禁只允许覆盖明确高价值风险,必须保持最小、低噪声、易迁移。
-
直接声明 Tekton Pipeline、最小原语校验 task 和 PipelineRun 样板;不再读取
CI.json或生成ci-jsonstep。 -
读取
deploy/deploy.json与deploy/k8s/*,生成 Argo CD 可消费的 G14 runtime Kustomize path。 -
G14 Tekton 的镜像构建发布入口必须是
scripts/g14-artifact-publish.mjs;它只是集群内 Task 的 build/push helper,不做 rollout、不写 D601、不获取 legacy DEV CD Lease。旧scripts/dev-artifact-publish.mjs入口已删除;dev-cd-apply、ci-publish和旧mainJS CD 入口禁止出现在 G14 Pipeline 生成脚本和 G14 验收证据中。 -
g14-contract-check在 fresh source clone 内取当前HEAD,把 GitOps 产物渲染到mktemp -d临时目录,并立刻用同一个--source-revision执行--check;它校验 render 代码、原生 Tekton 产物生成合同和 forbidden-fragment 护栏,不依赖 source branch 预先存在deploy/gitops/g14/source.json。面向已发布 runtime 的source.json只存在于G14-gitops生成分支,作为 promotion evidence。 -
生成
hwlab-g14-branch-pollerCronJob:它使用 G14 集群内的 Git SSH Secret 轮询G14分支,按 source commit 创建确定命名的 Tekton PipelineRun。 -
生成
hwlab-g14-control-plane-reconcilerCronJob:它使用同一个 Git SSH Secret 轮询G14,运行 repo 内scripts/g14-gitops-render.mjs,并 server-side apply 生成的 Tekton RBAC、Pipeline、Poller 和 Reconciler manifests;因此 CI 控制面变化应自动进入 G14 k3s,不需要人工长期执行 render/apply。 -
默认输出到
deploy/gitops/g14/。 -
默认 GitOps 生成分支是
G14-gitops;Pipeline 成功后把本次 source commit 对应的deploy/artifact-catalog.dev.json与deploy/gitops/g14/**推送到该分支,避免把生成提交继续写回G14。 -
默认 registry prefix 是
127.0.0.1:5000/hwlab,用于 G14 单节点 k3s 的 node-local registry。 -
默认 CI/CD proxy 是 G14 本机
http://127.0.0.1:10808/socks5h://127.0.0.1:10808。Tekton CI step、BuildKit sidecar 和 publish step 都注入 proxy/no_proxy;服务镜像构建只允许通过 Pod 内 BuildKit Unix socket 直接 push 到 G14 本地 registry,不能回退到 Docker daemon、DIND 或 host Docker。 -
prepare-source和最小原语校验 task 不允许每次运行时重新apk add、apt-get install或临时下载 browser/runtime 依赖。当前固定工具镜像是127.0.0.1:5000/hwlab/hwlab-ci-node-tools:node22-alpine-v1,包含 Node 22、npm、Git、OpenSSH、curl 和 Python3。脚本启动时必须输出工具与 proxy preflight 结构化日志;缺少工具时应先重建并推送工具镜像,再修改HWLAB_G14_CI_TOOLS_IMAGE/render 默认值,不能回退到 runtime 安装。 -
G14 host 只用于 source workspace、GitOps render、k3s 控制和轻量语法/静态合同检查;不要把 host 当成浏览器执行面。低频 browser smoke 已不再属于默认 primitive CI。若确实需要一次性布局、移动端或交互验证,必须显式在 G14 k3s/Tekton 的专用 Playwright 镜像内运行,不能回退成 host 上强装 browser 的长期方案。
-
Poller、control-plane reconciler、image publish 和 GitOps promote step 都不允许每次运行时
apk add/apt-get install。当前 G14 registry 固定工具镜像是127.0.0.1:5000/hwlab/hwlab-ci-node-tools:node22-alpine-v1,包含 Node 22、npm、Git、OpenSSH、curl 和 Python3;生成的脚本只做 proxy preflight 与工具存在性检查。若需要升级工具,先在 G14 构建/推送新的工具镜像,再修改HWLAB_G14_CI_TOOLS_IMAGE/render 默认值并由 reconciler apply。 -
服务镜像构建的默认 parent/base image 不得从 Docker Hub 反复拉取。当前
node:20-bookworm-slim已镜像到 G14 registry 的 allowlist 名称:127.0.0.1:5000/hwlab/hwlab-node20-base:20-bookworm-slim,render 默认base-image和 pollerBASE_IMAGE都指向这个本地镜像。需要升级 parent image 时,先通过 G14 proxy 拉取并推送到 G14 registry,再修改HWLAB_G14_DEV_BASE_IMAGE/render 默认值;image publish step 只允许从本地 registry pull base image,且 tag 必须符合 publish gate 的hwlab-node20-base/hwlab-dev-base/hwlab-node-runtime-baseallowlist。 -
任何依赖下载阶段都必须有可观测诊断。生成的 Tekton 脚本在 npm、BuildKit base image/local registry probe 和 GitOps promote 之前输出结构化
dependency-proxy-probe、dependency-curl-probe或dependency-download-*日志,至少包含 phase、目标 URL/镜像、脱敏 proxy、首包耗时、总耗时、下载字节数和速度。CI/CD 卡在下载时,先用这些日志判断是 proxy 不可达、目标源慢、DNS/首包慢还是下载吞吐低,再决定是否切换 G14 代理节点或预热镜像;不能只凭 PipelineRun Running 时长判断业务测试失败。
常用命令:
npm run g14:gitops:render -- --source-revision <sourceCommit>
人工 source workspace 不再对 deploy/gitops/g14/** 做生成物对比;这些文件在 source 分支下是忽略的生成物,旧文件和 source.json 不是真相。需要看渲染计划时使用 npm run g14:gitops:render -- --no-write;正式发布态只看 G14-gitops、Argo Application 和 live runtime。
原生 k8s Tekton + Argo 配置面 vs 已废弃的 CI.json runner
当前 G14 已完全删除 CI.json 和 ci-json step。下面的对比只保留为迁移理由:Tekton + Argo 是唯一发布控制面;repo-local 校验已经收敛为 render 内建的少量原语 task,而不是再保留一条 shell runner 路线。
| 维度 | 原生 k8s Tekton + Argo 配置面 | 已废弃的 CI.json runner 路线 |
|---|---|---|
| 权威职责 | 构建、发布、GitOps promotion、Argo sync、runtime rollout | repo-local 静态合同、schema、focused smoke、预检命令 |
| 真相来源 | PipelineRun、TaskRun result、G14-gitops revision、Argo Application、live workload |
仓库内 CI.json 命令、runner 镜像、单个 ci-json TaskRun 日志 |
| 优点 | 控制面声明式、k8s 可观测、并行 fan-out、TaskRun result 可复用、CD 与 runtime 验收边界清楚 | 改 repo 内检查成本低、命令贴近源码、适合 source-only 合同和 focused preflight、无需每加一条检查就手写一套新 Tekton Task |
| 缺点 | render/generated/cluster 模板三层更复杂,控制面改动要等 reconciler apply 后才能验证,source 与 generated 漂移会制造噪声 | shell 包装、命令链和日志语义更脆弱;多个检查挤在一个 step 内时失败隔离差,天然不提供 GitOps desired state、Argo rollout 或 live runtime 证据 |
| 适用场景 | 需要发布真相、并发构建、artifact identity、GitOps promotion、CD rollout、live runtime 判定 | 需要 repo-local 源码检查、静态合同、快速 smoke、focused preflight,但不需要声明 runtime 期望状态 |
| 不该承担的职责 | 不应回退成 D601 legacy JS CD 或 target-side build | 不应被提升为独立 CD 路线,也不应用来替代 Argo sync、live workload ready 或公网 health |
选择规则:
- 只要问题涉及 release truth、rollout、runtime desired state、namespace workload 健康、public health 或 artifact provenance,就必须回到 Tekton + Argo 配置面。
- 只要问题仍停留在 repo-local 静态合同或 focused preflight,就把它实现成独立的原语 Tekton task;不值得长期保留的检查直接删除,而不是重新引入
CI.jsonrunner。 - 不要再创建第二套 shell 命令发布面;如果一项检查开始依赖 rollout 顺序、TaskRun results、GitOps branch、Argo revision 或 live runtime,它就必须属于 Tekton/Argo 标准路径。
Monorepo 组件计划与兼容 render
HWLAB 是 monorepo,G14 CI/CD 加速必须按组件输入判断构建和滚动,并直接依赖内建 component model、deploy/deploy.json 与 per-service artifact catalog;CI.json 已删除,不再作为任何 planner 输入。
scripts/g14-ci-plan.mjs是只读 planner,默认读取当前 workspace 的deploy/deploy.json、deploy/artifact-catalog.dev.json和scripts/src/g14-ci-plan-lib.mjs内建 component model,输出affectedServices、reusedServices、componentCommitId、componentInputHash、dockerfileHash、baseImageDigest、buildArgsHash和原因;它不得修改 deploy、catalog 或 GitOps 文件。Tektonprepare-source会先从G14-gitops注入上一轮发布态 catalog,source 分支里的 catalog 只作为 seed contract。- 服务清单兼容顺序固定为:显式
--services、deploy.services[]、deploy.k3s.serviceMappings[]、internal/protocol.SERVICE_IDS。因此旧deploy/deploy.json形态和当前完整deploy.services[]形态都必须能被 planner 识别。 - 组件边界固定由
scripts/src/g14-ci-plan-lib.mjs的内建 service-path model 定义;如需新增或调整componentPaths、sharedPaths、runtimeDeps或buildSystemPaths,直接修改 planner 库和对应测试,不再额外维护 repo-local commands/forbidden skeleton。 scripts/g14-artifact-publish.mjs默认启用组件级 lazy build:先运行 planner,再只构建/推送affectedServices,reusedServices从deploy/artifact-catalog.dev.json复用已有 sha256 digest;如果 catalog 没有可验证 digest,planner 直接把该服务列为 affected 并重新发布,不能用旧 guard 阻塞,也不能退回 Docker 或 legacy full-build 路线。scripts/g14-artifact-publish.mjs的 publish report 必须携带 planner 的 per-service 元数据;scripts/refresh-artifact-catalog.mjs只把生成的commitId、image、imageTag、digest、publishState和 component provenance 字段复制进当前 workspace 的deploy/artifact-catalog.dev.json。Tekton promotion 只把刷新后的 catalog 写入G14-gitops;deploy/deploy.json是人写的 runtime config 真相源,不得被 promotion 回写镜像身份字段。scripts/g14-gitops-render.mjs只支持混合 desired state:workload 的 container image、HWLAB_IMAGE、HWLAB_IMAGE_TAG和 pod templatesource-commit来自deploy/artifact-catalog.dev.json的 per-service artifact identity;普通 env、replica、healthPath、profile 等配置来自deploy/deploy.json。全局 GitOps metadata 仍记录本次 source commit。--legacy-source-images与HWLAB_G14_USE_DEPLOY_IMAGES=0已废弃,不得把所有 workload image 回退渲染为同一个 source commit tag。- G14 Tekton promotion 在推送
G14-gitops前,必须用 publish report 刷新 workspace 内的deploy/artifact-catalog.dev.json,然后把刷新后的 catalog 和 rendered GitOps desired state 一起提交到G14-gitops。promotion 不得自动修改或推送G14source branch,也不得自动修改deploy/deploy.json或deploy/k8s/base/workloads.yaml,这样人写配置不会和 CI 生成身份反复冲突。 - Tekton 并发化只能以 planner 输出作为输入;每个 service 都有独立 TaskRun,changed service 启动 BuildKit,unchanged service 只写 reuse result 并复用 catalog digest,且不能改 pod template,避免无意义 rollout。没有完整 per-service desired state 证据时,必须修复 planner/catalog 证据,不能使用
--full-build、--legacy-source-images、DIND 或 Docker fallback 回退。
加速判定与当前瓶颈
G14 CI/CD 加速的第一判定标准不是 PipelineRun 总耗时单点变短,而是 monorepo 组件粒度的“少构建、少滚动、可并发”是否成立。
- 触发延迟:
hwlab-g14-branch-poller固定每 1 分钟轮询G14。相对 5 分钟轮询,平均触发等待应从约 2.5 分钟降到约 0.5 分钟,最坏等待从 5 分钟降到 1 分钟。发现kubectl -n hwlab-ci get cronjob hwlab-g14-branch-poller -o jsonpath='{.spec.schedule}'不是* * * * *时,应先修 poller/reconciler,而不是手工长期创建 PipelineRun。 - 组件懒构建:docs-only、GitOps-only、poller/reconciler manifest-only 等不影响服务输入的变更,planner 应输出
affectedServices=[]、buildSkippedCount=<全部服务数>,各 service TaskRun 应写出status=reused和build-backend=reused-catalog。这类变更不应重新构建任何服务镜像,也不应把 workload image 改成当前 source commit tag。 - 并发 fan-out:per-service TaskRun 应由 Tekton/k8s scheduler 同时调度,多个 service 的 build/reuse 窗口应接近“最慢单个服务任务耗时”,而不是所有服务串行相加。reuse-only 场景的 fan-out 窗口当前基线约为十几秒;真实组件构建场景仍需按 changed service 单独记录 BuildKit 耗时和 cache hit 情况。
- CD rollout:unchanged service 必须复用
deploy/artifact-catalog.dev.json的 image/digest,pod template 不应因全局 source commit 改变而无意义滚动。手写 manifest(例如deepseek-proxy、device-agent 类辅助 workload)只要复用某个已发布服务镜像,也必须走同一个 catalog image 选择逻辑,不能直接用当前 source commit tag。 - 运行态验证:GitOps promote 成功只说明
G14-gitops分支更新;最终通过必须看 Argo Application revision、sync 状态、目标 namespace Deployment/StatefulSet ready、公网 health。Argo 还停在旧 revision 时,优先做argocd.argoproj.io/refresh=hard刷新;不要把已经推送的G14-gitops分支误判成运行面已滚动。 - Argo health 判定:
spec.suspend=true的模板型 Job 会让 Application 总 health 显示Suspended。hwlab-agent-worker-template、hwlab-cli-template这类只作为手动启动模板的 Job 必须带argocd.argoproj.io/ignore-healthcheck: "true",避免 DEV 实际 workload 全部 ready 时仍被误判为 Suspended;真正发布验收仍以长驻 workload ready、公网 health 和失败 Pod 清单为准。
当前仍然慢的主要位置:
prepare-source与最小原语校验 task 仍是前段主要开销。它们包含 Git clone、checkout、必要的npm ci、repo-reports-guard、g14-contract-check和codex-api-forwarder-check。继续加速应优先减少 workspace cold start 与依赖安装成本,而不是重新塞回一条 shell runner。gitops-promote仍是大头,当前量级约 100 秒。它包含 source branch freshness check、artifact catalog refresh、render、cloneG14-gitops、复制 catalog 与 generated desired state、commit 和 push。继续加速应优先减少 git clone/push 成本,例如使用浅 clone、持久 workspace、server-side patch 或把 GitOps repo 操作单独缓存。- per-service TaskRun 数量增加后会有 k8s 调度和 sidecar 生命周期开销。reuse-only 任务很快,但如果每个 unchanged service 都启动完整 buildkit sidecar,调度开销会抵消部分收益;长期目标是让 unchanged service 走更轻量的 reuse Task,changed service 才启动 BuildKit。
- per-service BuildKit 必须使用 Pod 内 Unix socket 或其他 Pod-scoped 端点,禁止在 hostNetwork 下绑定固定 TCP 端口。多个 service TaskRun 并发时,如果 sidecar 统一监听
0.0.0.0:1234,会抢同一个宿主端口,导致主 step 结果成功但 Pod phase 显示 Failed,严重污染 CI 观测。 - Argo sync/health 不是 instant。
Sync=Synced后 health 仍可能因为 replicas=0 的模板 Deployment、未排除 health 的模板 Job 或 StatefulSet 旧 revision 显示Suspended/Progressing。这时应先看实际长驻 workload ready 与具体 unhealthy resource,不要只看 Application 总 health;如果 suspended Job 只是模板资源,应修 render 注解而不是把 DEV rollout 判成失败。 - StatefulSet 旧 ordinal pod 可能长期卡在历史缺失镜像上,即使 StatefulSet 当前 template 已经修正。DEV 可按运行面热修流程删除旧 Pending pod 让 StatefulSet 按当前 template 重建;PROD namespace 需要明确 maintenance 授权后再做同类删除。
每次优化 CI/CD 都必须保留可比测量:记录 PipelineRun 总耗时、prepare-source、repo-reports-guard、g14-contract-check、codex-api-forwarder-check、plan-artifacts、per-service fan-out 起止窗口、collect-artifacts、gitops-promote、Argo sync 到 workload ready 的时间,并标明本轮是 reuse-only、单组件 build 还是多组件 build。没有这些分段数据,不要只用“感觉变快/变慢”判断优化成败。
Code Agent Provider Profiles
G14 Code Agent 通过同一个 repo-owned Codex app-server stdio runner 承载多个 OpenAI-compatible Responses profile。Cloud Web 每次请求都发送 providerProfile,后端按 profile 生成本次请求的 env overlay;不得把某一个模型通道硬写死到全局运行态而删除另一个通道。
| Profile | 默认 | Model | Base URL | 说明 |
|---|---|---|---|---|
deepseek |
是 | HWLAB_CODE_AGENT_DEEPSEEK_MODEL,默认 deepseek-chat |
HWLAB_CODE_AGENT_DEEPSEEK_BASE_URL,默认 http://hwlab-deepseek-proxy.<namespace>.svc.cluster.local:4000/v1/responses |
G14 集群内 DeepSeek Responses bridge;Service 4000 先进入 hwlab-deepseek-responses-bridge,再转发到同 Pod 内 Moon Bridge 4001。 |
codex-api |
否 | HWLAB_CODE_AGENT_CODEX_API_MODEL,默认 gpt-5.5 |
HWLAB_CODE_AGENT_CODEX_API_BASE_URL,G14 默认应指向同 Pod 127.0.0.1 loopback forwarder,forwarder upstream 为 hyueapi |
独立 Codex/OpenAI-compatible Responses API 通道;不得依赖 DeepSeek bridge。 |
hwlab-cloud-api 仍以 HWLAB_CODE_AGENT_PROVIDER=codex-stdio 运行。HWLAB_CODE_AGENT_MODEL 与 HWLAB_CODE_AGENT_OPENAI_BASE_URL 可作为 runtime-default 兜底,但前端默认 profile 是 deepseek,用户可以切到 codex-api。Codex app-server 启动参数必须同时设置 provider base URL、provider name、model 和 review_model,否则 Codex/DeepSeek 链路可能在模型目录或 /v1/responses 阶段退化成 model=None。G14 cloud-api 的 NO_PROXY/no_proxy 必须包含 hyueapi.com 和 .hyueapi.com;codex-api 的 hyueapi upstream 由同 Pod loopback forwarder 直连,不能被 proxy 注入污染。
G14 codex-api 不得把 http://172.26.26.227:17680/v1/responses 作为默认 base URL;该地址只保留为 D601 legacy Code Queue runner 或历史 egress 对照线索。G14 上的 codex-api 应先进入同 Pod 127.0.0.1 loopback forwarder,再由 forwarder 直连 hyueapi.com / .hyueapi.com;这两个域名必须同时进入 NO_PROXY 和 no_proxy。DeepSeek profile 可以通过集群内 bridge/Moon Bridge 转换,codex-api 不能用 DeepSeek bridge 伪装通过,也不能因为默认 profile 切到 DeepSeek 而删除或覆盖 codex-api 的独立模型、base URL、auth 和最小闭环验证。
Provider/profile 变更必须按 Code Agent Chat Readiness Runbook 的分层方法先做目标 pod 最小闭环:env/profile overlay、SecretRef/auth 结构、hyueapi direct NO_PROXY、裸 Responses API、D601 Code Queue runner 对照、loopback forwarder 对照、codex exec --json、最终 app-server stdio completed + 非空 reply。裸 HTTP/SSE 请求通过只能证明 upstream、认证和模型可用;没有 Codex CLI/app-server 通过前,不得进入正式 GitOps/CI/CD 发布,也不得把 Workbench 状态标成 DEV-LIVE reply pass。
Codex app-server 当前要求 provider wire_api="responses",不得把 DeepSeek profile 切到旧 chat wire API。DeepSeek profile 的真实 Responses 转换层固定使用 Moon Bridge;不要在 HWLAB 里手写完整 Responses-to-Chat/Anthropic 转换器,因为这会破坏 Moon Bridge 对 prompt cache、tool-result 顺序和模型目录的成熟处理。Codex 发往 /v1/responses 的请求体可能带 Content-Encoding: zstd,而 Moon Bridge 不负责解压 Codex zstd body。因此 GitOps 中的 hwlab-deepseek-proxy Pod 必须包含 repo-owned hwlab-deepseek-responses-bridge sidecar:Service 端口 4000 指向 bridge,bridge 只做 zstd request body 解压、删除 Content-Encoding/重写 Content-Length、丢弃非 function tool 类型和 Codex-style GET /v1/models 目录适配,再把请求转发给 4001 的 Moon Bridge。DeepSeek API 只接受 function tools,bridge 必须在转发前丢弃 Codex Responses 请求里的非 function tool 类型(例如 web_search、image_generation),但不得移除 shell/apply-patch 等 function tools。模型、cache、tool 调用顺序、密钥和真实推理仍由 Moon Bridge 管理;bridge 不新增业务 gate,也不得把兼容失败伪装成 SOURCE/legacy blocker。
DeepSeek proxy manifest 是 GitOps desired state 的一部分,DEV/PROD 分别生成在 runtime-dev/deepseek-proxy.yaml 和 runtime-prod/deepseek-proxy.yaml。Moon Bridge 镜像由 deploy/moonbridge/Dockerfile 从上游 ZhiYi-R/moon-bridge 固定 commit 构建,默认镜像为 G14 本地 registry 的 moonbridge:<上游短 commit>;GitHub、Google 或 Docker base image 下载必须优先使用 G14 节点本地 proxy。DeepSeek key 仍通过 hwlab-code-agent-provider/openai-api-key Secret 注入到 init container 并写入 Pod 内 emptyDir 配置文件;ConfigMap、文档、trace、health、issue 和日志不得打印 Secret 值。
Polling 触发
G14 不要求 GitHub webhook 或 GitHub Actions 配置。hwlab-ci/hwlab-g14-branch-poller CronJob 每 1 分钟通过 Git SSH 拉取 G14 HEAD,并用 source commit 的前 12 位生成 PipelineRun 名称 hwlab-g14-ci-poll-<short12>。
如果同名 PipelineRun 已存在,poller 直接跳过;如果不存在,则创建新的 PipelineRun。这样可以用 Kubernetes 原生 CronJob、ServiceAccount、RBAC 和 Tekton API 实现无 GitHub webhook 的分支监控,同时避免同一个 commit 被反复派单。历史上的 chore: promote G14 GitOps source ... source 分支生成提交已经废弃;poller 只应该看到人写 source commit。
Pipeline 的标准路径是:G14 source commit -> Tekton 原语校验 task -> commit-tagged image push 到 G14 registry -> refresh artifact catalog -> render deploy/gitops/g14/** -> push catalog 与 GitOps desired state 到 G14-gitops -> Argo CD 同步 runtime。CD 只消费已经构建好的镜像和 Git desired state,不在 Argo CD 内构建镜像。
GitOps promotion 成功只证明 G14-gitops 分支已经写入新 desired state;如果 render 改变了 Argo Application、AppProject、runtime path 或 DEV/PROD 拆分目录,必须同步检查并应用 deploy/gitops/g14/argocd/project.yaml、application-dev.yaml 和 application-prod.yaml。hwlab-g14-dev 必须指向 deploy/gitops/g14/runtime-dev,hwlab-g14-prod 必须指向 deploy/gitops/g14/runtime-prod;如果集群里 Application 仍指向旧 deploy/gitops/g14/runtime,Argo 会停在旧 revision,即使 CI/publish/promote 全部成功也不会滚动新镜像。
观察 PipelineRun、Argo 和 rollout 时使用短连接轮询:一次 kubectl get 或有限 logs --tail 后返回,由指挥侧间隔重试。不要用长时间 kubectl wait --timeout=900s 占住 tran G14:k3s 透传锁;如果误用长 wait,只能杀掉本地等待客户端并清理 stale tran lock,不能把这个等待过程当成 CD 失败。
下载阶段排障命令:
KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n hwlab-ci logs pod/<pipelinerun-task-pod> --all-containers --tail=400 \
| grep -E 'dependency-(proxy|curl|download)'
如果 probe 显示 proxy-env-missing、proxy-connect-failed、timeout 或速度长期接近 0,应先按 /root/docs/vpn-proxy-ops.md 检查 v2rayN/Hysteria,再重跑 polling。若 probe 正常但后续校验失败,按对应 Tekton task 日志和业务检查排障。
手动 render/apply 只允许作为 bootstrap 或 reconciler 故障抢修;正常路径必须由 hwlab-g14-control-plane-reconciler 自动完成 CI 控制面 manifest 更新。
修改 scripts/g14-gitops-render.mjs、Tekton Pipeline、RBAC、poller 或 reconciler 这类 CI 控制面后,不能立刻用旧集群 PipelineRun 作为新模板验证。必须先确认 hwlab-g14-control-plane-reconciler 已完成并且集群内 Pipeline manifest 包含新字段,再触发手动 poller 或等待下一轮 source commit;否则 PipelineRun 会在旧 Pipeline 下创建,容易把已经修复的 sidecar、proxy 或 TaskRun 行为误判为仍然失败。
集群资源
hwlab-ci:registry、Tekton runner RBAC、Polling CronJob、Pipeline/PipelineRun 所在 namespace。hwlab-ci/hwlab-g14-control-plane-reconciler:自动 render/apply G14 CI 控制面 manifest 的 CronJob。argocd:Argo CD 控制面和hwlab-g14-dev/hwlab-g14-prodApplication 所在 namespace。hwlab-dev:HWLAB DEV runtime namespace,由 Argo CD 应用deploy/gitops/g14/runtime-dev。hwlab-prod:HWLAB PROD runtime namespace,由 Argo CD 应用deploy/gitops/g14/runtime-prod;通过hwlab-g14-prod-frpc映射到18666/18667,正式验收必须同时检查 Argo sync、Deployment ready、FRP public health 与 source commit。
G14 registry 由 Kubernetes Deployment hwlab-ci/hwlab-registry 承载,使用 host network 暴露 127.0.0.1:5000 给 k3s/containerd 和 host-network Tekton build pod。旧 host Docker registry 不能与该 Deployment 同时占用 5000 端口。
G14 k3s/containerd 的 Pod 镜像拉取也必须长期使用 G14 本机代理。主机配置记录在 /root/docs/kubernetes-ops.md,当前 systemd env 文件是 /etc/systemd/system/k3s.service.env。修改代理后需要 systemctl daemon-reload && systemctl restart k3s,并确认 k3s-server 进程环境中存在 HTTP_PROXY / NO_PROXY。
凭证边界
HWLAB repo 是私有仓库时,Tekton 和 Argo CD 需要各自的 Git SSH Secret。Secret 只能从 G14 本机已有 SSH key 创建,不能写入 Git,不能打印 key 内容。
Tekton 约定 Secret 名称:hwlab-ci/hwlab-git-ssh。
Argo CD 约定 repository Secret:argocd/hwlab-git-ssh,并带 label argocd.argoproj.io/secret-type=repository。
D601 边界
G14 GitOps manifests 不包含 D601 kubeconfig、D601 node guard、D601 FRP 公网入口或 UniDesk Code Queue 调度入口。D601 仍由既有生产路径维护;G14 GitOps 的安装、PipelineRun、Argo sync 和 registry 操作都不能对 D601 执行 kubectl、docker 或流量切换动作。
真相源与常见误判
G14 PR、CI、CD 的判断应按以下顺序收敛真相,越靠前越接近最终运行面:
- live runtime:目标 namespace 的 Deployment/StatefulSet template、Pod ready、
describe、容器日志和公网 health。 - Argo desired state:
hwlab-g14-dev/hwlab-g14-prod的 Application revision、sync、health 和实际 runtime path。 - Tekton 执行证据:branch-poller 日志、PipelineRun、TaskRun results、
gitops-promote终态。 - 干净 source workspace:
origin/G14当前内容,以及npm run g14:gitops:render -- --no-write和 planner 输出。 - 对照线索:旧 commit 记忆、坏 worktree、D601 legacy 路径、脚本旧默认值,只能当线索,不能当真相。
常见误判与纠正:
-
不要把
/root/hwlab当前 checkout、任意/tmpworktree 或带 conflict marker 的目录当 source truth;只有跟踪origin/G14的干净 worktree 才能作为当前发布依据。 -
不要按“某个预期 commit 是否出现在 ancestry 中”判断功能是否已经合入;当前
origin/G14实际内容比历史 commit 轨迹更重要。 -
改了 source 但没有触发 Tekton promotion 时,
G14-gitops仍停在旧 generated state 是正常现象,不等于 Tekton 或 Argo 本身坏掉。 -
不要把
build-*TaskRun 名称直接当作镜像重建证据;reuse-only 变更也会扇出同名 TaskRun,必须看 Tekton result 的status=reused与build-backend=reused-catalog。 -
不要把
G14-gitops分支已更新误判成 DEV 或 PROD 已滚动;只有 Argo Application revision、目标 workload ready 和 live manifest 生效,才算 CD 真实通过。 -
不要把 health payload 中的镜像 commit 当成 runtime manifest commit;runtime-only 修复可能复用旧镜像,只改变 probe、env、annotation 或 sidecar 行为。
-
sidecar 监听
127.0.0.1时,Pod-IPhttpGetprobe 失败不等于 sidecar 自身 crash;必须同时对照 sidecar listen 日志和 probe target 语义。 -
真实 live smoke 超时要先排除脚本入口和 timeout 误报;健康的 Codex stdio 冷启动首 token 可能需要数十秒,10 秒级 transport timeout 不能直接判服务故障。
-
不要重新引入把多条检查挤成顶层 shell 链的 runner。旧
CI.json的a && b && c一旦直接内联到顶层 shell,就会出现前半失败但 TaskRun 继续成功的假绿;原语化 CI 的原则是每个检查保持独立 task/result,失败语义直接由 Tekton 负责。
PR -> CI -> CD 最短零误判 SOP
- 工作区与路由预检
bun scripts/cli.ts ssh G14:/root/hwlab shell 'git status --short --branch && git remote -v | sed -n "1,4p"'
/root/hwlab是固定 source workspace 和 worktree 管理入口;完成预检后,在/root/hwlab/.worktree/<task>从最新origin/G14创建任务专属 worktree,再开始本轮代码、文档、测试和提交修改。- 只有独立 worktree 跟踪正确 base 且
git status只包含本任务文件时才继续;不要在/root/hwlab根目录直接堆叠并行开发改动,也不要复用其他任务遗留 worktree。 - k3s 只走
G14:k3s;不要混用 D601 kubeconfig、master server 执行面或旧 SSH route 语法。
- Source / PR 预检
npm run g14:gitops:render -- --no-write
node scripts/g14-ci-plan.mjs --base-ref origin/G14 --target-ref HEAD --pretty
- 先看当前内容和长期参考,不按旧 commit 记忆判断“功能是否已合入”。
- GitOps、manifest、poller/reconciler、provider profile 相关改动先跑 render no-write;planner 用于判断本轮是 docs-only、reuse-only 还是需要真实构建。不要在 source 分支对 ignored generated output 跑 drift check。
- provider/profile 变更在进入 PR 或 CI 之前,先按
code-agent-chat-readiness.md做目标 Pod 最小���环;不要把完整 CI/CD 当成 transport 试错工具。
- 合并或推送到
G14
G14是 poller 的唯一 source branch。只有 source 侧检查通过后,才进入 merge 或 push。- push 被 fast-forward 拒绝时,先
fetch和rebase到最新origin/G14;不要为了抢跑 poller 强推覆盖别人的 GitOps promote 提交。
- 确认 CI 已接单
- 先看最新 branch-poller job 或日志,确认它是否识别到新的
G14HEAD。 - 再看
hwlab-ci里的 PipelineRun 是否出现hwlab-g14-ci-poll-<short12>。poller 还没创建 PipelineRun 时,不要先把问题归类为 Tekton 故障。 - 如果本轮改的是 poller、Pipeline、RBAC、reconciler 或 render 模板,先确认
hwlab-g14-control-plane-reconciler已经把新控制面 apply 进去,再用新 commit 验证。
- 确认 CI 真实通过
- 最低通过条件是:
prepare-source、repo-reports-guard、g14-contract-check、codex-api-forwarder-check、plan-artifacts、per-service fan-out、collect-artifacts、gitops-promote全部成功。 build-*fan-out 要按 result 判断 reused 还是 rebuilt;不要只看 TaskRun 名称。- reuse-only 变更的目标是
affectedServices=[]、全部 servicestatus=reused,且不触发无意义 rollout。
- 确认 CD 真实通过
- 先确认
G14-gitops头 revision 已更新,再看 Argo Application 当前 revision 是否追上该 GitOps revision。 - 然后检查目标 namespace 的 Deployment、StatefulSet、ReplicaSet、Pod ready 和失败事件。
- runtime-only 修复要直接检查 live Deployment template 是否带上新的 probe、env 或 annotation;不要只盯公网 health 里的镜像 commit。
- 做最终运行态验证
- 先看公网
/health/live,再跑 focused live smoke;业务 smoke 必须在目标运行面已经 Healthy 后进行。 - Code Agent 对话链路用
node scripts/code-agent-chat-smoke.mjs --live或显式--url http://74.48.78.17:17667/ --timeout-ms 45000;通过标准是“真实 DEV 路由 +completed+ 非空 assistant reply”,不是单纯 HTTP 200、非 JSON chunk 或 10 秒内首包。