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/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 2
selector:
matchLabels: { app: web }
template:
metadata:
labels: { app: web }
spec:
containers:
- name: web
image: myrepo/web:1.4.0
ports:
- 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: v2
name: mychart
version: 0.1.0 # Chart 自身的版本
appVersion: "1.4.0" # 应用默认版本,仅作展示用途
第二步:把变量抽进 values.yaml
# values.yaml —— 默认值,可被 -f 或 --set 覆盖
replicaCount: 2
image:
repository: myrepo/web
tag: "1.4.0"
service:
port: 8080
然后把 templates/deployment.yaml 里会变的字段换成模板引用:
apiVersion: apps/v1
kind: Deployment
metadata:
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: web
image: "{{ .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。确认没问题再真正安装:
helm install myapp ./mychart
想模拟安装但不真的提交给集群,用 --dry-run:
helm install myapp ./mychart --dry-run --debug
第四步:多环境靠「差异值」文件,而不是复制 Chart
这才是 Helm 的价值所在。生产和测试共用同一个 Chart,各自只维护一个覆盖文件:
# values-prod.yaml —— 只写和默认值不同的部分
replicaCount: 4
image:
tag: "1.4.0"
# values-test.yaml
replicaCount: 1
image:
tag: "1.5.0-rc1"
安装时用 -f 叠加,后面的覆盖前面的:
# 生产
helm install web-prod ./mychart -f values-prod.yaml
# 测试
helm install web-test ./mychart -f values-test.yaml
临时改一两个值不想建文件,用 --set:
helm upgrade web-prod ./mychart -f values-prod.yaml --set image.tag=1.4.1
覆盖优先级从低到高是:values.yaml 默认值 < -f 文件 < --set。到这一步,「两份 YAML 漂移」的问题就根治了:结构只有一份,差异一目了然。
升级与回滚:Helm 记得每一版
改完值用 upgrade 而不是重新 install:
helm upgrade web-prod ./mychart -f values-prod.yaml
Helm 会把每次 upgrade 记成一个 revision。发现新版本有问题,一条命令滚回上一版:
helm history web-prod # 看历史版本
helm rollback web-prod 1 # 回到第 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 的模板引擎,结构一份、差异分环境,装前先渲染、出事能回滚。
更多推荐
所有评论(0)