跳到主要内容

Helm 包管理

Helm 是 Kubernetes 的包管理工具,被誉为"Kubernetes 的 apt/yum"。它将一组相关的 Kubernetes 资源打包成一个可重用的单元(称为 Chart),让复杂应用的部署变得像安装软件包一样简单。本教程将带你从零开始掌握 Helm 的使用和开发。

为什么需要 Helm?

在深入学习 Helm 之前,我们先看看直接使用 kubectl 管理应用会遇到哪些问题。

手动管理的痛点

假设你要部署一个典型的 Web 应用,通常需要创建以下资源:

  • Deployment:管理应用 Pod
  • Service:暴露服务
  • ConfigMap:存储配置
  • Secret:存储敏感信息
  • Ingress:配置外部访问
  • HorizontalPodAutoscaler:自动扩缩容

每个资源都是一个 YAML 文件,你需要逐个应用它们。当需要升级时,又要逐个更新。如果有多套环境(开发、测试、生产),配置又有细微差异,就需要维护多套几乎相同的 YAML 文件。

更麻烦的是,这些资源之间存在依赖关系。比如 Deployment 依赖 ConfigMap,ConfigMap 更新后 Deployment 需要重启才能生效。手动管理这些关系非常繁琐且容易出错。

Helm 如何解决问题

Helm 引入了"包"的概念,把一组相关的 Kubernetes 资源打包成一个 Chart。你可以:

  • 一键安装:一条命令部署整个应用栈
  • 版本管理:跟踪每次部署的版本,支持回滚
  • 配置复用:通过参数化配置,一个 Chart 部署到多个环境
  • 依赖管理:自动处理应用间的依赖关系

打个比方,如果 kubectl 是手动拼装电脑的螺丝刀,那么 Helm 就是一键安装软件的软件中心。

核心概念

Helm 有三个核心概念,理解它们是掌握 Helm 的基础。

Chart(图表)

Chart 是 Helm 的打包格式,包含了一组 Kubernetes 资源定义。可以把 Chart 理解为软件安装包,比如一个 WordPress Chart 包含了部署 WordPress 所需的所有资源:Deployment、Service、ConfigMap、Secret 等。

Chart 是可参数化的。同一个 Chart 通过不同的配置值,可以部署出不同实例。比如用同一个 WordPress Chart,通过不同的域名和数据库配置,部署多个 WordPress 站点。

Release(发布)

Release 是 Chart 的一次安装实例。每次使用 helm install 安装 Chart,就会创建一个新的 Release。同一个 Chart 可以安装多次,每次都是独立的 Release。

Release 这个名字可能有点迷惑,它更像是"部署实例"。比如你用 WordPress Chart 安装了两个站点,就有两个 Release:wordpress-devwordpress-prod

Repository(仓库)

Repository 是存放 Chart 的地方,类似 apt 的软件源或 Docker 的镜像仓库。你可以从公共仓库下载 Chart,也可以搭建私有仓库存储内部应用的 Chart。

安装 Helm

各平台安装方法

macOS(使用 Homebrew)

brew install helm

Windows(使用 Chocolatey 或 Scoop)

# 使用 Chocolatey
choco install kubernetes-helm

# 使用 Scoop
scoop install helm

Linux

# 使用官方脚本
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# 或使用 apt(Debian/Ubuntu)
curl https://baltocdn.com/helm/signing.asc | sudo apt-key add -
sudo apt-get install apt-transport-https --yes
echo "deb https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt-get update
sudo apt-get install helm

验证安装

helm version

输出类似:

version.BuildInfo{Version:"v3.13.0", GitCommit:"...", GitTreeState:"clean", GoVersion:"go1.20.8"}

配置自动补全

# Bash
source <(helm completion bash)
echo "source <(helm completion bash)" >> ~/.bashrc

# Zsh
source <(helm completion zsh)
echo "source <(helm completion zsh)" >> ~/.zshrc

# Fish
helm completion fish | source

基本使用

