1. 总体结论
架构方向一致,核心机制不一致。
现有体系已经具备目标流程的大部分"行为":ArgoCD 管理、Rollout 金丝雀、Traefik 权重运行时管理、业务完全隔离、基础设施独立 Application。但驱动方式是 Jenkins CLI 直连 + 运行时注入参数 的命令式(imperative)模式 ,而非目标描述的"gitops 仓库声明式 + ApplicationSet 元管理"的声明式(declarative)模式。
两者都能正常运行,但声明式是目标架构的要求。迁移的核心工作就是把命令式路径改造成声明式路径------即新建 GitOps 仓库(推荐公共单仓库,见第 9 节)、引入 ApplicationSet、让镜像 tag 成为 git 中的真实提交。
一句话可执行概述:现状能跑通目标流程的所有"行为",但"事实来源"在集群运行时而非 git;按目标改造 = 把事实来源迁移回 git。
2. 目标端到端流程(原样引用)
2.1 整体架构概览
基础设施层(Helm + Kustomize)
- Traefik、argo-rollouts-controller 使用 helm 安装,用 kustomize 做 values 覆写;
- 单独 1 个 ArgoCD Application 管理基础设施,不进 ApplicationSet。
业务层(7 个业务完全独立)
每个业务两套仓库:
- 业务代码仓库:开发写业务代码,Jenkins 在这里触发 CI
- 独立 GitOps 仓库:存放 Kustomize base + overlays/prod,包含 Rollout、两组 service、TraefikService、IngressRoute;Git 里的 TraefikService 不写流量权重。
ArgoCD 元管理
- 1 个 ApplicationSet,list 列表维护 7 个业务信息,每个指向各自独立 GitOps 仓库;
- ApplicationSet 自动生成 7 个业务 Application;template 内置忽略规则,保护 TraefikService 运行时的权重,防止 ArgoCD 回滚。
重要:ApplicationSet 只管生成 Application 对象,不处理金丝雀发布逻辑;金丝雀由 argo-rollouts controller 独立完成。
2.2 日常发布流程(只更新其中一个业务,例:app1)
全程不改动 ApplicationSet。
-
开发提交代码 → Jenkins CI 阶段
① 开发向 app1 业务代码仓库提交代码,触发 Jenkins 流水线
② Jenkins 编译、打包,生成新版本镜像推镜像仓库
③ Jenkins 只修改 app1 自己独立的 GitOps 仓库 的 overlays/prod 里的镜像 tag
④ commit 并 push 到 app1-gitops 仓库
只操作 app1 的 gitops 仓库,其他 6 个业务仓库、ApplicationSet 完全不动。
-
ArgoCD 同步阶段
① ApplicationSet 生成出来的 app1 这个 Application,检测到自己对应的 git 源发生变更
② ArgoCD 执行 kustomize 渲染,把 Rollout、service、TraefikService、IngressRoute 同步到 k8s 集群对应命名空间
③ ApplicationSet 模板自带的忽略规则生效:告诉 ArgoCD 不要干涉 TraefikService 运行时的 weight 字段,不要 selfHeal 覆盖。
-
Argo-Rollouts 金丝雀执行阶段
① argo-rollouts controller 监听到集群内 Rollout CR 的 pod 模板(镜像)发生变化,启动 canary 发布流程
② 拉起 canary 版本 Pod;控制器在集群运行时修改 TraefikService 的流量权重(例如 20%)
③ Traefik 网关读取 TraefikService 配置,把 20% 外部入口流量切到新版本
④ 进入 pause 暂停状态,等待人工确认。
此时 Git 仓库里 TraefikService 依旧没有 weight,权重只存在集群内存中。
-
人工介入
- 查看发布状态,验证新版本业务功能
- ✅ 验证正常:执行 promote,argo-rollouts 继续提升流量权重直到 100%,旧版本副本逐步缩容,发布完成。
- ❌ 发现问题:执行 abort,流量切回旧版本,销毁 canary 副本。
- 如果要永久回滚版本:再次走 Jenkins 流程,把 gitops 仓库镜像 tag 改回旧版本,完整重走一遍流程。
2.3 什么时候才要操作 ApplicationSet(元数据变更)
只有下面场景才修改 ApplicationSet:
- 新增业务:在 list 列表增加一条业务配置,apply;自动生成新的 Application。
- 删除业务:list 列表删掉对应业务条目,apply;自动删除对应 Application。
- 全局策略修改:所有业务统一改 syncPolicy、权限、忽略规则等。
修改 ApplicationSet CR 本身,会 reconcile 全部 7 个业务 Application。
业务版本迭代发布,禁止修改 ApplicationSet。
2.4 关键约束(必须遵守)
- 基础设施和业务分开,基础设施独立 Application,不要放到 ApplicationSet 中。
- 不要手动 edit 集群内 ApplicationSet 生成出来的子 Application,会被 AppSet 控制器覆盖。
- 只有经过 Traefik IngressRoute 的外部访问,才会走金丝雀流量切分;Pod 内部直连 service 不走网关,不会切流量。
- ArgoCD 要配置好所有 7 个业务 git 仓库的访问凭证,否则拉取不到资源。
- Traefik 的 apiGroup 版本要和 argo-rollouts 控制器配置匹配。
3. 现状详细分析
3.1 共享库能力地图
共享库位于 jenkins-configuration 仓库,vars → src 委托 com.pipeline.shared.PipelineEntry,对外暴露 6 个步骤:automatedPipeline、multiEnvPipeline、rollbackPipeline、dockerDigestGate、pipelineSteps、supplyChainEvidence。
部署层支持 3 条路径 ,由 RuntimeDeploymentExecutor.deploy() 按 plan.method 分发:
| 路径 | 实现 | 说明 |
|---|---|---|
kubernetes |
DeploySteps.k8sImageDeploy |
传统 kubectl set image 直接改 Deployment |
argocd |
deployWithArgoCD() |
7 个业务当前实际使用 :创建/更新 ArgoCD Application + argocd app sync |
argo-rollouts |
deployWithArgoRollouts() |
生成 Rollout YAML 后 kubectl apply + argo rollouts promote/abort |
argocd 路径相关类:
ArgocdApplicationYamlBuilder--- 生成 Application YAML(helm source、helm.parameters、syncPolicy)ArgocdCommandBuilder--- 组装argocdCLI 命令;固定服务地址ARGO_SERVER = argocd-server.argocd.svc.cluster.local:30080(本环境 argocd-server 非默认 443 端口,需--insecure --grpc-web)ArgocdCommandRunner--- 执行 create/update/sync/waitArgocdValidator/ArgocdSyncPolicy--- 校验与同步策略
3.2 ArgoCD 现有 Application 构成(实测)
集群当前 30 个 Application ,无 ApplicationSet:
api-dev api-test api-uat api-prod
core-dev core-test core-uat core-prod
edge-dev edge-test edge-uat edge-prod
gateway-dev gateway-test gateway-uat gateway-prod
notify-dev notify-test notify-uat notify-prod
web-dev web-test web-uat web-prod
worker-dev worker-test worker-uat worker-prod
(以上 7 业务 × 4 环境 = 28 个)
jenkins-configuration ← 基础设施(指向 jenkins-configuration-fixtures.git, path=helm, rev=master)
jsl-mb-go ← 基础设施(jsl-mb-go.git, path=helm, rev=master)
业务 Application 示例(api-dev):
repo= https://gitee.com/cao-weiguang_admin/api.git
path= helm
rev= dev
syncPolicy= automated { enabled: true, prune: false, selfHeal: false }
3.3 业务仓库结构(单仓库)
业务代码与 helm/ 目录(Chart + values.yaml + templates)在同一个仓库 ,如 api.git。
api 仓库 Jenkinsfile 关键配置:
groovy
@Library('jenkins-shared-library@production-ready') _
def envName(String branch) { return branch == 'master' ? 'prod' : branch }
def deployEnv = envName(env.BRANCH_NAME)
def config = [
projectName: 'api',
projectType: 'python',
deployEnv: deployEnv,
deployMethod: 'argocd',
deploy: [
appName: "api-${deployEnv}",
repoUrl: 'https://gitee.com/cao-weiguang_admin/api.git', // 业务仓库自己,不是独立 gitops 仓库
path: 'helm',
targetRevision: env.BRANCH_NAME,
imageRepository: '172.18.0.1:5000/api',
automated: false,
prune: false,
selfHeal: false
],
...
]
分支映射:master=prod,其余分支同名;多分支 job 按分支自动触发对应环境部署。
3.4 镜像 tag 注入机制(核心事实)
RuntimeDeploymentExecutor.deployWithArgoCD() 的流程:
- 构建完成后,把
image.repository与image.tag(来自DOCKER_IMAGE_TAG)拼成 helm parameters; ArgocdApplicationYamlBuilder生成 Application YAML,其中spec.source.helm.parameters携带本次镜像 tag;kubectl apply更新 Application →argocd app sync触发同步。
关键后果:
- 镜像 tag 是运行时写入 Application 的 helm 参数,业务 git 仓库里没有对应变更记录(git 中 values.yaml 仍是旧 tag);
- 因此所有业务 App 都是
selfHeal: false------目的是防止 ArgoCD 把运行时 tag 覆盖回 git 声明值。这是命令式模式的必然结果,与目标架构(声明式、可开 selfHeal)相反。
3.5 金丝雀现状
rollout.yaml位于 helm/templates 中,由 ArgoCD 渲染后同步进集群;- TraefikService 在 git 模板中不写 weight(符合目标约束③),权重由 Rollout 控制器运行时修改,Traefik 网关切外部流量;
- 每个业务 Application 已配置 ignoreDifferences,保护 TraefikService 权重与 Service selector;
- Rollout steps 为自动推进 :
ArgoRolloutsYamlBuilder默认生成setWeight 20 → pause 30s → 40 → pause 30s → 60 → pause 30s → 80 → pause 30s,没有人工确认点; - 实测中曾出现 canary 处于
Suspended(金丝雀暂停)状态,正是自动 pause 的体现------暂停后会自动继续,而非等待人工决策。
3.6 CI 触发机制现状(Multibranch + 轮询)与 Webhook 改造
现状(实测):
- Job 形态:每业务仓库 1 个 Multibranch Pipeline ,按分支自动创建子 Job(分支映射
master=prod,其余分支同名),分支内 Jenkinsfile 调用automatedPipeline; - 触发方式:轮询扫描 ------
Scan Multibranch Pipeline Triggers设置扫描间隔(如H/5 * * * *,每 5 分钟一次),提交代码后自动但非实时,最长延迟一个扫描周期; - git → Jenkins 的 webhook 触发未配置 :共享库/文档中无 Gitee webhook 触发实现,现有 webhook 配置均为飞书通知(
notifyWebhookId),与流水线触发无关。
结论:"提交代码自动触发"成立,但依赖轮询,非"提交即触发"。实时触发需引入 Webhook。
改造方案(推荐:Webhook 实时触发):
- Jenkins 安装 Gitee Plugin (码云官方,对 Multibranch 触发支持好)或 Generic Webhook Trigger(通用,任意 Git 平台);
- Multibranch Job 开启 webhook 触发入口;
- 每个 Gitee 仓库添加 WebHooks(推送事件),回调 Jenkins:
- Gitee Plugin:
http://<jenkins-host>/gitee-project/webhook(或插件端点); - GWT:
http://<jenkins-host>/generic-webhook-trigger/invoke?token=<job-token>;
- Gitee Plugin:
- 网络要求:Gitee 服务器需能回调 Jenkins(公网/反代 + HTTPS),token 鉴权防刷。
备选方案(仅过渡) :轮询间隔调小(H/1 * * * *)。缺点:仍非实时;1000 个 Job 时每个周期全量 git 扫描,开销爆炸,不可作为终态。
1000 业务规模注意点:
- webhook 配置本身也要批量:1000 个仓库手点不现实,建议脚本/CMDB 批量创建(与 ApplicationSet list 用脚本生成同一套路);
- 触发粒度:webhook 回调携带仓库标识,只触发对应 Multibranch Job(Gitee 插件按仓库路由),避免全量扫描;
- 与目标架构配合:webhook 触发只解决"CI 实时性";CD 侧(ArgoCD)的实时性靠 GitOps 仓库 webhook,两者独立配置。
4. 现状 vs 目标逐项对比
| # | 维度 | 现状(实测) | 目标 | 差距 |
|---|---|---|---|---|
| 1 | 仓库结构 | 业务代码 + helm/ 单仓库 |
代码仓库 + GitOps 仓库(Kustomize,公共单仓库或独立仓库) | ❌ 需新建(推荐 1 个公共仓库,见第 9 节) |
| 2 | 渲染引擎 | Helm(values.yaml + templates) | Kustomize(base + overlays) | ❌ 需转译 |
| 3 | 镜像 tag | Jenkins 运行时注入 Application 的 helm 参数,git 无记录 | gitops 仓库 overlays/prod 中改 tag,push 即声明 | ❌ 核心差异 |
| 4 | Application 管理 | 30 个独立 App(28 业务 + 2 基础设施),无 ApplicationSet | 1 个 ApplicationSet 生成业务 App,基础设施不进 | ❌ 需迁移 |
| 5 | 忽略规则 | 28 个 App 逐个配置 ignoreDifferences | ApplicationSet template 内置 | ⚠️ 有,但分散 |
| 6 | 同步触发 | Jenkins CLI 触发 argocd app sync |
git 变更自动检测(webhook/轮询) | ❌ |
| 7 | 金丝雀人工确认 | 自动 pause: duration: 45s,无人确认 |
pause(无 duration)等人 promote/abort | ❌ 缺人工确认 |
| 8 | TraefikService git 不写 weight | ✅ 模板无 weight,运行时控制器写 | ✅ 同左 | ✅ 已符合 |
| 9 | 业务隔离 | ✅ 发布只 sync 自己应用 | ✅ 同左 | ✅ 已符合 |
| 10 | 基础设施独立 Application | ✅ 2 个独立 App 与业务分开 | ✅ 同左,不进 ApplicationSet | ✅ 已符合 |
5. 5 处核心差距详述
差距 1:无 ApplicationSet(元管理缺失)
现状 :28 个业务 App 由 Jenkins 用 argocd app create CLI 逐环境创建和维护(共享库 ArgocdCommandBuilder.createApp / ArgocdApplicationYamlBuilder 支撑),配置漂移在集群中,git 里没有单一事实来源。
影响:
- 新增/删除业务需改共享库或手动逐个建 App,无声明式入口;
- ignoreDifferences、syncPolicy 等策略要逐个 App 维护,容易不一致;
- 无法享受 AppSet 的 template 集中管理能力。
目标:1 个 ApplicationSet CR + list 列表,apply 即声明式管理全部业务 App。
差距 2:无独立 GitOps 仓库、无 Kustomize
现状 :api.git 内代码和 helm 同仓;helm templates 由共享库/开发者维护。
影响:
- 业务代码提交与部署配置变更耦合在同一次提交里,发布与代码评审不可分离;
- Helm 模板在 7 个仓库间重复复制,升级配置要逐个改;
- 没有 overlays/prod 这种"环境目录"概念,环境差异靠分支 + values 区分。
目标:GitOps 仓库(Kustomize base + overlays/{dev,test,uat,prod})承载部署配置,与代码演进解耦。仓库组织方式有两种:每业务独立仓库(强隔离)或公共单仓库(低成本,推荐,详见第 9 节)。
差距 3:镜像 tag 非声明式(核心差异)
现状 :deployWithArgoCD() 把 image.tag 作为 helm 参数运行时写入 Application ,仓库里永远是旧值;selfHeal: false 是为了防止 ArgoCD 回滚运行时 tag。
影响:
- 集群实际运行版本与 git 对不上,"谁在跑什么版本"只能查 ArgoCD UI;
- 无法通过 git 历史回滚版本;审计链路断裂;
- selfHeal 关闭,ArgoCD 的"自愈"能力被禁用。
目标:tag 是 git 里的真实提交(每次发布一条 commit),版本历史可审计、可回滚,selfHeal 可开启。
差距 4:同步靠 CLI 触发
现状 :argocd app sync 由构建 job 在流水线里执行,发布成功与否依赖 Jenkins 执行环境(凭证、网络、CLI 版本)。
影响:
- 发布入口只有"Jenkins 触发"一条路,值班同学无法独立发布;
- Jenkins 故障 = 发布通道故障。
目标 :push GitOps 仓库后 ArgoCD 自动(webhook/轮询)检测并同步,发布与 CI 解耦;Jenkins 只负责改 GitOps 仓库(tag 声明),同步由 ArgoCD 完成。
差距 5:金丝雀无人工确认
现状 :rollout steps 全是 pause: {duration: 45s} 自动过,发布全程无人干预,异常流量到了 80% 才可能被发现。
影响:
- 风险大版本(数据库迁移、破坏性变更)无法在 20% 停留验证;
- 与目标流程第 4 步"pause 等待人工确认 → promote/abort"不符。
目标:第一个 pause 无 duration,等人执行 promote/abort(交互方式见第 7 节)。
6. 已符合项确认
现有体系已满足目标架构的 4 项关键要求:
-
TraefikService git 不写 weight ✅
模板中 TraefikService 无 weight 字段,权重只由 Rollout 控制器运行时写,Traefik 网关读取后切外部流量;git 与运行时彻底分离。
-
业务完全隔离 ✅
每个业务独立仓库、独立 Application、独立 namespace,发布只 sync 自己的 App,其余 6 个业务不受影响。
-
基础设施独立 Application ✅
2 个基础设施 App(
jenkins-configuration、jsl-mb-go)与 28 个业务 App 完全分开,符合"基础设施不进 ApplicationSet"的结构意图(当前尚未引入 ApplicationSet,故天然满足)。 -
ignoreDifferences 保护权重 ✅(但分散)
各业务 App 已配置 ignoreDifferences 保护 TraefikService 权重与 Service selector;不足是配置在应用级,不集中。
7. 金丝雀人工确认:两种方式对比
| 维度 | 方式 A:Jenkins 流水线内确认 | 方式 B:kubectl/argo CLI 外部确认 |
|---|---|---|
| 交互流程 | 流水线跑到 pause 时挂起,Jenkins 界面出现【继续/中止】;点击后流水线继续跑 promote 并完成收尾(健康检查、通知) | 流水线推到 pause 后结束 ,人离开 Jenkins,在终端执行 argo rollouts promote/abort;后续提权、缩容由 Rollout 控制器自行完成 |
| 发布状态记录 | 完整留在 Jenkins 流水线视图,可回溯 | 脱离流水线,靠 kubectl argo rollouts get rollout <name> -n <ns> 查看 |
| 适合场景 | 单业务小团队、希望所有动作留痕、无独立发布平台 | 有值班平台/独立发布入口、不想让 Jenkins job 长时间占用 executor |
| 缺点 | job 长时间挂起占用构建节点;超时中断会留下"发布未完成"的中间态 | 状态不集中,人工在终端操作,对操作者 k8s 能力有要求 |
| 共享库改造量 | 中:需要 input/确认步骤 + promote/abort 封装 | 小:流水线推完即止即可,人工操作无需改动共享库 |
实质结论:两者金丝雀行为完全一致(权重推进、pause),差别只在"谁按确认键、记录在哪"。选型取决于是否有独立值班/发布平台;没有平台时,方式 A 更稳。
8. ApplicationSet 粒度方案对比
| 维度 | 方案 A:每业务 1 个 App(7 个) | 方案 B:每业务 4 个 App(28 个) |
|---|---|---|
| ApplicationSet list 条目 | 7 条(每业务 1 条) | 7 条 × generators 展开环境,或 28 条 |
| 环境区分方式 | gitops 仓库内用分支(dev/test/uat/prod),App 的 targetRevision 随环境切换 | gitops 仓库内用 overlays/dev、test、uat、prod 目录,4 个 App 各自 path 指向 |
| 优点 | list 最简,与"自动生成 7 个业务 Application"描述一致;App 数量少 | 环境相互独立,可并行发布;overlay 目录即环境声明,符合 Kustomize 惯例;targetRevision 可统一 |
| 缺点 | 一个 App 同时只有 1 个 targetRevision,多环境发布需切换分支,天然串行;分支间漂移难控制 | list 稍长;4 个环境各建 1 个 App,数量多 |
| 与现状(28 个 App)的迁移成本 | 需合并现有 28 App 的配置到 7 个,namespace/路径映射变化大 | 与现有 28 个 App 一一对应,迁移平滑 ,只需把各自 source 从 helm 改为 overlay 路径 |
建议 :优先 方案 B(28 个)。理由:①与现状 28 个 App 结构完全对齐,迁移无阵痛;②Kustomize 的 overlays 目录天然表达环境,与目标描述("overlays/prod")一致;③环境间可独立发布互不影响。若团队强烈希望 App 数量收敛到 7,再考虑方案 A。
8.1 1000 业务规模的 ApplicationSet 写法
背景:目标架构按"7 个业务、每业务独立 GitOps 仓库"描述,ApplicationSet 用 list 维护 7 条即可。业务量扩展到 1000 个时,若 1000 个业务各自用独立 GitOps 仓库(每个业务 repoURL 不同),不能使用目录生成器 (
git directories只扫描一个仓库,适用于公共单仓库),只能使用 list 或 files 两种 generator。
写法一:List generator(业务数量少时手写,1000 个时由脚本生成)
yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: business-apps
namespace: argocd
spec:
generators:
- list:
elements:
- name: app1
repoURL: https://git.example.com/gitops-app1.git
path: overlays/prod
targetRevision: main
namespace: app1-prod
- name: app2
repoURL: https://git.example.com/gitops-app2.git
path: overlays/prod
targetRevision: main
namespace: app2-prod
# ... 1000 个业务:每业务 1 行,repoURL/path/targetRevision/namespace 可各自不同
template:
metadata:
name: '{{name}}'
spec:
project: default
source:
repoURL: '{{repoURL}}'
targetRevision: '{{targetRevision}}'
path: '{{path}}'
kustomize:
images:
- 'registry.example.com/{{name}}:{{imageTag}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: false
ignoreDifferences:
- group: traefik.containo.us
kind: TraefikService
jsonPointers:
- /spec/weight
维护说明:7 个业务时手写 7 行即可;1000 个时靠人工维护容易出错,建议用脚本从 CMDB/业务清单生成这段 list,并加 CI 校验(仓库 URL 格式、path 存在性、命名空间不重复等)。
写法二:Git files generator(100+ 业务推荐,ApplicationSet 本体固定)
思路:单独建一个"元数据仓库",里面一个 JSON 描述一个业务;ApplicationSet 扫描该仓库的 JSON 文件生成 Application,业务差异全部收敛在 JSON 里:
yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: business-apps
namespace: argocd
spec:
generators:
- git:
repoURL: https://git.example.com/tenant-registry.git # 元数据仓库,只存 JSON
revision: main
files:
- path: "apps/*/config.json"
template:
metadata:
name: '{{name}}'
spec:
project: default
source:
repoURL: '{{repoURL}}'
targetRevision: '{{targetRevision}}'
path: '{{path}}'
kustomize:
images:
- 'registry.example.com/{{name}}:{{imageTag}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: false
ignoreDifferences:
- group: traefik.containo.us
kind: TraefikService
jsonPointers:
- /spec/weight
配套元数据仓库里的 JSON(tenant-registry/apps/app1/config.json):
json
{
"name": "app1",
"repoURL": "https://git.example.com/gitops-app1.git",
"path": "overlays/prod",
"targetRevision": "main",
"namespace": "app1-prod"
}
维护说明:新增业务 = 提交一个 JSON,自动生成对应 Application;删除业务 = 删 JSON;修改参数 = 改 JSON。ApplicationSet 本体约 30 行,一旦写好无需因业务增删而改动;1000 个业务的管理成本收敛为"1000 个 JSON 文件的增删改",JSON 还可按目录做 CODEOWNERS 细粒度授权。
两种写法对比
| 维度 | List generator | Git files generator |
|---|---|---|
| 业务参数自由度 | 每行完全独立 | 每个 JSON 完全独立 |
| 新增业务 | 改 ApplicationSet YAML(脚本生成) | 元数据仓库提交一个 JSON |
| 删除业务 | 改 ApplicationSet YAML | 删对应 JSON |
| 1000 个时 YAML 长度 | list 1000 行 | 固定约 30 行 |
| 权限细粒度 | 同一份 YAML 谁都能改 | JSON 按目录 CODEOWNERS |
| 推荐场景 | ≤ 几十个业务 | 100+ 业务 |
关键结论:
- 限制写法的是**"每个业务 repoURL 是否不同"**,不是业务数量:独立 GitOps 仓库 → list/files;公共单仓库 → 还可额外用目录生成器(每业务一个目录自动发现);
- 1000 个业务且配置各不相同 → 推荐 files generator;
- 两种写法都满足目标架构核心诉求:ApplicationSet 只负责生成 Application,金丝雀发布由 argo-rollouts controller 独立完成,template 内置 ignoreDifferences 保护 TraefikService 运行时权重(与方案 B 一致)。
9. GitOps 仓库组织方案评估(公共单仓库可行性)
背景:目标流程最初按"每业务独立 GitOps 仓库"描述(7 业务 = 7 仓库)。业务量增长到几十、上百时,仓库数量线性增长,带来建仓、配凭证、权限、webhook 等管理 overhead。本节评估公共单仓库(monorepo)方案。
9.1 核心认知:仓库数量 ≠ 维护成本
两类成本需要区分:
- 内容维护成本:共享 base(rollout/service/traefikservice 模板)只在 1 处维护,与仓库数量无关;
- 仓库管理成本:建仓、配凭证、权限、webhook------随仓库数线性增长。
即使每业务独立仓库,业务仓库也只是薄薄一层(几行 overlay + image tag),共享模板仍在公共 base 中;但建 N 个仓库、配 N 次凭证的 overhead 是实打实的。公共单仓库把仓库管理成本降为 O(1)。
9.2 三方案对比
| 维度 | A:每业务独立仓库 | B:公共单仓库(monorepo) | C:按域分仓(混合) |
|---|---|---|---|
| 仓库数量 | = 业务数 | 恒为 1 | 3~5 个 |
| 新增业务 | 建仓 + 配凭证 + AppSet list 加一行 | 加一个目录,git generator 自动发现 | 域内加目录 |
| 权限隔离 | ✅ 最强(每仓独立授权) | ⚠️ 弱(靠 CODEOWNERS/分支保护软隔离) | ✅ 按域隔离 |
| 爆炸半径 | ✅ 最小 | ⚠️ 一次坏 push 影响全仓 | ✅ 域内隔离 |
| 共享 base 升级 | 需跨仓传播(remote base 或额外机制) | ✅ 改一处,全业务生效 | ✅ 域内共享 |
| CD 同步触发(GitOps 仓库变更 → ArgoCD) | 每仓独立 webhook | 需 path filter(只触发对应目录) | 需 path filter |
| ArgoCD 凭证 | 每仓 1 个 | 只配 1 个 | 只配 3~5 个 |
9.3 公共单仓库目录结构
gitops/ ← 1 个仓库
├── base/ ← 共享模板(按业务类型)
└── apps/
├── api/
│ ├── kustomization.yaml ← 引用 base
│ └── overlays/{dev,test,uat,prod}/kustomization.yaml ← image tag 在此
├── core/ ...
└── web/ ...
ApplicationSet 用 git generator :扫描 apps/* 目录,每个子目录自动生成一个 Application。新业务 = 建 apps/xxx/ 目录,push,Application 自动出现------无需维护 list、建仓、配凭证。
9.4 与目标流程的映射(单仓库版零损耗)
目标流程"Jenkins 只修改 app1 独立 GitOps 仓库的 overlays/prod 的 image tag"→ 单仓库版:
Jenkins 修改
gitops/apps/app1/overlays/prod/kustomization.yaml的 image tag → push → ArgoCD 检测变更 → 只同步 app1 这一个 Application。
业务隔离靠"目录独立 + Application 独立",不靠"仓库独立";目标流程中"其余业务完全不受影响"依然成立------ArgoCD 按 Application(目录)粒度同步。
9.5 单仓库短板与缓解
| 短板 | 缓解 |
|---|---|
| 权限粗粒度 | CODEOWNERS 按目录指定 reviewer + 主分支保护 + 强制 PR 流程 |
| 坏提交影响全仓 | CI 加 kustomize build 校验门禁(PR 必须 build 通过);误操作只影响本次 sync,可回滚 |
| CI 触发粒度 | path filter,或依赖 ArgoCD 轮询(只同步变更目录对应的 App) |
9.6 按规模建议
- 7 个业务(现状):直接采用公共单仓库。改造量轻于建 7 个仓库,未来无需再迁移;
- 几十个业务:仍是单仓库,git generator 自动扩展;
- 上百业务且团队分权明显:按域拆 2~4 个仓库(infra / 平台 / 业务域),域内仍是 monorepo------既控制仓库数量,又有域级权限边界。
9.7 结论
"独立仓库"解决的是权限隔离 ,不是"管理多少业务"的必然要求;管理大量业务靠的是 ApplicationSet git generator + 目录约定。公共单仓库在本文档对应规模下是更优解:维护成本最低、共享模板升级最方便、与目标流程映射零损耗。若后续出现强团队分权需求,再按域拆仓。
10. 改动量评估
10.1 分层工作量
| 改造项 | 量级 | 具体内容 |
|---|---|---|
| 新建 GitOps 仓库(推荐 1 个公共单仓库) | 中 | 现有 helm 模板(rollout、双 service、TraefikService、IngressRoute、HPA、configmap)机械转译成 Kustomize base;apps/<业务>/overlays/{dev,test,uat,prod} 环境目录;gitee 建仓 + ArgoCD 配置仓库访问凭证(单仓库只需 1 个,目标约束④);仓库数量不随业务增长 |
| 业务代码仓库 | 小 | 删 helm/ 目录;Jenkinsfile 的 deploy 块从 path: helm 改为指向 gitops 仓库(每仓库约几行改动) |
| Jenkins 共享库 | 中(核心) | ① deployWithArgoCD 改为:构建完 clone gitops 仓库 → 改 overlays/<env>/kustomization.yaml 的 image tag → commit+push → 等 ArgoCD 同步到 Healthy;② 新增金丝雀 |