Helm 实战:用 Chart 打包发布 Kubernetes 应用

把应用搬上 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 安装包
ReleaseChart 在集群里的某次安装实例装好后的一个运行中的软件
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 / versionChart 名与语义化版本,升级靠它区分
apiVersion模板规范版本(v2 为当前主流)
dependencies声明子 Chart(如 redis、postgresql)
typeapplication(应用)或 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 怎么选

维度HelmKustomize
核心思路模板 + 参数渲染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 就从「个人脚本」变成了「团队标准交付协议」。

上一篇 文件描述符耗尽排查:Too Many Open Files
下一篇 ByteBuddy 实战:字节码增强与 Java Agent
最新评论
Docker 网络模式详解:bridge/host 生产选型 - FSData
Docker 网络模式详解:bridge/host 生产选型 - FSData
8月20日
[…] 注意最后那条:把端口绑定到 127.0.0.1,再由宿主机上的 Nginx 反代进来,比直接 -p 80:80 暴露安全得多,也方便统一做
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
8月20日
[…] Pinia 的工程化用法,可以参考我们之前的实战文章 《Vue3 组合式 API + Pinia:状态管理从入门到实战》,那里覆盖了 Sto
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
8月19日
[…] 状态,点一下就能起停容器,配合我们讲过的 Docker Compose 编排 […]
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
8月19日
[…] 缓存三大坑的本质都是”缓存失效导致请求穿透到数据库”。记住口诀:穿透用布隆、击穿用锁、雪崩用错峰。配合合理的过期策略
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
8月19日
[…] Docker 镜像部署。结合我们之前写的 Docker Compose 一键编排实战,可以在 CI […]