深色模式
Helm 基础与 Chart 结构
摘要:本文面向需要在 Kubernetes 上做应用打包、复用与版本化发布的 SRE / 平台工程师。覆盖 Helm 3.x 的 Chart 结构、
Chart.yaml关键字段、values 与模板的分工,以及helm install/upgrade/rollback的发布流程。默认按 Helm 3.14+ 与 Kubernetes v1.25+ 说明。
适用版本与前提
- Helm:3.x(本文以 Helm 3.14+ 为准;Helm 3 已于 v3.0 移除 Tiller,客户端直连 Kubernetes API)
- Kubernetes:v1.25+(注意
apps/v1等稳定 API,避免extensions/v1beta1等已弃用 API) - 前提:已配置
kubectl且对目标集群有对应命名空间的create/update权限
背景与问题
Kubernetes 的原生对象是声明式的 YAML(Deployment、Service、ConfigMap 等)。但真实应用通常包含十几个互相关联的资源,且需要在 dev/staging/prod 之间复用同一套结构、只替换镜像、副本数、资源配置。纯手写 YAML 会出现三类问题:
- 重复与漂移:每个环境复制一份 YAML,字段被手工改乱,难以回溯。
- 参数化缺失:镜像 tag、副本数、域名等硬编码,无法"一次定义、多处复用"。
- 生命周期管理缺位:原生
kubectl apply没有"发布版本""回滚到某个版本"的概念,排障时很难知道集群里跑的是哪次变更。
Helm 的定位是 Kubernetes 的包管理器(package manager):把一组相关资源打包成 Chart,用 values.yaml 做参数化,用 templates/ 做模板渲染,并用 release 概念记录每次发布。它解决的是"可复用、可版本化、可回滚"的应用交付问题,而不是"多环境 YAML 差异治理"(那更偏向 Kustomize,见下文对比)。
一个常见误区
Helm 不是 GitOps 工具。它只负责"把 Chart 渲染成 manifest 并发布到集群",谁来触发、如何与 Git 对齐,是 Argo CD / Flux 的职责。很多团队用 Argo CD 渲染 Helm Chart(pull 模型),而不是在 CI 里 helm upgrade(push 模型)。
核心概念
- Chart:一个描述相关 Kubernetes 资源的文件集合,是 Helm 的"包"。
- Release:Chart 在集群某命名空间中的一次具体运行实例。同一个 Chart 可以装出多个 release(例如
prod-api与staging-api)。 - Repository:分发打包后 Chart(
.tgz)的仓库,可以是经典index.yaml仓库,也可以是 OCI 镜像仓库(Helm 3.8+ GA)。 - values:Chart 的默认参数;用户在安装/升级时用
-f values-prod.yaml或--set覆盖。
Chart 目录结构
Helm 对 Chart 目录有约定(Helm 保留 charts/、crds/、templates/ 这几个目录名):
text
mychart/
├── Chart.yaml # 必填:Chart 元数据
├── values.yaml # 默认配置值
├── values.schema.json # 可选:用 JSON Schema 约束 values
├── charts/ # 可选:依赖的子 Chart
├── crds/ # 可选:CRD(Helm 不会模板化,仅按序安装)
├── templates/ # 模板目录,渲染后生成 manifest
│ ├── NOTES.txt # 可选:安装后展示的使用说明
│ └── _helpers.tpl # 可选:可复用的模板片段(以 _ 开头)
├── LICENSE # 可选
└── README.md # 可选1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
Helm 在渲染时,会把 templates/ 下所有文件(除 _ 开头的 partial 文件)送入 Go template 引擎,结合 values.yaml 和内置对象渲染成一组 manifest,再整体提交给 Kubernetes。charts/、crds/、templates/ 这几个名字被 Helm 保留,自定义文件随意放不会被处理。
Chart.yaml 字段详解
Chart.yaml 是必填文件。Helm 3 的 Chart 使用 apiVersion: v2(v1 是 Helm 2 的;v3 曾被标记 experimental,生产不建议使用)。关键字段:
yaml
apiVersion: v2
name: mychart
version: 0.1.0 # SemVer 2,每次发布必须递增,作为 release 标记
appVersion: "1.16.0" # 被打包应用的版本,信息性字段,不参与版本计算
description: A Helm chart for Kubernetes
type: application # application(可安装)或 library(仅被依赖复用)
kubeVersion: ">= 1.25.0" # 可选:声明兼容的 K8s SemVer 范围,安装时校验
maintainers:
- name: sre-team
email: sre@example.com
dependencies:
- name: redis
version: "17.0.0"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
版本字段容易踩的两个坑
version必须是 SemVer 2(如1.2.3),且每次发布必须递增;它和appVersion是两个独立概念,appVersion写"1.16.0"引号推荐加上,否则 YAML 可能把1.0解析成浮点数。appVersion是信息性字段,不影响 Helm 的版本计算与回滚逻辑,切勿用它来做发布判断。
values.yaml 与模板的分工
values.yaml 保存默认参数;模板通过 {{ .Values.xxx }} 引用。两者分工明确:结构(哪些资源)由模板决定,数值(多少副本、什么镜像)由 values 决定。
yaml
# values.yaml
replicaCount: 2
image:
repository: nginx
tag: "1.27"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
resources:
requests:
cpu: 50m
memory: 64Mi1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
yaml
# templates/deployment.yaml(片段)
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-app
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ .Release.Name }}
spec:
containers:
- name: app
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: 801
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Chart 渲染与发布流程
helm install 时,Helm 客户端读取 Chart,把 templates/ 经 Go template 渲染,记录为一个 release(含 revision 1)并提交到集群。后续 upgrade 生成 revision 2、3……每次 revision 都可独立回滚。
生产实践
步骤 1:验证环境与渲染结果
bash
helm version # 确认 Helm 3.x
kubectl config current-context
# 先 dry-run 渲染,不真正安装,检查输出
helm install myapp ./mychart --dry-run --debug --namespace prod1
2
3
4
2
3
4
--dry-run 只渲染不安装,但不会校验 Kubernetes 是否接受这些 manifest,因此仍需结合 kubectl apply --dry-run=server([版本相关] 旧版为 --dry-run,v1.18+ 推荐 server/client)做服务端校验。
步骤 2:安装与原子化升级
bash
helm install myapp ./mychart \
--namespace prod --create-namespace \
-f values-prod.yaml
# 升级并启用原子模式:失败自动回滚
helm upgrade myapp ./mychart \
--namespace prod -f values-prod.yaml \
--atomic --timeout 5m1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
生产危险
helm uninstall 会立即删除 release 关联的所有资源,且默认无二次确认。生产执行前务必确认 --namespace 与 release 名称,必要时先 helm get manifest 备份当前 manifest。
验证
bash
helm list -n prod # 查看 release 与 revision
helm status myapp -n prod # 查看状态、最近 revision
helm get manifest myapp -n prod # 导出当前集群实际应用的 manifest
helm get values myapp -n prod # 查看最终生效的 values(含覆盖)1
2
3
4
2
3
4
回滚与清理
bash
helm history myapp -n prod # 列出所有 revision
helm rollback myapp 2 -n prod # 回滚到第 2 个 revision
helm uninstall myapp -n prod # 卸载(资源将被删除)1
2
3
2
3
Helm 的回滚本质是"用历史 revision 的 manifest 重新 apply",因此回滚速度取决于资源重建速度,而非快照恢复。
故障排查
Error: INSTALLATION FAILED: ... already exists:release 名已存在,用helm ls确认;或上次的uninstall因 hook 失败残留,可helm uninstall --no-hooks或手动清理。- 渲染报
nil pointer evaluating:模板引用了不存在的 values 路径,优先用default或if守卫(见下一篇模板语法)。 kubeVersion校验失败:集群版本不满足Chart.yaml的kubeVersion约束,需调整约束或升级集群。
常见坑
- Release 名称限制:Helm 3 release 名最长 53 字符(资源名受 DNS 63 字符限制,留给
name字段 10 字符)。 - Tiller 已移除:Helm 3 不再需要集群内的 Tiller,客户端直接以当前
kubeconfig的身份操作,RBAC 权限模型更简单,但也意味着本地kubeconfig的权限就是 Helm 的权限。 crds/不被模板化:CRD 仅按文件顺序安装,且helm upgrade默认不更新已存在的 CRD(需helm upgrade --install配合显式管理)。
Helm 与 Kustomize 的取舍
| 维度 | Helm | Kustomize |
|---|---|---|
| 核心范式 | 模板化(参数注入生成 manifest) | 叠加补丁(base + overlay 修改现成 YAML) |
| 学习成本 | 需学 Go template 语法 | 只需理解 kustomization.yaml 字段 |
| 多环境差异 | 靠 values 文件切换 | 靠 overlay 目录切换 |
| 适合场景 | 需要被多团队复用的"通用包"(如中间件 Chart) | 维护同一套 YAML 的多环境变体、不想引入模板 |
| 与 GitOps | Argo CD / Flux 均支持渲染 | kubectl 原生 -k 支持,GitOps 一等公民 |
经验判断
通用、要分发的组件(数据库、网关)优先 Helm;业务应用、需要细粒度多环境 overlay 的,优先 Kustomize。二者也可组合:用 Kustomize 的 HelmChartInflationGenerator 或 Argo CD 在 Application 层用 Helm,再叠加 Kustomize 做环境定制。
FAQ
Q:helm template 和 helm install 有什么区别? A:helm template 只把 Chart 渲染成 manifest 文本输出,不连接集群、不创建 release;helm install 会渲染并提交,同时记录 release revision。CI 里常用 helm template | kubectl apply 做无状态发布,但会失去 Helm 的回滚能力。
Q:Chart 版本和 App 版本必须一致吗? A:不必。Chart 版本(SemVer)追踪的是"打包方式"的变更,App 版本追踪的是"被打包应用"的版本,二者独立演进。
参考资料
- Helm Charts(官方文档),访问日期:2026-10-08。
- Helm Chart Template Guide: Getting Started(官方文档),访问日期:2026-10-08。
- Helm Chart.yaml Schema(apis.io 镜像官方 schema),访问日期:2026-10-08。