为什么我强烈建议你把 K8s YAML 从代码仓库里扔出去?谈谈 GitOps 的终极分工
在推进云原生落地、玩转 Kubernetes 的过程中,很多团队在上手 GitOps(以 ArgoCD 为代表) 时,都会顺理成章地做一个决定:
“既然代码要编译,YAML 清单也要部署,那把它们堆在同一个 Git 仓库(Monorepo)里不就行了?省时省力,提交代码的同时顺便把
deployment.yaml也改了,多丝滑!”
相信我,如果你现在正打算或者已经这么做了,你正在给团队埋下一个巨大的安全隐患和运维噩梦。
在真正的生产环境、尤其是对合规和安全性有极高要求的金融级环境下,GitOps 落地有一条不容妥协的黄金定律:
“CI(持续集成)与代码同行,CD(持续部署)与代码隔离。”
今天不讲云空套话,我们用最接地气的硬核干货,聊聊为什么要这么做,以及在多仓库(Multi-Repo)架构下,这套闭环自动化到底该怎么无缝跑起来。
一、 一个形象的比喻:造家具 vs 摆家具
要说透这套分工的本质,我们得先把“写代码”和“做部署”从认知上彻底拆开。
假设你买了一栋毛坯别墅(也就是你的 K8s 集群):
- 你的 Java/Quarkus 源代码:是制作家具的原材料(原木、螺丝、胶水)。
- 容器镜像(Docker Image):是根据木材在工厂里加工出来的成品沙发(比如标签为
v2的沙发)。 - Git 仓库里的 YAML 清单:是别墅的装修图纸(上面写着:“客厅正中央,摆放一个
v2号沙发”)。 - ArgoCD:则是你雇佣的装修监理(图纸管家)。
1. CI 是“造家具的” 🧬
它需要贴着代码生存(CI 与代码同行)。每次你修改了 Java 代码,CI(比如 GitHub Actions 或 GCP Cloud Build)就会启动。它拉取源码,跑单元测试,进行编译。它的终点,是把成品沙发(Docker 镜像)推送到后方仓库(Image Registry,如 GHCR)里存着。
2. CD 是“摆家具的” 🛡️
它只需要盯着图纸和现场(CD 与代码隔离)。也就是 ArgoCD 的工作,它实际上是个“瞎子”,根本看不见你的 Java 源码。它手手里只拿着那张装修图纸(Git 仓库里的 YAML 清单)。图纸上写着要用什么镜像,它就命令 K8s 集群去拉什么镜像。
如果把这两个仓库混在一起,就像是在客厅里堆满了木材、锯子和油漆,让木匠在客厅里现场锯木头。不仅把现场搞得乌烟瘴气,还极易失火。
二、 混合仓库的致命痛点:权限漏洞与“死循环”
把代码和 K8s YAML 放在同一个 Git 仓库,在玩沙盒 POC 时可能很爽,一旦上了规模,以下两个问题会立刻扇你耳光:
痛点 1:权限边界的彻底崩溃(金融合规的大忌) 👮♂️
在安全审计中,研发(Dev)与运维(Ops)必须职责分离(Separation of Duties)。
如果代码和部署清单在同一个仓库,意味着任何一个有代码提交权限的开发人员,都可以直接修改生产环境的 deployment.yaml(比如把副本数从 2 改到 200,或者修改内网环境变量)。
一旦出现误操作或恶意篡改,直接威胁生产安全。而在独立仓库架构下,开发人员只能动代码仓库,配置仓库的写权限被严格锁定在 CI 系统的 Machine Token 或者是 Tech Lead 手中。
痛点 2:把流水线烧干的“GitOps 死循环(Doom Loop)” 🔄
在完全自动化的 GitOps 闭环中,CI 打包完新镜像后,会顺便修改 YAML 里的镜像 tag,然后推回 Git,从而触发 ArgoCD 的自动拉取。
如果代码和 YAML 在同一个仓库:
- 你向
main分支 push 了 Java 代码,触发 CI。 - CI 编译成功,打出新镜像,脚本修改了同仓库下的
deployment.yaml里的镜像版本,并 push 回main分支。 - 高能预警:这次 push 动作,再次触发了 main 分支的构建钩子!
- 于是 CI 再次启动,再次编译,再次修改 YAML,再次 push……
这就是大名鼎鼎的 GitOps 死循环。即便你在流水线里写了复杂的路径排除规则(Path Filters),这种配置也极其脆弱,稍微调整一下目录结构就会再次“防线失守”。
三、 终极解耦:多仓库(Multi-Repo)协作 Pattern
为了更直观地展现这套跨仓库解耦架构的运行轨迹,我们可以通过下面这张架构图,一眼看清代码流、配置流与镜像流的无缝咬合:
既然“CI与代码同行,CD与代码隔离”,我们在实战中是如何让它们进行优雅的跨仓库联动呢?
答案是:CI 扮演“跨界邮差”,镜像 Tag(Image Tag)充当唯一的接力棒!
🏰 仓库 A:quarkus-svc-code(代码仓库)
里面只有业务代码和本地 CI 配置文件(如 .github/workflows/ci-cd.yml)。
- 工作流:
- 开发人员提交 Java 代码并 Push ➡️ 触发本地 CI 启动。
- CI 在云端完成编译、运行测试,生成
my-quarkus-svc:sha-625ba591镜像,推送到 GHCR 镜像仓库。 - 跨界魔术:在 Action 的最后一个 Step 中,利用安全的临时特权(GitHub PAT),跨仓库
git clone检出独立的配置仓库,修改里面的deployment.yaml镜像 tag 值为sha-625ba591,执行commit并git push推回配置仓库。 - 本仓库运行结束,因为本仓库没有任何新提交,100% 免疫死循环!
🏰 仓库 B:rcm-gitops-manifests(配置仓库)
里面只有纯粹的、面向多套环境(Dev/UAT/Prod)的 K8s 部署清单,不含任何 Actions 工作流。
- 工作流:
- 收到代码仓库推过来的最新
deployment.yaml变更。 - 盯着该配置仓库的 ArgoCD 被唤醒,发现图纸上的镜像 tag 变了。
- ArgoCD 自动将新图纸拉下来,下发给腾讯云/阿里云 K3s 集群,集群根据指令去 GHCR 拉取最新的镜像,滚动更新,大功告成!
- 收到代码仓库推过来的最新
四、 核心联动代码(GitHub Actions 跨仓库推送范例)
为了让大家更有体感,这里直接贴出在“代码仓库”的 CI 脚本中,如何优雅、安全地完成“跨界邮递配置”的 Step:
- name: Clone and Update GitOps Manifests Repository
run: |
# 1. 配置临时 Git 身份
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
# 2. 利用安全的 GITHUB_TOKEN/PAT 跨仓库克隆配置仓库
git clone https://x-access-token:${{ secrets.MANIFESTS_REPO_PAT }}@github.com/your-org/rcm-gitops-manifests.git
cd rcm-gitops-manifests
# 3. 跨仓库精确定位并修改部署图纸中的镜像 Tag
# 假设把 deployment.yaml 里的旧镜像 tag 换成本次构建 of Commit SHA
sed -i "s|image: ghcr.io/your-org/my-quarkus-svc:.*|image: ghcr.io/your-org/my-quarkus-svc:${{ github.sha }}|g" apps/quarkus-svc/overlays/dev/deployment.yaml
# 4. 提交并推回配置仓库,触发 ArgoCD
git add .
git commit -m "ci: deploy my-quarkus-svc with tag ${{ github.sha }} [skip ci]"
git push origin main
五、 结语:架构的优雅,源于职责的纯粹
“CI 与代码同行,专注于应用质量;CD 与代码隔离,专注于环境状态。”
通过将 CD(部署清单)从业务代码中剥离出来, we 不仅从底层物理消除了流水线死循环的隐患,更建立起了一道坚固的安全屏障。研发专注于写好代码、跑通测试;运维和管家 ArgoCD 则专注于管理集群图纸,各司其职,互不打扰。
这,才是将 GitOps 玩到炉火纯青的工业级最佳实践。
更多推荐
所有评论(0)