添加仓库

Helm 默认没有配置任何仓库,需要手动添加。常用的公共仓库有:

# 添加 Bitnami 仓库(包含大量高质量 Chart)
helm repo add bitnami https://charts.bitnami.com/bitnami

# 添加官方稳定仓库
helm repo add stable https://charts.helm.sh/stable

# 添加 incubator 仓库(实验性 Chart)
helm repo add incubator https://charts.helm.sh/incubator

# 更新仓库索引
helm repo update

# 查看已添加的仓库
helm repo list

搜索 Chart

# 在已添加的仓库中搜索
helm search repo bitnami

# 搜索特定应用
helm search repo wordpress

# 搜索 Artifact Hub(公共 Chart 目录)
helm search hub wordpress

查看 Chart 信息

# 查看 Chart 基本信息
helm show chart bitnami/wordpress

# 查看完整 README
helm show readme bitnami/wordpress

# 查看默认配置值
helm show values bitnami/wordpress

# 查看所有信息
helm show all bitnami/wordpress

安装 Chart

# 基本安装(自动生成 Release 名称)
helm install bitnami/wordpress --generate-name

# 指定 Release 名称
helm install my-wordpress bitnami/wordpress

# 指定命名空间
helm install my-wordpress bitnami/wordpress -n web-apps

# 使用自定义配置值
helm install my-wordpress bitnami/wordpress -f values.yaml

# 通过命令行设置值
helm install my-wordpress bitnami/wordpress \
--set wordpressUsername=admin \
--set wordpressPassword=secret \
--set service.type=NodePort

# 混合使用文件和命令行
helm install my-wordpress bitnami/wordpress \
-f values.yaml \
--set replicaCount=3

查看已安装的 Release

# 列出所有 Release
helm list

# 列出所有命名空间的 Release
helm list -A

# 查看特定 Release 详情
helm status my-wordpress

# 查看 Release 的历史版本
helm history my-wordpress

升级 Release

# 升级到新版本
helm upgrade my-wordpress bitnami/wordpress

# 升级并更新配置
helm upgrade my-wordpress bitnami/wordpress \
--set replicaCount=5

# 升级时如果 Release 不存在则安装
helm upgrade --install my-wordpress bitnami/wordpress

回滚 Release

# 回滚到上一个版本
helm rollback my-wordpress

# 回滚到指定版本
helm rollback my-wordpress 2

卸载 Release

# 卸载 Release
helm uninstall my-wordpress

# 卸载但保留历史记录
helm uninstall my-wordpress --keep-history

Chart 结构详解

了解 Chart 的目录结构,是开发自定义 Chart 的基础。一个典型的 Chart 结构如下:

mychart/
├── Chart.yaml # Chart 元数据(必需)
├── values.yaml # 默认配置值(必需)
├── charts/ # 依赖的子 Chart
├── templates/ # Kubernetes 资源模板
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── configmap.yaml
│ ├── _helpers.tpl # 模板助手函数
│ └── NOTES.txt # 安装后显示的提示信息
├── .helmignore # 打包时忽略的文件
├── LICENSE # 许可证
├── README.md # 说明文档
└── values.schema.json # 值的 JSON Schema 验证

Chart.yaml 详解

Chart.yaml 是 Chart 的核心配置文件,包含 Chart 的元数据:

apiVersion: v2          # Chart API 版本(Helm 3 使用 v2)
name: mychart # Chart 名称(必需)
version: 1.0.0 # Chart 版本(必需,遵循 SemVer)
kubeVersion: ">= 1.20.0" # 兼容的 Kubernetes 版本
description: A Helm chart for my application
type: application # application 或 library
keywords:
- web
- frontend
home: https://example.com
sources:
- https://github.com/example/mychart
maintainers:
- name: John Doe
email: [email protected]
url: https://example.com
icon: https://example.com/icon.png
appVersion: "2.0.0" # 应用版本(与 Chart 版本不同)
deprecated: false # 是否已废弃
annotations:
artifacthub.io/license: Apache-2.0

