agent-skills/gitops-app-onboarding/SKILL.md
2026-04-15 18:35:55 +08:00

448 lines
15 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.

---
name: gitops-app-onboarding
description: 面向当前 Baizhi GitOps 平台的项目接入工作流,只适用于 `deploy.baizhi.cloud`、`registry.baizhi.cloud`、GitLab + Argo CD 这套固定交付模型。只要用户提到“给当前平台接入新项目”“恢复 .gitlab-ci.yml / deploy 目录”“补齐当前平台的 Helm chart / release bundle”“修当前平台的发版链路”“让应用仓库在发版时推送自己的 release 结果”,就应优先使用这个 skill如果只是通用 CI、通用 Helm 或通用 GitOps 任务而未指向当前平台,不应触发。
---
# GitOps 项目接入 Skill
## 目标
让 agent 能独立完成下面四件事:
- 生成或修复 `.gitlab-ci.yml`
- 生成或修复 `deploy/helm/<app>/`
- 生成或修复 `deploy/release/`
- 让发版链路把当前应用的发布结果同步到固定 GitOps 仓库
## 平台固定常量
除非用户明确要求修改,否则固定使用:
- GitOps 主机:`deploy.baizhi.cloud`
- Registry 主机:`registry.baizhi.cloud`
- Helm OCI 仓库:`oci://registry.baizhi.cloud/helm`
- GitOps 仓库地址:`https://deploy.baizhi.cloud/gitops-admin/argodeploy.git`
- Registry 用户名:`registry-ci`
- 共享 pull secret`registry-pull-secret`
- GitOps 控制器Argo CD
- 代码托管GitLab
GitLab CI 默认依赖这些变量:
- `GITEA_USER`
- `GITEA_TOKEN`
- `REGISTRY_PASSWORD`
## 开始前先做什么
先按这个顺序读仓库:
1. `README.md`
2. Dockerfile、包管理文件、构建脚本、已有 deploy 文件
3. 用户提供的额外设计文档
在动手前先确定:
- 组件列表
- 每个组件的构建上下文与入口
- 对外暴露方式
- 运行时配置结构
- 平台共享依赖与应用私有依赖
- 是否检测到私有 Git 依赖(例如 `git.in.chaitin.net/ai/baizhiyun/opensdk`
应用仓库自己的 `README.md` 是应用运行架构的真相来源;本 skill 只定义平台接入规则。
## 边界
- 只处理应用仓库侧接入
- 不修改与当前应用无关的 GitOps 清单
- 对 GitOps 的唯一动作,是在应用仓库 CI 中同步当前应用自己的 release 结果与版本引用
- 如果当前应用的 `Application` 已存在,只允许更新 `apps/<app>/application.yaml` 中当前应用 chart source 的 `targetRevision`
- 不修改 `AppProject`、bootstrap、其他应用的 `Application`
## 应用仓库必须产出哪些文件
### CI
- `.gitlab-ci.yml`
### Chart
- `deploy/helm/<app>/Chart.yaml`
- `deploy/helm/<app>/values.yaml`
- `deploy/helm/<app>/templates/*`
### release 作者源
- `deploy/release/metadata.yaml`
- `deploy/release/values.yaml`
- `deploy/release/secret.yaml`
## GitOps 仓库里最终应该有哪些文件
CI 导出结果固定为:
- `deploy/release/metadata.yaml` -> `releases/<app>/metadata.yaml`
- `deploy/release/values.yaml` -> `releases/<app>/values.yaml`
- `deploy/release/secret.yaml` -> `releases/<app>/manifests/secret.yaml`
- `apps/<app>/application.yaml` -> 只更新 chart source 的 `targetRevision`
固定规则:
- 不导出 `releases/<app>/secret.yaml`
- 不生成或覆盖 `db-secret.yaml``kustomization.yaml` 这类 GitOps 仓库里已有的文件
## GitLab CI 规则
### 私有 Git 依赖判定口径
下文中的“检测到私有 Git 依赖”统一指:仓库在 `go.mod`、`go.sum`、源码 import、构建脚本或 Dockerfile 构建流程中,实际引用了需要认证访问的私有 Git 仓库(例如 `git.in.chaitin.net/ai/baizhiyun/opensdk`)。
只有在检测到这类依赖时,才启用 `.netrc`、私有仓库认证,以及 `GOPRIVATE`、`GONOSUMDB`、`GONOPROXY`、`GOINSECURE`、`GIT_SSL_NO_VERIFY` 这一组私有 Go 变量;否则不要添加这些配置。
### stages
固定使用:
- `test`
- `build`
- `release`
### runner tags
只要 job 使用 Docker、DinD 或 `docker buildx`,就必须带:
- `docker`
- `network`
### test job
用途:只做测试,不改 GitOps不推镜像。
要求:
- 运行在分支和 MR 上
- 安装当前语言栈的最小依赖
- 只有检测到私有 Git 依赖时才补齐认证;否则不要引入 `.netrc`
- 使用项目原生测试入口
Go 项目默认变量写在 `.gitlab-ci.yml``variables:`
- `GOPROXY=https://goproxy.cn,direct`
- `GOSUMDB=sum.golang.google.cn`
只有检测到私有 Git 依赖时,才额外设置这些变量:
- `GOPRIVATE=git.in.chaitin.net`
- `GONOSUMDB=git.in.chaitin.net`
- `GONOPROXY=git.in.chaitin.net`
- `GOINSECURE=git.in.chaitin.net`
- `GIT_SSL_NO_VERIFY="true"`
### release 触发条件
只在 `vX.Y.Z` tag 上触发发布链路。
### build-images job
输入源码、Dockerfile、多组件构建上下文。
输出:推送到 `registry.baizhi.cloud/<app>/<component>:<version>` 的运行时镜像。
要求:
- 登录 `registry.baizhi.cloud`
- 优先使用 `docker buildx`
- 只有检测到私有 Git 依赖时,才通过 `.netrc` 和 build secret 传入;否则不要生成 `.netrc` 相关步骤
- 如需额外 CA也通过 build secret 传入
- 如果 Dockerfile 内会执行 `go mod download`、`go build` 等 Go 构建命令,必须通过 `--build-arg` 透传 Go 构建变量,不要只写在 `.gitlab-ci.yml``variables:`
- 无论是否检测到私有 Git 依赖,至少透传:`GOPROXY`、`GOSUMDB`
- 只有检测到私有 Git 依赖时,才额外透传:`GOPRIVATE`、`GONOSUMDB`、`GONOPROXY`、`GOINSECURE`
- Dockerfile 中对应变量必须有 `ARG`,并让构建命令实际使用传入值,而不是退回默认值
禁止:
- `http://registry...`
- `--plain-http`
- `--insecure-skip-tls-verify`
- 不要假设 `.gitlab-ci.yml` 中的环境变量会自动进入 `docker build` / `docker buildx build`
### package-chart job
输入:`deploy/helm/<app>/Chart.yaml`、`deploy/helm/<app>/values.yaml`、`deploy/helm/<app>/templates/*`
输出:推送到 `oci://registry.baizhi.cloud/helm` 的 Chart 包。
要求:
- `helm registry login registry.baizhi.cloud`
- 在临时目录复制 `deploy/helm/<app>/`
- 把复制品中的 `version``appVersion` 改成 tag 版本
- `helm package`
- `helm push`
### update-gitops-repo job
输入:`deploy/release/*`、当前 tag 版本、GitOps 仓库中的 `apps/<app>/application.yaml`
输出:
- `releases/<app>/metadata.yaml`
- `releases/<app>/values.yaml`
- `releases/<app>/manifests/` 下的发布结果
- `apps/<app>/application.yaml` 中当前应用 chart source 的 `targetRevision`
处理顺序固定为:
1. 克隆 `https://${GITEA_USER}:${GITEA_TOKEN}@deploy.baizhi.cloud/gitops-admin/argodeploy.git`
2. 确保 `releases/<app>/``releases/<app>/manifests/` 存在,不要整体清空目录
3. 将应用仓库中的 `deploy/release/metadata.yaml``deploy/release/values.yaml` 复制到 GitOps 仓库的 `releases/<app>/metadata.yaml``releases/<app>/values.yaml`,覆盖已有内容
4. 保留已有的 `releases/<app>/manifests/kustomization.yaml``releases/<app>/manifests/db-secret.yaml`
5.`deploy/release/secret.yaml` 物化为 `releases/<app>/manifests/secret.yaml`
6. 替换 `releases/<app>/metadata.yaml``releases/<app>/values.yaml` 中的 `__VERSION__`
7. 更新 `apps/<app>/application.yaml` 中当前应用 chart source 的 `targetRevision`
8. 只有存在 diff 时才提交并推送 `main`
禁止:
- 在 CI 中调用 `kubectl`
- 在 CI 中调用 `argocd app sync`
- 把 hard refresh 当常规发布步骤
## Helm Chart 规则
Chart 必须反映应用的真实运行架构。
固定要求:
- 按职责拆文件,不堆一个大模板
- 模板中不硬编码生产 tag
- 所有镜像名从 values 读取
- 所有 Service 暴露方式从 values 读取
- nginx 对外 Service 固定使用 `NodePort`
- 后端 Service 只做集群内访问
- 不生成 Ingress 模板,也不保留 Ingress values
- `NodePort` 必须来自用户或平台已分配值,不能猜
- 设置 `enableServiceLinks: false`
- 支持 `imagePullSecrets`
- 环境变量注入保持可读
- 如果镜像内带 nginx / 反向代理配置upstream service 名必须与 Chart 渲染出的 Service 名一致
- 生成 chart 时要确认应用是否包含需要经 nginx 转发的静态文件;如果有,必须明确静态资源目录、挂载方式和 nginx 路由,不要只配后端 upstream
- 不要依赖 Kubernetes 不支持的 `$(OTHER_ENV)` 展开
- 对 Neo4j 这类镜像,不要注入不存在的 `NEO4J_*` 配置名,例如 `NEO4J_PASSWORD`
如果应用依赖平台 shared 之外的私有服务,必须明确表达依赖来源:
- 要么由 Chart 生成应用自带资源
- 要么明确引用用户提供的外部地址
不能只留一个指向不存在服务的 host。
如果应用自带依赖同时需要业务连接口令和依赖自身启动口令Secret key 要同时表达两种消费方式,例如:
- `neo4j_password`
- `neo4j_auth`
## 对外暴露模型
固定使用:
- nginx 作为统一入口
- 对外只暴露一个 nginx `NodePort`
- 后端服务只在集群内通信
- 不生成 Ingress
`NodePort` 处理规则:
- 用户或文档已提供时直接使用
- 没提供时,在生成到这一项时立即索取
- 不要写示例端口或默认端口
## Release Bundle 规则
### `metadata.yaml`
至少包含:
- 应用名
- release 名
- namespace
- chart 名
- chart 版本
- chart 仓库
- 镜像 tag
- 源码仓库地址
### `values.yaml`
必须是可部署默认值,不是示例值。
至少满足:
- 应用自建镜像使用 `registry.baizhi.cloud/<app>/...`
- 第三方镜像保持真实来源
- Secret 名与 Chart 约定一致
- PostgreSQL 连接读取应用自己的 `databaseSecret`
- 私有镜像包含 `imagePullSecrets`
- 与 Chart schema 一致
- nginx 对外入口使用 `NodePort`
- `NodePort` 值来自用户或平台分配结果
- 不包含 Ingress 配置项
### `manifests/db-secret.yaml`
这是 deploy 仓库注册应用阶段生成的数据库源secret 名称格式为 `<app>-db` 不是应用仓库侧要生成的文件。至少包含:
- `host`
- `port`
- `database`
- `username`
- `password`
固定规则:
- chart 如果依赖 Postgres 则必须消费这个 secret
### `secret.yaml`
只放应用私有 Secretkey 名必须与 Chart 读取的 key 对齐。
规则:
- 不伪造生产值
- 外部集成凭据在生成到对应配置时逐项索取
- 应用自带私有依赖的内部口令优先自动生成
- 组合型鉴权字段优先直接写成完整 key 值
- 缺值时停在当前项继续问,不要留看似可部署的假配置
## 平台共享配置契约
`shared/` 只放平台级共享配置。
共享资源:
- `platform-runtime-config`
- `platform-shared-secrets`
- `registry-pull-secret`
`platform-runtime-config` 提供:
- `LLM_BASE_URL`
- `EMBEDDER_BASE_URL`
- `OSS_BUCKET`
`platform-shared-secrets` 提供:
- `REDIS_PASSWORD`
- `QDRANT_API_KEY`
- `OSS_ACCESS_KEY`
- `OSS_SECRET_KEY`
平台共享基础设施固定为:
- `PostgreSQL`
- `Redis`
- `Qdrant`
- `OSS`
固定 FQDN 与对象存储约定:
- `redis.infra.svc.cluster.local`
- `qdrant.infra.svc.cluster.local`
固定规则:
- 不要写成当前应用 namespace 下的裸服务名
- 不默认为 `Redis`、`Qdrant`、`OSS` 生成应用私有实例
- 如果应用当前使用的是 `MinIO` / S3 兼容配置,优先沿用现有对象存储配置结构接入平台对象存储;但不要默认假设 `MinIO` 客户端可直接连接平台 `OSS`,需根据仓库实际使用的 SDK 与平台提供的协议兼容性确认
- `Neo4j` 不属于 shared如应用需要由应用自己部署
- 不要把应用私有鉴权材料放进 `shared/`
- 如果 Chart 依赖的运行时资源不是由 Chart 直接创建,就必须确保 `releases/<app>/manifests/` 仍会把这些资源 apply 到目标 namespace
## 百智云用户鉴权接入
只有在检测到私有 Git 依赖,且该依赖就是 `git.in.chaitin.net/ai/baizhiyun/opensdk` 时才需要接入。
识别规则:
- 先按上文“私有 Git 依赖判定口径”检查仓库,再确认私有依赖中是否实际包含 `git.in.chaitin.net/ai/baizhiyun/opensdk`
- 只有确认包含这个依赖或导入时,才进入本节并索取百智云相关材料
- 如果仓库里没有这个包,就跳过整段,不要要求接入百智云,也不要生成对应配置
固定规则:
- 不要把鉴权材料放进 `shared/`
- 不要伪造生产值
- 按固定顺序逐项索取:`app_id` -> `app.crt` -> `app.key` -> `ca.crt` -> `public.key`
- 缺少哪一项,就停在那一项继续问
挂载规则:
- 固定挂载目录:`/app/ssl`
- 固定文件路径:`/app/ssl/app.crt`、`/app/ssl/app.key`、`/app/ssl/ca.crt`
- 不要改成其他自定义目录
- `public.key` 如果保留,应明确其用途,不要混同为 mTLS 必需文件
## 提问方式
- 只问当前步骤真正阻塞的值
- 逐项问,不要一次性要一大串
- 对外部集成字段,在写到对应配置时就问
- 对应用自带私有依赖内部口令,优先自动生成
- 如果当前正在等补值,回复重点只放当前这一项
## 执行顺序
按下面顺序推进:
1. 读 README 与构建文件
2. 梳理组件、依赖、暴露模型
3. 生成或修复 `.gitlab-ci.yml`
4. 生成或修复 Chart
5. 缺少必填值时停在当前项索取
6. 生成或修复 `deploy/release/`
7. 自检并汇报风险点
## 自检
完成后尽量执行:
- `git status --short`
- `git diff --check`
- `helm template`(前提是 Chart 与 values 已能渲染)
至少确认:
- 接入文件齐全
- `.gitlab-ci.yml` 包含 test、镜像构建、Chart 发布、GitOps 同步
- release values 指向 `registry.baizhi.cloud`
- 第三方镜像没有被错误改写到平台 registry
- GitOps update job 指向 `https://deploy.baizhi.cloud/gitops-admin/argodeploy.git`
- CI 中没有直接调用 Argo
- 只使用 `deploy.baizhi.cloud``registry.baizhi.cloud`
- 没有使用不安全的 registry 访问方式
- 如果 `Application` 仍引用 `releases/<app>/manifests/`,该 path 在发布结果中实际存在
- 如果镜像内包含固定 upstream 配置upstream service 名与 Chart 渲染结果一致
- Neo4j 一类自带依赖的启动环境变量不依赖 `$(OTHER_ENV)` 展开
- 如果检测到的私有 Git 依赖中包含 `git.in.chaitin.net/ai/baizhiyun/opensdk`,缺少必填百智云私有配置时交互停在当前项继续索取
## 最终输出
默认按这个顺序汇报:
1. 修改了哪些文件
2. 关键决定
3. 最值得人工复核的点
## 常见错误
- 把应用私有鉴权材料放进 `shared/`
- 在 CI 里直接刷新 Argo
- 重新引入旧域名
- 使用 insecure registry 参数
- Chart 与应用真实组件不匹配
- 在生产 release values 中写示例地址
- 擅自发明新的公网 host
- 在未检测到私有 Git 依赖中的 `git.in.chaitin.net/ai/baizhiyun/opensdk` 时仍强行接入百智云
- 用户未提供必填值时伪造占位内容