三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

Helm Chart 入门实战:把一坨 K8s YAML 收敛成可传参的可复用模板

Helm Chart 入门实战:把一坨 K8s YAML 收敛成可传参的可复用模板

Helm Chart 入门实战:把一坨 K8s YAML 收敛成可传参的可复用模板

在 K8s 上部署过几个服务后,你大概率遇到过这个场景:测试环境和生产环境的 Deployment 几乎一模一样,只有镜像 tag、副本数、域名不同。于是你复制了一份 YAML,改几个字段,结果两份文件慢慢就漂移了——生产上加了个环境变量忘了同步到测试,某次故障排查半天才发现两边配置根本对不上。

Helm 就是来治这个病的:把 K8s manifest 变成带变量的模板,不同环境只维护一份「差异值」文件。这篇从一个裸 YAML 出发,一步步把它 Helm 化,讲清 Chart 的目录结构、模板语法和最容易踩的坑。

从一份重复的 YAML 说起

假设我们有个 web 服务,原始 Deployment 长这样:

# deployment.yaml —— 每个环境复制一份,改镜像、副本、域名apiVersion:apps/v1kind:Deploymentmetadata:name:webspec:replicas:2selector:matchLabels:{app:web}template:metadata:labels:{app:web}spec:containers:-name:webimage:myrepo/web:1.4.0ports:-containerPort:8080

生产要 4 个副本、镜像是1.4.0,测试要 1 个副本、镜像是1.5.0-rc1。用复制大法就会有两份几乎相同的文件。Helm 的思路是:结构只写一遍,变的部分抽成变量。

第一步:建一个 Chart 骨架

helm create mychart

生成的目录里,核心就三样(其余可以先删掉):

mychart/ ├── Chart.yaml # Chart 的元信息:名字、版本 ├── values.yaml # 默认值(变量的默认取值) └── templates/ # 带变量的 K8s manifest 模板 └── deployment.yaml
  • Chart.yaml是这个包的身份证。
  • values.yaml存所有可配置项的默认值。
  • templates/里是模板,用{{ }}引用 values。

Chart.yaml最小内容:

apiVersion:v2name:mychartversion:0.1.0# Chart 自身的版本appVersion:"1.4.0"# 应用默认版本,仅作展示用途

第二步:把变量抽进 values.yaml

# values.yaml —— 默认值,可被 -f 或 --set 覆盖replicaCount:2image:repository:myrepo/webtag:"1.4.0"service:port:8080

然后把templates/deployment.yaml里会变的字段换成模板引用:

apiVersion:apps/v1kind:Deploymentmetadata:name:{{.Release.Name}}-web# .Release.Name 是安装时指定的实例名spec:replicas:{{.Values.replicaCount}}selector:matchLabels:{app:{{.Release.Name}}-web}template:metadata:labels:{app:{{.Release.Name}}-web}spec:containers:-name:webimage:"{{ .Values.image.repository }}:{{ .Values.image.tag }}"ports:-containerPort:{{.Values.service.port}}

几个内置对象要认识:

  • .Values.xxx:读 values.yaml(或命令行覆盖)里的值。
  • .Release.Name:helm install <name>时的实例名,用它拼资源名,同一个 Chart 就能装多份而不撞名。
  • .Chart.Name:Chart 名字本身。

第三步:先渲染再安装,别盲发

Helm 最实用的习惯是装之前先看渲染结果helm template把模板 + values 算出最终 YAML 打到屏幕,不碰集群:

helm template myapp ./mychart

你会看到{{ .Release.Name }}被替换成myapp,replicas变成2。确认没问题再真正安装:

helminstallmyapp ./mychart

想模拟安装但不真的提交给集群,用--dry-run:

helminstallmyapp ./mychart --dry-run--debug

第四步:多环境靠「差异值」文件,而不是复制 Chart

这才是 Helm 的价值所在。生产和测试共用同一个 Chart,各自只维护一个覆盖文件:

# values-prod.yaml —— 只写和默认值不同的部分replicaCount:4image:tag:"1.4.0"
# values-test.yamlreplicaCount:1image:tag:"1.5.0-rc1"

安装时用-f叠加,后面的覆盖前面的:

# 生产helminstallweb-prod ./mychart-fvalues-prod.yaml# 测试helminstallweb-test ./mychart-fvalues-test.yaml

临时改一两个值不想建文件,用--set:

helm upgrade web-prod ./mychart-fvalues-prod.yaml--setimage.tag=1.4.1

覆盖优先级从低到高是:values.yaml默认值 <-f文件 <--set。到这一步,「两份 YAML 漂移」的问题就根治了:结构只有一份,差异一目了然。

升级与回滚:Helm 记得每一版

改完值用upgrade而不是重新install:

helm upgrade web-prod ./mychart-fvalues-prod.yaml

Helm 会把每次 upgrade 记成一个 revision。发现新版本有问题,一条命令滚回上一版:

helmhistoryweb-prod# 看历史版本helm rollback web-prod1# 回到第 1 版

这比手动kubectl apply旧文件靠谱得多——你不用自己保管「上一版长啥样」,Helm 替你存了。

两个新手高频坑

坑一:缩进用了 Tab。Helm 模板本质是 YAML,YAML 不认 Tab。模板里{{ }}前后的缩进必须是空格,否则helm template直接报error converting YAML

坑二:字符串数字没加引号。像镜像 tag"1.40"这种,如果 values 里写成tag: 1.40,YAML 会解析成浮点数1.4,渲染出来镜像就变成web:1.4,拉取失败。凡是可能被误判成数字/布尔的值,一律加引号:tag: "1.40"。模板里也建议image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"整体套引号。

小结

  • Helm 治的是「YAML 复制漂移」:结构写一遍进templates/,变的部分抽进values.yaml,多环境只维护差异文件。
  • 三个核心目录:Chart.yaml(身份)、values.yaml(默认值)、templates/(带{{ }}的模板)。
  • 装前先渲染:helm template/--dry-run --debug看最终 YAML,别盲发。
  • 覆盖优先级:默认值 <-f 文件<--set;多环境用多个 values 文件叠加。
  • 升级用 upgrade,出事 rollback:Helm 记录每个 revision,回滚不用自己存旧文件。
  • 两个必踩坑:模板缩进只能空格不能 Tab;像 tag 这种值一律加引号防被解析成数字。

一句话记忆:Helm = K8s YAML 的模板引擎,结构一份、差异分环境,装前先渲染、出事能回滚。

← 返回列表