Helm 入门 模板 值覆盖与版本管理
月下星杖
9 min read
Helm 入门 模板 值覆盖与版本管理
Helm 解决的是“同一套 K8s 资源要在多环境、多实例间复用”的问题。它把 YAML 用模板变量化,把差异收进 values,把发布当成可回滚的版本。不靠 Helm,多环境的配置只能靠复制粘贴,差异一多就失控。对需要部署几十个服务、跨三四套环境的团队,Helm 是把重复压下去、把一致性提上来的关键工具。它也让人从“手写一堆几乎相同的 YAML”里解脱出来,把注意力集中到真正不同的那几个值上。
一个 chart 的骨架
mychart/
Chart.yaml
values.yaml
charts/ # 子 chart 依赖
templates/
deployment.yaml
service.yaml
_helpers.tpl # 公共模板片段
templates/tests/ # 部署后冒烟测试
Chart.yaml 记名字和版本,values.yaml 是默认值,templates 里的 Go template 引用这些值生成最终 manifest,_helpers.tpl 放可复用的命名模板,避免每个文件重复写标签。把标签、注解这类重复块抽成 helper,是 chart 可维护的关键一步。
模板怎么写
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-app
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
template:
spec:
containers:
- name: app
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: {{ .Values.containerPort }}
.Values 来自 values.yaml,.Release.Name 是安装时给的发布名,.Chart 是 chart 元信息。{{- ... -}} 的减号用来压掉前后空白,控制渲染后的缩进,是模板里最容易写错导致 YAML 报错的地方,缩进错一格整段就废。建议本地先 helm template 渲染确认,再往集群推。
常用模板函数
光会替换变量不够,常用函数能省很多手工:
{{ .Values.name | upper }} # 转大写
{{ .Values.name | quote }} # 加引号,防 YAML 把数字当数值
{{ .Values.config | toYaml | nindent 4 }} # 把 map 整体渲染并缩进
{{ required "image.tag is missing" .Values.image.tag }} # 缺失即报错
quote 尤其重要,不加引号时 8080 会被解析成数字而非端口字符串,部署后字段类型错。required 能在渲染期直接拦下漏配,比运行时报错省事。
条件与循环
按条件生成资源、按列表展开副本,是模板减少重复的核心:
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
...
{{- end }}
{{- range .Values.extraContainers }}
- name: {{ .name }}
image: {{ .image }}
{{- end }}
if 条件写反会静默少生成资源,range 遍历空列表则什么都不出。两者都要配合默认值,避免空值导致渲染异常。
值覆盖的层级
覆盖优先级从低到高:chart 内置 values.yaml < 父 chart 的 values < helm install -f custom.yaml < --set 命令行。经验上,环境级差异用 -f 文件管,临时调试用 --set:
helm install prod ./mychart -f values-prod.yaml --set replicaCount=5
--set 优先级最高,能覆盖文件里的值,适合一次性覆盖。注意 --set 写数组和嵌套容易出错,-f 文件更可读。复杂值强烈建议用文件,命令行只做微调,否则一个引号就能让渲染崩掉。
版本与回滚
每次 helm upgrade 都生成一个 release revision。出问题直接回滚:
helm history myapp
helm rollback myapp 2
revision 2 是上一次稳定状态。回滚只是把 manifest 重新应用到旧版本,镜像和配置随之退回,但数据库 schema 这类外部状态不会自动还原,需自己保证兼容。版本号建议语义化,和镜像 tag 对齐,便于追溯是哪次变更引入的问题。发布流水线里把 helm upgrade 和镜像发布绑定,保证 chart 版本与应用版本可追溯。
子 chart 与依赖
复杂应用可拆成多个子 chart,父 chart 的 values 通过 xxx.<子chart名>.key 向下传:
# 父 values.yaml
redis:
enabled: true
replicaCount: 3
子 chart 是否启用、配多少,都由父 chart 统一管控,避免到处改。依赖关系写在 Chart.yaml 的 dependencies 里,用 helm dependency build 拉取并锁定版本。子 chart 的默认 values 被父 chart 同名键整体覆盖而非深合并,深层结构要逐层显式声明,否则配置“消失”却找不到原因。
发布前后做校验
helm lint ./mychart # 静态检查
helm template ./mychart # 本地渲染看产物
lint 能抓出明显的模板错误,template 能把渲染结果打印出来人工核对。把这两步放进 CI,比推到集群才发现失败便宜太多。
values 里的类型陷阱
数字写成字符串会导致模板运算或资源字段类型错。在 values 里明确类型,或模板里用 int 转换:
cpu: {{ .Values.cpu | int }}
别让 "2" 和 2 混用,前者是字符串后者是数字,K8s 字段类型严格,写错会让 manifest 校验失败而非悄悄生效。这类问题在 helm template 阶段就能暴露,所以本地渲染检查值得做。
踩坑清单
- 模板里忘了默认值,values 漏传就渲染成空,部署直接失败。给关键字段在 values.yaml 写默认或用
default。
--set 里含特殊字符(逗号、等号)要转义,否则解析错位,复杂结构改用 -f 文件。
- 升级前没
helm diff 看实际变更,把 imagePullPolicy 之类顺手改了,引发意外拉取。
- chart 版本和 appVersion 是两件事,前者是模板版本后者是应用版本,发布流水线别混淆。
helm uninstall 会连 release 记录一起删,想保留回滚点用 helm uninstall --keep-history 或干脆留着。
- 模板里用
if 控制资源时,条件写反会静默少生成资源,上线才发现少了 Service。
- 子 chart 的默认 values 被父 chart 同名键整体覆盖而非合并,深层结构要逐层显式声明,否则配置“消失”却找不到原因。
把 chart 当代码管,进版本库、走评审,模板能力再强也只是减少重复,不替代对生成结果的审阅。发布前用 helm template 本地渲染检查,比到集群里报错便宜。
1 view
0 likes
0 comments