版本说明

  • version:Chart 本身的版本,每次修改 Chart 都应该增加
  • appVersion:Chart 包含的应用版本,比如 nginx:1.25 中的 1.25

values.yaml 详解

values.yaml 定义了 Chart 的默认配置值,这些值可以在安装时被覆盖:

# 副本数
replicaCount: 3

# 镜像配置
image:
repository: nginx
tag: "1.25"
pullPolicy: IfNotPresent

# 服务配置
service:
type: ClusterIP
port: 80

# 资源限制
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi

# 环境变量
env:
- name: APP_ENV
value: production

# 亲和性配置
nodeSelector: {}
tolerations: []
affinity: {}

模板语法

Helm 使用 Go 模板语言编写 Kubernetes 资源模板。以下是一个 Deployment 模板示例:

apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "mychart.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "mychart.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.port }}
resources:
{{- toYaml .Values.resources | nindent 12 }}

模板语法要点

语法说明示例
{{ .Values.key }}访问 values.yaml 中的值{{ .Values.replicaCount }}
{{ .Chart.key }}访问 Chart.yaml 中的值{{ .Chart.Name }}
{{ .Release.Name }}访问 Release 信息{{ .Release.Name }}
{{- ... -}}去除空白{{- include "mychart.labels" . -}}
|管道操作{{ .Values.resources | toYaml }}
nindent N缩进 N 空格并换行| nindent 4

预定义值

Helm 在模板中提供了一些预定义的对象:

# Release 对象
{{ .Release.Name }} # Release 名称
{{ .Release.Namespace }} # 命名空间
{{ .Release.Service }} # 执行发布的服务
{{ .Release.IsUpgrade }} # 是否是升级操作
{{ .Release.IsInstall }} # 是否是安装操作

# Chart 对象
{{ .Chart.Name }} # Chart 名称
{{ .Chart.Version }} # Chart 版本
{{ .Chart.AppVersion }} # 应用版本

# Values 对象
{{ .Values.replicaCount }} # values.yaml 中的值

# Files 对象
{{ .Files.Get "config.ini" }} # 读取文件内容

# Capabilities 对象
{{ .Capabilities.KubeVersion }} # Kubernetes 版本

_helpers.tpl 文件

_helpers.tpl 文件用于定义可重用的模板片段,以 _ 开头的文件不会被渲染成 Kubernetes 资源:

{{/*
Expand the name of the chart.
*/}}
{{- define "mychart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
*/}}
{{- define "mychart.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "mychart.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "mychart.labels" -}}
helm.sh/chart: {{ include "mychart.chart" . }}
{{ include "mychart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "mychart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "mychart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

使用定义好的模板:

metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}

创建自定义 Chart

使用命令创建骨架

helm create mychart

这会创建一个完整的 Chart 目录结构,包含常用的模板文件。

编写模板

让我们创建一个简单的 Nginx Chart 作为示例。

values.yaml

replicaCount: 1

image:
repository: nginx
pullPolicy: IfNotPresent
tag: "1.25"

service:
type: ClusterIP
port: 80

ingress:
enabled: false
className: ""
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific

resources: {}

templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "mychart.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "mychart.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.port }}
resources:
{{- toYaml .Values.resources | nindent 12 }}

templates/service.yaml

