按环境部署 Helm Chart 与 Kustomize Overlay
为 dev 和 prod 组织同一个仓库,并避开 ConfigMap 滚动发布的陷阱。
真实的应用会运行在多个环境中,这些环境之间只有细微差别:副本数、主机名、配置值。Argo CD 可以从纯 YAML、Helm chart 或 Kustomize 部署,并能自动识别文件夹使用的是哪一种。本指南展示如何用 Kustomize overlay 和 Helm values 文件,为多个环境组织同一个仓库,并介绍一个在修改配置时容易踩到的坑。本指南基于前面指南中的 webapp 示例。
选择布局:用文件夹,而不是分支
你可以把环境建模为长期存在的分支(dev、staging、main),但这会让升级变成一次次合并,也会让各环境逐渐漂移。单一分支加每个环境一个文件夹的方式更容易理解:所有环境并排可见,对其中一个的修改就是一次普通的 diff。
Kustomize 正是为此而设计:一个共享的 base,加上每个环境一个小小的 overlay,只修改有差异的部分。
构建 Kustomize base 与 overlay
webapp-config/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── dev/
│ └── kustomization.yaml
└── prod/
└── kustomization.yaml
base/kustomization.yaml 列出共享资源:
resources:
- deployment.yaml
- service.yaml
在 base/deployment.yaml 中,让容器从一个 ConfigMap 读取设置,该 ConfigMap 将由各个 overlay 生成:
envFrom:
- configMapRef:
name: webapp-config
overlays/dev/kustomization.yaml:
resources:
- ../../base
namespace: webapp-dev
replicas:
- name: webapp
count: 2
configMapGenerator:
- name: webapp-config
literals:
- HEADER=Hello from dev
overlays/prod/kustomization.yaml 与之类似,只是 namespace: webapp-prod、count: 4,并且有自己的 HEADER 值。
让每个环境对应一个 Application
Argo CD 会检测路径中的 kustomization.yaml 并为你构建。为每个环境创建一个 Application:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: webapp-dev
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/webapp-config.git
targetRevision: HEAD
path: overlays/dev
destination:
server: https://kubernetes.default.svc
namespace: webapp-dev
syncPolicy:
syncOptions:
- CreateNamespace=true
automated:
prune: true
对于 webapp-prod,修改名称、路径(overlays/prod)和命名空间,并考虑去掉 automated,这样生产环境的同步就需要人工批准。
对于 Helm,形式相同,只是来源是 chart,并且你要选择某个环境的 values 文件:
source:
repoURL: https://github.com/your-org/webapp-config.git
targetRevision: HEAD
path: charts/webapp
helm:
valueFiles:
- values-dev.yaml
valueFiles 的路径相对于 chart 文件夹,后面的文件会覆盖前面的。
有意识地处理配置变更
在某个环境中修改 HEADER 的值,然后比较两种工具的行为:
- Kustomize 会在生成的 ConfigMap 名称后附加内容哈希。新的值会产生新的 ConfigMap(
webapp-config-<hash>),并更新 Deployment 的引用,从而触发 Pod 滚动发布。旧的 ConfigMap 变成孤儿资源,所以在被清理之前应用会显示OutOfSync。启用prune: true后,它会被自动清理。 - Helm 会原地更新现有的 ConfigMap。Deployment 的 spec 没有变化,因此运行中的 Pod 保留旧值,没有任何机制通知 Argo CD 或 Kubernetes 去重启它们。
Helm 的标准解决办法是把 ConfigMap 的校验和放入 Pod 模板,这样配置变化就会改变模板并滚动 Pod。在 templates/deployment.yaml 中:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
手动重启 Deployment 也能奏效一次,但这并没有记录在 Git 中,违背了初衷。
在各环境之间升级变更
采用这种布局,升级就是一连串普通的提交。先修改 dev overlay(例如,在 overlays/dev 中运行 kustomize edit set image webapp=nginx:1.26 来升级镜像),让自动同步应用它,然后验证。接着对 overlays/prod 做同样的修改并同步,如果你保留了生产环境的把关,则手动同步。CI 流水线可以自动完成 dev 的提交,而拉取请求或审批则可以把关生产环境的提交。若要从一处管理许多集群或环境,可以了解 Argo CD 的 ApplicationSet,它能根据模板生成 Application 资源。