一句话总结
同一个应用要部署到 dev/staging/prod,90% 的 YAML 一样,10% 不同;
Helm 用模板 + 变量解决差异,Kustomize 用基线 + 叠加(overlay) 解决差异--前者像"填空的模具",后者像"打补丁",二者常常配合使用.
前置回顾
第 05 篇的 ApplicationSet 里出现过一行 path: overlays/{{env}}--每个环境读各自的配置目录.当时按下没表:这些"各环境的配置"到底怎么组织,才能既复用公共部分,又表达环境差异?本篇就是回答这个问题.它是 GitOps 配置仓库的"内容物"该如何编排.
问题:多环境的 YAML 该怎么管
假设一个应用要上三个环境,差异其实很少:
|
最朴素的做法:复制三份完整 YAML,各改各的.后果你大概能猜到:
- 给所有环境的 Deployment 加一个 label? -- 要在 3 个文件里改 3 遍,漏一个就不一致
- 新增一个环境 pre? -- 又复制一整套,继续手动维护
- 某次只想改 prod 的副本数,却手滑动了公共部分? -- 三个环境一起遭殃
根因和第 02 篇可复用 Workflow,第 05 篇 ApplicationSet 完全一样:重复的东西散落多处,改一处要改 N 遍,迟早不一致.Helm 和 Kustomize 是两种消除这种重复的思路.
Helm:模板化的思路
Helm 把一套 K8s 资源打包成一个 Chart.核心动作是模板渲染:YAML 里挖空,变量从 values.yaml 注入.
|
|
渲染时(helm template 或 helm install),Helm 把模板里的 {{ }} 用 values 填上,生成最终 YAML.多环境怎么办?每个环境一个 values 文件,覆盖默认值:
|
|
Helm 像简历模板的填空:模板固定了排版和栏目(姓名:,工作经历:),每个人填自己的内容(values).换个人就换一份填空内容,版式不用重做.
Helm 不止是模板:它还是个包管理器
Helm 的定位其实是"Kubernetes 的 apt/npm".除了模板化,它还带来:
- 分发与复用:Chart 可以打包推到仓库,别人
helm install一条命令就装好一整套(如helm install redis bitnami/redis)--这也是你部署第三方中间件最常用的方式 - 版本与发布(Release):每次安装/升级是一个有版本号的 Release,
helm rollback可回退 - 条件与循环:模板里能写
if/range,表达复杂逻辑(如"prod 才创建 HPA")
Helm 模板本质是对文本做替换,它并不"理解" YAML 结构.后果是:缩进错一格,变量没引号导致类型错乱,这类问题在渲染前不易察觉;模板逻辑一复杂(嵌套 if + range + 缩进控制),可读性会迅速下降.功能强大,但容易写得很"绕".
Kustomize:叠加的思路
Kustomize 走完全相反的路:没有模板,没有占位符,全是合法的纯 YAML.它的模型是 base(基线)+ overlay(叠加层).
base 放公共的,完整的,能直接 apply 的 YAML:
|
每个环境是一个 overlay,只声明"我要在 base 上打什么补丁":
|
|
Kustomize 像给照片加滤镜:原图(base)不动,每个场景套不同的滤镜层(overlay)--这张调亮一点,那张裁个边.原图始终是原图,叠加是非侵入的.
Kustomize 的最大优点:全程都是真 YAML
因为没有 {{ }} 占位符,base 和 overlay 都是合法 YAML--可以直接 kubectl apply,能被编辑器校验,能被 IDE 高亮和补全.而且 kubectl 已内置 Kustomize(-k 参数),无需额外安装工具.简单场景下,它的心智负担明显比 Helm 模板低.
怎么选:Helm vs Kustomize
| 维度 | Helm | Kustomize |
|---|---|---|
| 核心机制 | 模板 + 变量注入 | base + overlay 打补丁 |
| 文件形态 | 带 {{ }} 的模板(非合法 YAML) |
全程合法纯 YAML |
| 逻辑能力 | 强(if/range/函数) | 弱(刻意不支持逻辑) |
| 分发/包管理 | ✅ 能打包,推仓库,装第三方 | ❌ 不是包管理器 |
| 学习曲线 | 较陡(模板语法) | 平缓(就是 YAML) |
| 最适合 | 分发给他人的,可配置项多的复杂应用 | 自家应用的多环境差异管理 |
一句话经验:要把应用打包分发给别人安装,或配置项极多 → Helm;管自己应用的几个环境差异 → Kustomize.但这不是二选一--
二者结合:Helm 出模板,Kustomize 打补丁
真实世界里最常见的反而是组合使用,各取所长.典型场景:你要用一个别人发布的 Helm Chart(比如第三方中间件),但想对它做一点 Chart 本身没暴露的定制.
Kustomize 可以把"先用 Helm 渲染出 YAML,再对结果打 overlay 补丁"串成一条流水线:
|
组合管线:Helm 负责"生成基础",Kustomize 负责"环境微调"
|
回到 GitOps:ArgoCD 原生支持两者
这一篇的内容不是孤立的--它直接服务于第 05 篇.ArgoCD 的 Application 原生认识 Helm 和 Kustomize:你在 source.path 指向的目录里放的是 Chart 还是 kustomization,ArgoCD 自动用对应工具渲染后再同步.
|
于是第 05 篇 ApplicationSet 里那行 path: overlays/{{env}} 完全闭合了:ApplicationSet 为每个环境生成一个 Application,各自指向本篇的一个 overlay,ArgoCD 渲染后同步到对应集群.配置的复用(本篇)和部署的自动化(第 05 篇)在这里合成一条完整链路.
快速回顾
- 要解决的问题:多环境 90% 配置相同,10% 不同,复制多份会导致"改一处要改 N 遍,迟早不一致"
- Helm = 模板 + 变量:YAML 挖空,各环境用不同 values 文件覆盖;还是个包管理器(打包/分发/装第三方);代价是模板本质是字符串拼接,复杂后难读
- Kustomize = base + overlay:base 放公共完整 YAML,overlay 只打补丁;全程合法纯 YAML,kubectl 内置,心智负担低;但不是包管理器
- 选型:分发给他人/配置项多 → Helm;管自家应用的环境差异 → Kustomize
- 常组合:Helm 渲染基础 + Kustomize 打补丁,各取所长
- 接 GitOps:ArgoCD 原生支持二者,Application 的 path 指向 Chart 或 overlay 即自动渲染同步--闭合第 05 篇的
overlays/{{env}}
既然 Kustomize 更简单又是 kubectl 内置,为什么大家还大量用 Helm?
因为分发.当你要安装 Redis,Prometheus,Nginx Ingress 这类第三方组件时,社区几乎都以 Helm Chart 形式发布,一条 helm install 就装好,且暴露了大量可配置项.Kustomize 没有"包仓库"生态,做不了这件事.所以常见分工:装别人的东西用 Helm,管自己的环境差异用 Kustomize.
为什么 Kustomize 故意不支持 if/循环这类逻辑?
这是刻意的设计哲学.Kustomize 认为配置就该是"声明你要什么",而不是"写一段会生成配置的程序".一旦引入逻辑,YAML 就退化成模板代码,失去了"所见即所得,能直接 apply,能被工具校验"的优点.它用"能力换简单"--牺牲灵活性,换取可读性和可预测性.理解这个取舍,就明白它和 Helm 不是谁更好,而是两种价值观.
动手练习
- Helm Chart 基础:用
helm create mychart生成一个 Chart,改values.yaml的副本数,用helm template看渲染结果,再写一个values-prod.yaml覆盖它对比差异. - Kustomize overlay:用 Kustomize 写一个 base + dev/prod 两个 overlay,各自只改副本数和镜像 tag,用
kubectl kustomize overlays/prod看渲染结果. - Helm vs Kustomize 对比:对比两种方式:同样"给所有环境的 Deployment 加一个公共 label",在 Helm 里改哪,在 Kustomize 里改哪?哪个更直观?
- (进阶)组合管线:在 Kustomize 里用
helmCharts渲染一个 bitnami 的 Chart,再打一个 overlay 补丁,体验组合管线. - (串联)GitOps 集成:把你的 overlay 目录推到配置仓库,让 ArgoCD 的 Application 指向它,确认 ArgoCD 自动 kustomize 渲染并同步.