仓库布局与清单
这一课你将能做到
- 设计一套以 Helm 为主的
deploy/charts + deploy/env/<env> 目录,说清「Chart 一份、环境 values 多份」如何让 PR 只碰该碰的文件
- 背出 Helm 与 Kustomize 的对比表(模板派 vs 补丁派),并知道二者都能被 Argo CD/Flux 消费
- 为密钥进 Git 选定一种替代方案(Sealed Secrets / SOPS / External Secrets),并检查示例 values 无任何明文密码
为什么要学
GitOps 不是「把 YAML 扔进仓库」就结束:目录混乱会导致 Application 难写(path 对不上)、环境差异难 diff(改一处要在三个目录间找)、新人不敢改(不知道边界在哪)。合理的布局让 PR 的 diff 就是变更本身——例如「生产副本数从 2 改 3」应该只出现 env/prod/backend-values.yaml 一行变化。本课给出本站可落地的目录树、环境差异清单、Kustomize 对照与密钥策略,为 Argo CD / Flux 配置铺路。仓库若已有 deploy/ 目录(nginx 配置、脚本),原则是 扩展而非推倒。
先建立图像
deploy/ ← 部署真相(与应用源码同库或独立 deploy 库)
├── charts/
│ ├── backend/ ← 业务 Chart(模板 + 默认 values)
│ └── platform/ ← 平台 Chart(可选,结构同理)
├── env/
│ ├── dev/
│ │ ├── backend-values.yaml
│ │ └── platform-values.yaml
│ └── prod/
│ ├── backend-values.yaml
│ └── platform-values.yaml
├── argocd/applications/ ← 控制器清单(或 flux/ 下的 GitRepository+HelmRelease)
│ ├── backend-dev.yaml
│ └── backend-prod.yaml
└── README.md ← 约定:谁改哪、密钥怎么进、tgz 是否提交
| 放这里 | 绝不放这里 |
|---|
| Chart 模板与默认 values | 环境特有的域名/副本(该进 env) |
| env 差异 values | 明文密码、TLS 私钥 |
| Application/HelmRelease 声明 | 与部署无关的大二进制 |
| 简短 README 约定 | 过时的手工操作秘籍当唯一文档 |
两大流派:
Helm :模板 + values(参数多、条件渲染、第三方生态以 Chart 为主)
Kustomize:base + overlays/patches(无模板语言,纯补丁叠加)
都能被 Argo/Flux 直接消费;团队选主路径写进 README
跟着做
步骤 1:对照仓库现有 deploy 目录
打开仓库 deploy/(有 README 先读)。记下已有内容:nginx 配置、部署脚本、环境痕迹。笔记写:「我们将 增加 charts/ 与 argocd/(或 flux/),不删除现网脚本依赖的路径」——迁移是并行演进,不是一夜切换。
步骤 2:草拟 backend 环境差异表
这张表直接映射到两份 values 文件:
| db.host | mysql.coderoadmap-dev.svc | mysql.prod.internal |
| resources | 空 | limits 500m/512Mi |
填不出差异说明结构还没想清;反过来,表里没有的键就不要出现在 env values 里(默认值归 Chart 的 values.yaml 管)。
步骤 3:写一份最小 dev values
# deploy/env/dev/backend-values.yaml
# 只覆盖与 Chart 默认不同的项;密钥不出现
replicaCount: 1
image:
repository: registry.example/coderoadmap-backend
tag: "1.0.0-dev"
db:
host: mysql.coderoadmap-dev.svc
passwordSecretName: backend-db-secret # 只引用 Secret 名
检查清单:无 password: 明文、无重复 Chart 默认值、每个键都能对应到环境差异表。prod 文件同理另写一份,不允许「注释切换」。
步骤 4:Kustomize 最小阅读(对比认知)
同样的 backend 用 Kustomize 表达长这样:
# kustomization.yaml — 组合资源并打补丁(无 Go template)
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
images:
- name: registry.example/coderoadmap-backend
newTag: 1.0.0-dev
patches:
- path: replicas-patch.yaml
笔记结论:「改镜像 tag」这种高频小变体,Kustomize 的 images 转换器非常顺手;「多环境几十个参数 + 第三方 Chart 生态」则 Helm 更合适。本站主路径选 Helm,但 Argo/Flux 都能同时吃两种格式,不必二选一斗争。
步骤 5:密钥策略三选一写进 README 草稿
| 方案 | 一句话原理 | 适合 |
|---|
| Sealed Secrets | 加密后的 Secret 可安全进 Git,集群内控制器用私钥解密 | 无现成 KMS 的小团队 |
| SOPS + age/KMS | 对 values/Secret 文件按字段加密,工具链按需解密 | 已有 KMS/PGP 体系 |
| External Secrets Operator | Git 里只声明「从 Vault/云 KMS 拉哪个密钥」,集群自动同步 | 已有 Vault/云密钥服务 |
无论哪种,README 写死同一句:「CI 不打印密钥;values 只含 Secret 名;生产 Secret 的创建/轮换走密钥流程。」本站示例用 External Secrets 思路:backend-db-secret 由 ESO 从 Vault 同步,Git 里只有名字。
步骤 6:规划 Application 与 path 对齐
预写下节课 Argo Application 将用到的字段,现在就在目录上对齐:
repoURL:本仓库地址
path:deploy/charts/backend(Chart 所在目录)
helm.valueFiles:相对 path 的 values 文件路径(相对路径解析是下节课第一高频坑,布局时心里有数)
再加一条保护:deploy/env/prod/ 写进 CODEOWNERS,要求平台组评审才能 merge——生产期望状态的变更从此有人把关。
讲清楚要点
- 因为 PR diff 要可读,所以环境差异集中在 env values,而不是复制 Chart——评审人一眼看到「这次只改了 tag」,Chart 目录长期稳定。
- 因为 Git 不是密钥保险柜,所以明文 Secret 禁止入库——历史会永久保留,删除文件不等于删除泄漏;必须用封存/外部方案。
- 因为控制器按 path 同步,所以目录稳定比炫技嵌套重要——频繁给目录改名会导致所有 Application 集体失败;path 是 API 契约。
- 因为 Helm 与 Kustomize 都能表达期望状态,所以选型看参数复杂度与团队技能——本站 Helm 为主;遇到纯补丁场景不强行模板化。
- 因为现有 deploy 脚本可能仍服务非 K8s 路径,所以 GitOps 目录应共存演进——先新增 charts/env/argocd,现网切换完成后再清理旧脚本。
- 因为 prod 与 dev 风险等级不同,所以用 CODEOWNERS/分支保护分级管控——
env/prod/ 强制评审,env/dev/ 放宽;权限结构跟随目录结构。
你可能会懵的地方
-
应用代码和 deploy 清单分一个仓库还是两个?
单库(monorepo)简单直接:改代码与改部署在同一次 PR 里评审,适合本站这类单应用为主的项目;多服务多团队时可用独立 deploy 库统一管控。无论哪种,期望状态必须版本化,tag 变更必须有清晰 PR——这是本质,库的个数是形式。
-
valueFiles 的相对路径到底相对谁?
Argo CD 中相对 spec.source.path(Chart 目录),不是仓库根。所以 deploy/charts/backend 的 Chart 引用 deploy/env/dev/backend-values.yaml 要写 ../../env/dev/backend-values.yaml。布局课提前知道这点,下节课就不踩坑。
-
charts/*.tgz 与 Chart.lock 提交吗?
与 helm-deps 课一致:要么提交(可复现、离线可用),要么 gitignore + CI helm dependency build。唯一错误姿势是两头都不管。写进 README 让全员一致。
-
Kustomize 能完全替代 Helm 吗?
简单清单可以,且没有模板学习成本;但条件渲染、复杂参数化、第三方 Chart 生态(ingress-nginx、监控栈几乎都以 Chart 分发)仍偏向 Helm。工程答案是共存:本站业务 Chart 用 Helm,个别纯补丁场景用 Kustomize,控制器两个都支持。
-
env 目录要不要也放 Secret 的 YAML?
只放 External Secrets/Sealed Secrets 这类 声明,不放明文 Secret。真正的密文由集群侧控制器生成——Git 里可读的是「策略」,不是「密钥」。
错法对照
| 错法 | 问题 | 正解 |
|---|
env/prod/ 下整份复制 Chart | 模板分叉,修 bug 三处同步 | 共享 charts/ + env values |
| 密码明文写进 values 提交 Git | 永久泄漏(历史删不掉) | Sealed/SOPS/ESO,values 只留 Secret 名 |
| 一个 values 文件用注释切换环境 | 易错、diff 不可读 | dev/prod 分文件分目录 |
| Application path 与目录频繁改名 | 同步大面积失败 | path 当 API 契约,稳定优先 |
| 一天之内砸掉旧脚本强迁 GitOps | 中断现网交付路径 | 并行新增、单应用试点、分阶段切流 |
| prod 目录无保护,任何人可 push | 绕过评审改生产 | CODEOWNERS + 分支保护 |
卡点急救
- 现象:新同事不知道「改镜像 tag 该动哪个文件」——README 顶部放一张「改 X → 编辑 Y」速查表(改 tag → env/<env>/backend-values.yaml;改部署结构 → charts/backend/templates/),并配一个真实 PR 链接当样例。
- 现象:两套环境 values 越长越像,差异看不出来——加一个脚本或 CI 步骤对
env/dev 与 env/prod 跑 helm template diff 并输出差异摘要;如果 diff 很小,警惕 prod 漏配。
- 现象:目录迁移后 Argo Application 全部报错——path 与实际目录不符;先在 UI 里看 Application 的 repository/refresh 错误信息,把 path 改回真实位置;长期靠「path 冻结」纪律避免复发。
面试常问
-
描述一个典型的 GitOps 仓库结构。
两层核心:charts/(或 manifests/)存放期望状态的模板层——Helm Chart 或 Kustomize base;env/<env>/ 存放各环境差异层——values 文件或 overlay/patch;再加 argocd/ 或 flux/ 存放控制器资源声明(Application/HelmRelease)。配套约定:prod 目录 CODEOWNERS 保护、密钥方案声明、Chart.lock 与 tgz 的提交策略。
-
Helm 和 Kustomize 的对比?
一句话:Helm 是模板引擎,Kustomize 是补丁引擎。Helm 用 Go template + values 参数化,支持条件渲染、函数、仓库分发,适合参数多的应用与第三方 Chart 生态;Kustomize 只做 YAML 叠加(base+overlay),无模板语言、学习成本低、diff 天然清晰,适合少量变体。二者可混用,Argo CD/Flux 均原生支持。
-
为什么把部署清单和应用代码放一起(或分开)?各自利弊?
同库:一次 PR 同时评审代码与部署变更,原子性强,适合应用数量少;分库:部署库权限/评审可与代码库解耦,平台团队统一管控多应用的期望状态,但「改 tag 的 PR」与「写代码的 PR」分离需要流程衔接。核心标准是期望状态必须版本化+可评审,库的形态服务于团队规模。
自测三问
- 画出本课推荐的
deploy/ 目录树,并指出「把生产镜像 tag 升级」应编辑哪个文件、diff 长什么样。
- 背出 Helm 与 Kustomize 的对比(至少 3 个维度),并说出本站主路径与理由。
- 三种密钥方案(Sealed Secrets / SOPS / External Secrets)各一句话原理?values 文件里允许保留什么、禁止出现什么?
小结一句话
用「一份 Chart + 分环境 values + 控制器清单」固定 GitOps 仓库形状;密钥走封存或外部方案、prod 目录加保护、path 保持稳定——同步配置才能写得清、审得动。
延伸