apiVersion: v1
kind: Service
metadata:
name: {{ include "mychart.fullname" . }}
labels:
{{- include "mychart.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "mychart.selectorLabels" . | nindent 4 }}

验证和调试

# 验证 Chart 语法
helm lint mychart

# 渲染模板查看输出(不安装)
helm template myrelease mychart

# 使用自定义值渲染
helm template myrelease mychart -f custom-values.yaml

# 使用 --dry-run 模拟安装
helm install myrelease mychart --dry-run --debug

打包和分发

# 打包 Chart
helm package mychart

# 这会生成 mychart-1.0.0.tgz 文件

# 本地安装打包好的 Chart
helm install myrelease mychart-1.0.0.tgz

依赖管理

复杂应用通常依赖其他服务。比如 WordPress 依赖 MySQL,可以使用 Chart 依赖来管理这种关系。

定义依赖

Chart.yaml 中定义依赖:

apiVersion: v2
name: myapp
version: 1.0.0
dependencies:
- name: mysql
version: "9.x.x"
repository: https://charts.bitnami.com/bitnami
condition: mysql.enabled

- name: redis
version: "17.x.x"
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled
tags:
- cache

更新依赖

# 下载依赖到 charts/ 目录
helm dependency update myapp

# 查看依赖状态
helm dependency list myapp

条件启用依赖

values.yaml 中控制依赖是否启用:

mysql:
enabled: true
auth:
rootPassword: secret
database: myapp

redis:
enabled: false

子 Chart 配置

子 Chart 的配置通过父 Chart 的 values.yaml 进行:

# 父 Chart 自己的配置
replicaCount: 3

# 子 Chart mysql 的配置
mysql:
enabled: true
auth:
rootPassword: secret
database: myapp

# 子 Chart redis 的配置
redis:
enabled: true
auth:
password: redis-secret

最佳实践

1. 版本控制

将 Chart 纳入 Git 版本控制,每次修改更新 version 字段。

2. 值的文档化

values.yaml 中添加注释说明每个配置项:

# 副本数,生产环境建议设置为 3 或更高
replicaCount: 1

# 镜像配置
image:
repository: nginx
# 镜像标签,建议使用具体版本而非 latest
tag: "1.25"
# 拉取策略:Always, Never, IfNotPresent
pullPolicy: IfNotPresent

3. 使用 values.schema.json 验证

创建 JSON Schema 文件验证用户输入:

{
"$schema": "https://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"replicaCount": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"description": "Number of replicas"
},
"service": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["ClusterIP", "NodePort", "LoadBalancer"]
}
}
}
}
}

4. 使用 --dry-run 验证

在安装或升级前,始终使用 --dry-run 检查:

helm upgrade --install myrelease mychart --dry-run --debug

5. 合理使用标签

使用标准的 Kubernetes 标签:

labels:
app.kubernetes.io/name: myapp
app.kubernetes.io/instance: myrelease
app.kubernetes.io/version: "1.0.0"
app.kubernetes.io/component: frontend
app.kubernetes.io/part-of: myproject
app.kubernetes.io/managed-by: Helm

6. 避免硬编码

不要在模板中硬编码值,全部通过 values.yaml 配置:

# 不好
image: nginx:1.25

# 好
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"

常用命令速查

命令说明
helm repo add <name> <url>添加仓库
helm repo update更新仓库索引
helm search repo <keyword>搜索 Chart
helm show values <chart>查看默认值
helm install <release> <chart>安装 Chart
helm upgrade <release> <chart>升级 Release
helm rollback <release> [revision]回滚 Release
helm uninstall <release>卸载 Release
helm list列出所有 Release
helm history <release>查看历史版本
helm lint <chart>验证 Chart
helm template <release> <chart>渲染模板
helm package <chart>打包 Chart
helm dependency update <chart>更新依赖

小结

本章我们学习了:

  1. Helm 概念:Chart、Release、Repository
  2. 基本使用:安装、升级、回滚、卸载
  3. Chart 结构:目录结构和文件说明
  4. 模板语法:Go 模板和预定义值
  5. 依赖管理:管理 Chart 间的依赖关系
  6. 最佳实践:版本控制、文档化、验证

Helm 大大简化了 Kubernetes 应用的部署和管理,是云原生应用交付的标配工具。

练习

  1. 安装 Helm 并添加 Bitnami 仓库
  2. 使用 Helm 部署一个 WordPress 应用
  3. 创建一个自定义 Chart 并部署
  4. 练习升级和回滚操作
  5. 添加一个依赖(如 Redis)到你的 Chart

参考资料