Helm 核心概念与实践:快速掌握 K8s 应用打包与管理
在 Kubernetes (K8s) 的世界中,应用部署通常涉及编写和管理大量的 YAML 文件,这些文件定义了 K8s 的各种资源,如 Deployment, Service, ConfigMap, Secret 等。随着应用复杂度的增加,手动管理这些 YAML 文件变得越来越繁琐、易错且难以维护。为了解决这一痛点,Helm 应运而生。Helm 被誉为“Kubernetes 的包管理器”,它极大地简化了 K8s 应用的定义、安装、升级和共享过程。本文将深入探讨 Helm 的核心概念,并通过实践案例,帮助您快速掌握使用 Helm 打包和管理 K8s 应用的技能。
一、为什么需要 Helm?K8s 应用管理的痛点
在了解 Helm 之前,我们先回顾一下在没有 Helm 的情况下管理 K8s 应用可能遇到的挑战:
- YAML 文件爆炸:一个中等规模的应用可能包含数十个甚至上百个 YAML 文件。管理它们的版本、依赖关系和一致性是一项艰巨的任务。
- 配置复杂性:不同的环境(开发、测试、生产)通常需要不同的配置(如副本数、镜像标签、资源限制等)。手动修改和维护多套 YAML 文件容易出错。
- 复用性差:如果多个应用需要部署类似的组件(如 Redis 缓存、MySQL 数据库),很难方便地复用已有的配置模板。
- 版本控制困难:对应用进行升级或回滚时,需要精确追踪哪些 YAML 文件发生了变化,操作复杂且风险高。
- 缺乏标准化:没有统一的应用打包和分发机制,使得应用共享和协作变得困难。
Helm 正是为了解决上述问题而设计的,它提供了一套标准化的方法来打包、配置和部署 K8s 应用。
二、Helm 核心概念解析
要理解 Helm,首先需要掌握其几个核心概念:
-
Chart (图表):
- 定义:Chart 是 Helm 的打包格式,它包含了创建 K8s 应用实例所需的所有资源定义、配置信息和元数据。你可以将 Chart 类比为 Linux 系统中的 RPM 或 DEB 包,或是 Node.js 中的 npm 包。
- 结构:一个典型的 Chart 是一个特定目录结构的文件集合。主要包含:
Chart.yaml
: 描述 Chart 的元数据,如名称、版本、描述、API 版本(apiVersion
,Helm 3 中通常为v2
)、应用版本(appVersion
)等。values.yaml
: Chart 的默认配置值。这些值可以在部署时被覆盖,从而实现应用的定制化。templates/
: 存放 K8s 资源清单的模板文件。这些文件使用 Go 模板语言编写,Helm 会在部署时将values.yaml
中的值以及其他预定义变量渲染到这些模板中,生成最终的 K8s YAML 文件。常见的资源模板有deployment.yaml
,service.yaml
,ingress.yaml
,configmap.yaml
等。templates/NOTES.txt
: (可选) Chart 安装成功后显示的帮助信息或使用说明。charts/
: (可选) 存放该 Chart 依赖的其他 Chart(称为子 Chart 或 Subcharts)。这使得构建复杂应用成为可能。crds/
: (可选) 存放自定义资源定义 (Custom Resource Definitions)。这些 CRD 会在模板渲染之前被安装到 K8s 集群中。
-
Release (发布):
- 定义:Release 是 Chart 在 K8s 集群中的一个运行实例。当使用
helm install
命令部署一个 Chart 时,Helm 会创建一个新的 Release。 - 特性:
- 每个 Release 都有一个唯一的名称,用于在集群中标识该实例。
- 同一个 Chart 可以被多次安装到同一个集群中,每次安装都会创建一个新的 Release(只要 Release 名称不同或安装到不同的命名空间)。
- Helm 会跟踪每个 Release 的版本历史,方便进行升级和回滚操作。
- 定义:Release 是 Chart 在 K8s 集群中的一个运行实例。当使用
-
Repository (仓库):
- 定义:Repository 是用来存储和共享 Chart 的地方。它类似于
apt
或yum
的软件仓库,或 Docker Hub。 - 类型:
- 公共仓库:如官方的 Artifact Hub (取代了之前的 Helm Hub),提供了大量预构建的常用应用 Chart。
- 私有仓库:企业或团队可以搭建自己的 Chart 仓库,用于内部共享。常见的私有仓库解决方案有 ChartMuseum, Harbor, Nexus Repository Manager 等。
- 索引文件:每个 Repository 都有一个
index.yaml
文件,它描述了该仓库中所有 Chart 的元数据和下载链接。helm repo add
命令会下载并缓存这个索引文件。
- 定义:Repository 是用来存储和共享 Chart 的地方。它类似于
-
Templates (模板):
- Helm 使用 Go 模板引擎来生成 K8s 清单文件。模板文件位于 Chart 的
templates/
目录下。 - 模板中可以使用预定义的 Helm 对象(如
.Release
,.Values
,.Chart
,.Capabilities
),以及 Go 模板语言的控制结构(如if/else
,range
)和函数(如default
,quote
,tpl
)。 _helpers.tpl
文件通常用于定义可复用的模板片段(命名模板),使主模板更简洁易读。
- Helm 使用 Go 模板引擎来生成 K8s 清单文件。模板文件位于 Chart 的
-
Values (值):
- Values 提供了自定义 Chart 配置的能力。它们可以在多个地方定义,并按特定优先级合并:
- Chart 中
values.yaml
文件(优先级最低)。 - 父 Chart 的
values.yaml
中对子 Chart 的配置。 - 通过
helm install/upgrade
命令的--values
(或-f
) 参数指定的自定义 YAML 文件。 - 通过
helm install/upgrade
命令的--set
参数直接设置的单个值(优先级最高)。
- Chart 中
- 这种机制使得 Chart 开发者可以提供一套灵活的默认配置,而用户可以根据自己的需求轻松覆盖这些配置,而无需修改 Chart 源码。
- Values 提供了自定义 Chart 配置的能力。它们可以在多个地方定义,并按特定优先级合并:
三、Helm 实践:快速上手
1. 安装 Helm CLI
首先,你需要在本地机器上安装 Helm 客户端。访问 Helm 官方发布页面 (https://github.com/helm/helm/releases) 下载适合你操作系统的二进制文件,或者使用包管理器(如 brew install helm
for macOS, choco install kubernetes-helm
for Windows)。
安装完成后,验证安装:
bash
helm version
你应该能看到客户端版本信息。Helm 3 不再需要 Tiller (Helm 2 中的服务端组件),简化了架构和安全性。
2. 添加和管理 Chart 仓库
大多数常用的 Chart 都托管在公共仓库中。Artifact Hub (artifacthub.io) 是一个很好的查找 Chart 的起点。
例如,添加 Bitnami 仓库,它提供了许多高质量的开源应用 Chart:
bash
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update # 更新本地仓库索引
查看已添加的仓库:
bash
helm repo list
搜索 Chart:
bash
helm search repo bitnami/mysql # 在 bitnami 仓库中搜索 mysql
helm search hub mysql # 在 Artifact Hub (及其他配置的 hub) 中搜索 mysql
3. 安装 Chart (创建 Release)
假设我们要安装一个 Nginx 服务。我们可以从 Bitnami 仓库中找到 Nginx Chart。
“`bash
搜索 Nginx Chart
helm search repo bitnami/nginx
安装 Nginx Chart,并命名 Release 为 “my-nginx”,部署到 “default” 命名空间
helm install my-nginx bitnami/nginx –namespace default
“`
如果需要在特定命名空间部署,且该命名空间不存在,可以加上 --create-namespace
参数:
bash
helm install my-nginx bitnami/nginx --namespace web-apps --create-namespace
查看 Release 状态:
bash
helm list -n web-apps # 列出 web-apps 命名空间下的所有 Release
helm status my-nginx -n web-apps # 查看 my-nginx Release 的详细状态
4. 自定义 Chart 安装 (使用 Values)
通常,我们需要根据自己的需求定制 Chart 的配置。例如,修改 Nginx 的 Service 类型或副本数量。
方法一:使用 --set
参数
bash
helm install custom-nginx bitnami/nginx \
--namespace web-apps \
--set replicaCount=3 \
--set service.type=NodePort
这会将副本数设置为 3,并将 Service 类型设置为 NodePort。
方法二:使用自定义 values.yaml
文件
首先,获取 Chart 的默认 values.yaml
文件内容:
bash
helm show values bitnami/nginx > my-nginx-values.yaml
然后,编辑 my-nginx-values.yaml
文件,修改其中的配置项。例如:
“`yaml
my-nginx-values.yaml
replicaCount: 2
service:
type: LoadBalancer
port: 8080
…其他配置保持默认或按需修改
使用自定义的 values 文件安装:
bash
helm install another-nginx bitnami/nginx \
-f my-nginx-values.yaml \
–namespace web-apps
“`
5. 升级 Release
当应用需要更新版本,或者配置需要变更时,可以使用 helm upgrade
。
假设我们要将 custom-nginx
的副本数从 3 改为 5:
bash
helm upgrade custom-nginx bitnami/nginx \
--namespace web-apps \
--set replicaCount=5
Helm 会比较新旧配置,只应用变更的部分。
如果要升级到 Chart 的新版本:
bash
helm upgrade custom-nginx bitnami/nginx --version <new-chart-version> -n web-apps
6. 回滚 Release
如果升级后发现问题,可以快速回滚到之前的版本。
bash
helm history custom-nginx -n web-apps # 查看 Release 的历史版本
helm rollback custom-nginx <revision-number> -n web-apps # 回滚到指定的修订版本
例如,回滚到上一个版本 (修订号通常是比当前版本小 1 的数字):
bash
helm rollback custom-nginx 1 -n web-apps
7. 卸载 Release
当不再需要某个应用实例时,可以将其卸载:
bash
helm uninstall my-nginx -n web-apps
这会删除该 Release 创建的所有 K8s 资源。
8. 创建自己的 Chart
除了使用现有的 Chart,我们也可以创建自己的 Chart 来打包应用。
使用 helm create
命令生成一个 Chart 骨架:
bash
helm create myapp
这会创建一个名为 myapp
的目录,包含标准的 Chart 结构:
myapp/
├── Chart.yaml
├── values.yaml
├── charts/
├── templates/
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ └── tests/
│ └── test-connection.yaml
└── .helmignore
编写 Chart.yaml
:
填写 Chart 的元数据。
“`yaml
myapp/Chart.yaml
apiVersion: v2
name: myapp
description: A Helm chart for my custom application
type: application # Chart 类型,可以是 application 或 library
version: 0.1.0 # Chart 版本 (SemVer 2)
appVersion: “1.0.0” # 应用版本
“`
配置 values.yaml
:
定义应用的可配置参数。
“`yaml
myapp/values.yaml
replicaCount: 1
image:
repository: nginx
pullPolicy: IfNotPresent
tag: “latest”
service:
type: ClusterIP
port: 80
ingress:
enabled: false
# hosts:
# – host: chart-example.local
# paths:
# – path: /
# pathType: ImplementationSpecific
“`
编写 templates/
:
修改或添加模板文件。例如,templates/deployment.yaml
可能如下:
“`yaml
myapp/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include “myapp.fullname” . }} # 使用 _helpers.tpl 中定义的命名模板
labels:
{{- include “myapp.labels” . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include “myapp.selectorLabels” . | nindent 6 }}
template:
metadata:
labels:
{{- include “myapp.selectorLabels” . | nindent 8 }}
spec:
containers:
– name: {{ .Chart.Name }}
image: “{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}”
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
– name: http
containerPort: 80 # 假设应用监听 80 端口
protocol: TCP
# … livenessProbe, readinessProbe 等
``
{{ .Values.replicaCount }}
这里:
*引用
values.yaml中的
replicaCount。
{{ .Chart.Name }}
*引用
Chart.yaml中的
name。
{{ include “myapp.fullname” . }}
*和
{{ include “myapp.labels” . }}调用在
_helpers.tpl中定义的命名模板,用于生成标准化的名称和标签。
| default .Chart.AppVersion
*表示如果
.Values.image.tag未定义,则使用
Chart.yaml中的
appVersion。
| nindent 4` 是一个模板函数,用于将输出缩进指定空格数。
*
Linting 和调试:
在打包或安装之前,检查 Chart 是否有语法错误或不符合最佳实践:
bash
helm lint ./myapp
可以使用 helm template
或 helm install --dry-run --debug
来渲染模板并查看生成的 K8s YAML,而不实际部署到集群,这对于调试非常有用:
bash
helm template myapp-release ./myapp -f ./myapp/values.yaml > rendered-manifests.yaml
helm install myapp-release ./myapp --dry-run --debug > dry-run-output.txt
打包 Chart:
将 Chart 打包成 .tgz
文件,以便分发或上传到仓库:
bash
helm package ./myapp
这会生成一个如 myapp-0.1.0.tgz
的文件。
9. Chart 依赖管理 (Subcharts)
复杂的应用可能由多个组件构成,每个组件可以是一个独立的 Chart。Helm 允许将这些 Chart 作为依赖(Subcharts)包含在主 Chart 中。
依赖可以在 Chart.yaml
文件中声明 (Helm 3.0+):
“`yaml
myapp/Chart.yaml
apiVersion: v2
name: myapp
…
dependencies:
– name: redis
version: “15.x.x” # 指定 redis chart 的版本范围
repository: “https://charts.bitnami.com/bitnami” # redis chart 所在的仓库
# alias: my-redis # (可选) 为子 chart 指定一个别名
# condition: redis.enabled # (可选) 只有当 values.yaml 中 redis.enabled 为 true 时才加载此依赖
或者在 Helm 2 风格的 `requirements.yaml` 文件中(依然兼容):
yaml
myapp/requirements.yaml (如果 Chart.yaml 中没有 dependencies 块)
dependencies:
– name: redis
version: “15.x.x”
repository: “https://charts.bitnami.com/bitnami”
声明依赖后,需要更新依赖:
bash
helm dependency update ./myapp # 下载依赖的 Chart 到 charts/ 目录
helm dependency build ./myapp # 等同于 update,但如果 charts/ 已存在会报错,除非加 –skip-refresh
子 Chart 的配置可以在主 Chart 的 `values.yaml` 中通过以子 Chart 名称(或别名)为键的块进行覆盖:
yaml
myapp/values.yaml
replicaCount: 1
…
redis: # 对应子 Chart 的名称
architecture: standalone
auth:
enabled: false
# … 其他 redis chart 的配置项
“`
四、Helm 的进阶主题与最佳实践
- Chart Hooks (钩子):允许在 Release生命周期的特定点执行操作,如
pre-install
,post-install
,pre-delete
,post-delete
,pre-upgrade
,post-upgrade
等。常用于数据库迁移、备份、清理等任务。 - 命名模板与
_helpers.tpl
:大量使用命名模板 ({{ define "mychart.foo" }} ... {{ end }}
) 并将它们放在_helpers.tpl
中,可以使主模板文件更清晰,并提高代码复用性。 - Chart 测试 (
templates/tests/
):Helm 支持在 Chart 中定义测试作业,用于验证部署是否成功。使用helm test <release-name>
执行。 - 条件化启用/禁用子 Chart 或资源:使用
values.yaml
中的布尔标志和模板中的if
条件,可以灵活控制哪些子 Chart 或资源在特定部署中被创建。 - Secrets 管理:Helm 本身不直接处理敏感数据的加密,但可以与 Vault, Sealed Secrets, SOPS 等工具集成,或者利用 K8s Secrets 对象(注意其本身只是 base64 编码)。
- Helmfile / Helmsman: 对于管理大量 Helm Release 的场景,这些工具提供了声明式的方式来定义和部署多个 Release 及其配置,增强了 GitOps 实践。
- 版本控制 Chart: 像对待任何代码一样,将 Chart 源码纳入版本控制系统 (如 Git),并遵循 SemVer 规范管理 Chart 版本。
五、总结
Helm 作为 Kubernetes 生态系统中的关键组件,通过其 Chart、Release 和 Repository 的概念,以及强大的模板引擎和配置管理能力,极大地简化了 K8s 应用的打包、分发、部署和管理。它不仅提高了运维效率,降低了出错风险,还促进了 K8s 应用的标准化和复用。
从安装第一个 Chart 到创建和维护自己的复杂 Chart,掌握 Helm 的核心概念和实践技巧,是每一位 Kubernetes 从业者提升其应用管理水平的必经之路。通过本文的介绍,希望能为您打开 Helm 的大门,让您在 K8s 的航程中更加得心应手。随着您经验的积累,您会发现 Helm 的更多高级特性和最佳实践,使其成为您云原生工具箱中不可或缺的一员。