把应用搬上 Kubernetes,最初的快乐往往止步于第 N 个 YAML 文件:Deployment、Service、ConfigMap、Ingress、HPA……每次上线都要手动 kubectl apply 一堆清单,环境一多就张冠李戴,回滚更是一场灾难。Helm 正是为解决「Kubernetes 应用打包」而生的包管理器——它用一套 Chart 模板把零散的清单收敛成可版本化、可复用、可一键安装与回滚的「应用安装包」。本文从零讲透 Helm 的核心概念、模板语法、打包发布,以及它如何与 CI/CD、GitOps 协同,帮你把 Kubernetes 应用的 delivery 流水线彻底跑顺。
一、为什么需要 Helm
裸写 YAML 有三道坎:第一,重复,十个微服务十套近乎相同的 Deployment,改一处要改十次;第二,环境差异,开发、测试、生产只是镜像 tag、副本数、域名不同,却要维护多份清单;第三,可观测与回滚缺失,kubectl apply 没有「版本」概念,出问题只能靠人肉比对。Helm 用「模板 + 值覆盖 + Release 版本」一次性解决这三件事:清单变成模板,差异收敛进 values.yaml,每一次安装/升级都是带编号的 Release,回滚只需一条命令。
二、Helm 的四个核心概念
| 概念 | 是什么 | 类比 |
| Chart | 应用打包模板(目录 + 元数据) | Debian 的 .deb 安装包 |
| Release | Chart 在集群里的某次安装实例 | 装好后的一个运行中的软件 |
| Repository | 存放 Chart 的仓库(HTTP/OCI) | apt 的软件源 |
| Values | 覆盖模板的参数集合 | 安装时的配置问答 |
同一个 Chart 可以装出多个 Release(例如一套 mychart 同时跑 dev 和 prod),彼此互不干扰——这正是 Helm 管理多环境的基石。
三、安装 Helm 并验票
# macOS
brew install helm
# Linux 官方脚本
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# 验票
helm version
# version.BuildInfo{Version:"v3.16.0", GitCommit:...}
Helm 3 已内置 Tiller 移除后的安全模型,直接与 kubeconfig 交互,无需再单独部署服务端组件。本地想快速起一套验证集群,可参考 k3s 实战 用轻量 Kubernetes 跑通下面的例子。
四、解剖一个 Chart:目录结构
mychart/
├── Chart.yaml # 元数据:name、version、dependencies
├── values.yaml # 默认参数
├── charts/ # 子 Chart(依赖)
├── templates/ # 真正渲染的 Kubernetes 清单
│ ├── _helpers.tpl # 可复用模板片段
│ ├── deployment.yaml
│ ├── service.yaml
│ └── NOTES.txt # 安装后给用户的提示
└── templates/tests/ # 冒烟测试
Helm 渲染时,会把 templates/ 下所有文件用 Go template 引擎处理,注入 values.yaml 与内置对象(.Release、.Chart、.Capabilities),生成最终 YAML 后交给 kubectl 执行。
五、模板语法:把静态 YAML 变成可配置
先看 values.yaml 如何描述应用画像:
# values.yaml
replicaCount: 2
image:
repository: nginx
tag: "1.27"
service:
port: 80
resources:
requests:
cpu: 100m
memory: 128Mi
再在 templates/deployment.yaml 里用 {{ .Values.xxx }} 把值「填」进清单,并用管道做格式化、用 if/range 做条件与循环:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Chart.Name }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Chart.Name }}
template:
metadata:
labels:
app: {{ .Chart.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: {{ .Values.service.port }}
resources:
requests:
cpu: {{ .Values.resources.requests.cpu }}
memory: {{ .Values.resources.requests.memory }}
{{ .Chart.Name }} 读取 Chart.yaml 里的 name;{{ .Values.image.tag }} 读取上面的值。模板还支持 helm lint 静态检查与 helm template 本地预览渲染结果,无需真正连集群即可排错。
六、Chart.yaml 与依赖管理
| 字段 | 作用 |
| name / version | Chart 名与语义化版本,升级靠它区分 |
| apiVersion | 模板规范版本(v2 为当前主流) |
| dependencies | 声明子 Chart(如 redis、postgresql) |
| type | application(应用)或 library(可复用模板库) |
# 拉取并打包依赖
helm dependency build mychart
# 或锁定版本后离线打包
helm package mychart
# 生成 mychart-0.1.0.tgz
七、把 Chart 发布到仓库(含 OCI 与 GitHub Actions)
现代 Helm 推荐用 OCI 镜像仓库存 Chart(Harbor、GHCR、阿里云 ACR 均支持),一条 helm push 即可上线:
# 登录 OCI 仓库(以 GHCR 为例)
helm registry login ghcr.io -u <your-user>
# 打包并推送
helm package mychart
helm push mychart-0.1.0.tgz oci://ghcr.io/<org>/charts
把「打包 + 推送」放进 GitHub Actions 实战 的 CI 流水线,打 tag 即自动发布新版本 Chart,团队用 helm repo add 或 helm pull oci://... 即可消费,版本可追溯、可回退。
八、安装、升级与回滚
# 安装(首次 = 创建 Release)
helm install myapp ./mychart -n demo --create-namespace
# 改了 values 后升级(生成新 Release 版本)
helm upgrade myapp ./mychart -n demo --set replicaCount=3
# 查看历史
helm history myapp -n demo
# 一键回滚到上一版本
helm rollback myapp -n demo
# 卸载
helm uninstall myapp -n demo
helm upgrade 默认采用「三路策略合并」(旧 Release、新 values、线上现状),比纯 kubectl apply 更稳健;回滚是把 Release 重新指向历史版本号,秒级完成。
九、多环境管理与密钥
同一套 Chart 跑多环境,最佳实践是用多份 values 文件覆盖,而不是改模板:
# 基础值
helm install myapp ./mychart -f values.yaml
# 生产环境用独立覆盖文件
helm upgrade myapp ./mychart -f values.yaml -f values-prod.yaml --set image.tag=1.27-prod
密钥切忌写进 values(会进 Git)。应配合 External Secrets Operator 实战 从云密钥库动态注入,或用 --set 在 CI 里从保密环境变量传入。镜像本身则建议先用 Docker Compose 一键编排 在本地验证可运行,再交给 Helm 上集群。
十、与 GitOps 协作(Argo CD / Flux)
Helm 与 GitOps 是天作之合:把 Chart 或渲染后的 values 存进 Git,由控制器自动同步到集群。在 Argo CD 实战 里可以直接声明 source.helm,指定 Chart 路径与 values,Argo CD 负责拉取、渲染、比对并自动纠偏;Flux 同理通过 HelmRelease 资源驱动。这样「人只改 Git,集群自动跟随」,回滚也变成「把 Git 退一个 commit」。
十一、调试与排错
# 本地渲染,不真正部署,肉眼看生成的 YAML
helm template myapp ./mychart
# 静态检查(模板语法、弃用 API)
helm lint ./mychart
# 查看某 Release 实际生效的 values
helm get values myapp -n demo
# 安装/升级失败时打印完整 manifest 便于定位
helm install myapp ./mychart --debug
# 渲染时注入调试信息
helm template ./mychart | kubectl apply --dry-run=client -f -
常见的坑:模板里数字被渲染成字符串(记得用 quote 或 int 管道)、range 作用域丢变量(用 $ 捕获)、依赖 Chart 版本没 helm dependency build 导致找不到。
十二、Helm vs Kustomize 怎么选
| 维度 | Helm | Kustomize |
| 核心思路 | 模板 + 参数渲染 | overlay 补丁叠加 |
| 学习成本 | 中(需学模板语法) | 低(纯 YAML 补丁) |
| 打包分发 | 强(Chart 仓库/OCI) | 弱(靠 Git 仓库) |
| 适用场景 | 通用应用、需复用分发 | 同构环境、少量差异 |
两者并非互斥。想深入补丁式管理,可看 Kustomize 实战;实际项目里常「Kustomize 管基础底座、Helm 管业务应用」。对需要持久化存储的有状态应用(如数据库),部署时可结合 Longhorn 实战 的 StorageClass 自动供给 PV。
十三、落地清单
把 Helm 真正用起来,按这份清单走即可:① 用 helm create 起骨架;② 把可变项全部抽到 values.yaml;③ 用 helm lint + helm template 本地验证;④ 多环境用 values 覆盖文件,密钥走 External Secrets;⑤ Chart 推 OCI 仓库,由 GitHub Actions 自动发版;⑥ 生产用 Argo CD/Flux 做 GitOps 同步;⑦ 升级前记住 helm history,出问题 helm rollback 兜底。做到这七步,你的 Kubernetes 应用交付就从「人肉 apply」升级成了「可版本、可回滚、可追溯」的工程化流水线。
十四、模板函数进阶:让值更健壮
Go template 自带大量函数,配合 Helm 的 Sprig 扩展,能写出更安全的模板。几个高频用法:default 给缺省值,避免空值渲染报错;quote 把数字/字符串包成 YAML 引号,防止被当成数字;required 在必填项缺失时直接中断并给出友好提示;include 复用 _helpers.tpl 里的命名模板。
# 缺省值 + 引号包裹
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default "latest" | quote }}"
# 必填项校验,缺失即报错
database:
host: {{ required "请配置 values.database.host" .Values.database.host | quote }}
# 复用 helpers 里的命名模板
name: {{ include "mychart.fullname" . }}
# 列表转逗号字符串
env: {{ .Values.env | join "," | quote }}
把这些函数用在 _helpers.tpl 里统一生成资源名、标签,能让多环境、多实例下的命名既一致又可预测,也减少「名字撞车」导致的部署失败。
十五、常用命令速查表
| 命令 | 用途 |
| helm create <name> | 生成 Chart 骨架 |
| helm lint <path> | 模板静态检查 |
| helm template <rel> <path> | 本地渲染预览 |
| helm install <rel> <path> | 首次安装 |
| helm upgrade –install <rel> <path> | 安装或升级(幂等) |
| helm history <rel> | 查看 Release 版本 |
| helm rollback <rel> [<ver>] | 回滚到指定版本 |
| helm get values <rel> | 查看生效参数 |
| helm package <path> | 打包成 .tgz |
| helm push <tgz> oci://… | 推送到 OCI 仓库 |
把这张表贴进团队的 Confluence 或内部 Wiki,新人十分钟就能上手。配合前面讲的 GitOps 与 CI 自动发版,Helm 就从「个人脚本」变成了「团队标准交付协议」。




