适用环境:Kubernetes 1.19+ | Helm 3.x
目标读者:云原生开发 / DevOps / SRE / 运维工程师
一、Helm 是什么?
1.1 核心概念
Helm 是 Kubernetes 的包管理器,类似于 Linux 中的 apt、yum,或前端的 npm、pip。它将 Kubernetes 应用打包为 Chart,通过简单的命令实现一键部署、版本管理和配置变更。
传统方式:手动管理 YAML 清单
┌──────────┐ ┌──────────┐ ┌──────────┐
│ ConfigMap │ │ Deploy │ │ Service │
│ .yaml │ │ .yaml │ │ .yaml │
└──────────┘ └──────────┘ └──────────┘
❌ 配置分散、版本混乱、复用困难
Helm 方式:Chart 包管理
┌──────────────────────────────────────────┐
│ my-app-1.0.0.tgz │
│ 包含:Deployment / Service / ConfigMap │
│ 支持:values.yaml 动态配置 │
│ 支持:版本升级 / 回滚 / 卸载 │
└──────────────────────────────────────────┘
✅ 一键部署 / 版本可控 / 参数化配置 / 社区共享
1.2 Helm 核心概念
| 概念 | 说明 |
|---|---|
| Chart | Helm 包,即一个 Kubernetes 应用的完整描述包(YAML 模板 + 配置) |
| Repository | Chart 仓库,存储和分发 Chart 的仓库(类似 Docker Hub) |
| Release | Chart 的运行实例,同一个 Chart 可以部署多次,每次生成一个 Release |
| Values | 配置值,用于渲染 Chart 模板 |
| Template | Go 模板文件,渲染后生成最终 Kubernetes 资源清单 |
1.3 Helm 架构
┌──────────────────────────────────────────────────────────────┐
│ Helm Client (CLI) │
│ helm install / upgrade / rollback / repo │
└──────────────────────────────────────────────────────────────┘
│
┌───────────────┼────────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌──────────────┐
│ Charts │ │ Helm Repo │ │ Kubernetes │
│ (本地) │ │ (远程) │ │ Cluster │
└────────────┘ └────────────┘ └──────────────┘
│
▼
┌──────────────┐
│ Tiller? │
│ (Helm 2) │
│ ❌ 已移除 │
│ (Helm 3) │
└──────────────┘
⚠️ Helm 3 重大变化:移除了 Tiller(服务端组件),改为纯客户端架构,Kubeconfig 直接与集群通信,安全性和运维复杂度大幅降低。
二、安装 Helm
2.1 快速安装(脚本方式)
# Linux / macOS 一键安装
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# 验证安装
helm version
# 输出示例: version.BuildInfo{Version:"v3.14.0", GitCommit:"...")
2.2 包管理器安装
# macOS — Homebrew
brew install helm
# Linux — Snap
sudo snap install helm --classic
# Windows — Chocolatey
choco install kubernetes-helm
2.3 手动安装(二进制)
# 1. 下载对应版本(请根据系统架构选择)
curl -LO https://get.helm.sh/helm-v3.14.0-linux-amd64.tar.gz
# 或 ARM 架构:
curl -LO https://get.helm.sh/helm-v3.14.0-linux-arm64.tar.gz
# 2. 解压
tar -zxvf helm-v3.14.0-linux-amd64.tar.gz
# 3. 移动到 PATH
sudo mv linux-amd64/helm /usr/local/bin/helm
# 4. 清理
rm -rf linux-amd64 helm-v3.14.0-linux-amd64.tar.gz
# 5. 添加官方仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
2.4 补全工具安装
# Bash 补全
helm completion bash >> ~/.bashrc
source ~/.bashrc
# Zsh 补全
helm completion zsh >> ~/.zshrc
source ~/.zshrc
# PowerShell 补全
helm completion powershell >> $PROFILE
2.5 初始化 Azure/阿里云镜像(可选,国内加速)
# 方式一:使用阿里云镜像
export HELM_HOME="$HOME/.helm"
mkdir -p $HELM_HOME/repository
curl -fsSL https://apphub.aliyuncs.com/bash/helm-init.sh | bash
# 方式二:修改 repo URL
helm repo add stable https://apphub.aliyuncs.com/stable
helm repo update
三、Helm 仓库管理
3.1 常用 Chart 仓库
| 仓库 | 说明 | 地址 |
|---|---|---|
| Bitnami | 最大的开源 Chart 仓库 | charts.bitnami.com/bitnami |
| Prometheus | Prometheus 官方 Chart | prometheus-community.github.io/helm-charts |
| Grafana | Grafana 官方 Chart | grafana.github.io/helm-charts |
| Ingress-NGINX | Nginx Ingress Controller | kubernetes.github.io/ingress-nginx |
| Elastic | ELK 官方 Chart | helm.elastic.co |
| Harbor | Harbor 镜像仓库 Chart | helm.goharbor.io |
3.2 仓库操作命令
# 添加仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add grafana https://grafana.github.io/helm-charts
# 更新仓库索引(添加新 Chart 后必须执行)
helm repo update
# 查看已添加的仓库
helm repo list
# 搜索 Chart(搜索官方 Hub)
helm search hub nginx
# 搜索已添加仓库中的 Chart
helm search repo nginx
# 搜索所有可用版本的 Chart
helm search repo redis --versions
# 移除仓库
helm repo remove bitnami
# 列出仓库中的所有 Chart
helm repo index /path/to/local/dir
3.3 构建私有 Chart 仓库
# 1. 创建 Chart
helm create my-chart
# 2. 打包 Chart
helm package my-chart
# 3. 生成 index.yaml
helm repo index . --url https://charts.example.com/my-chart
# 4. 目录结构
# .
# ├── my-chart-0.1.0.tgz
# └── index.yaml
# 5. 在集群中部署私有仓库
# 使用 Nginx 托管或 GitHub Pages / Gitea Pages
四、Chart 结构详解
4.1 标准 Chart 目录结构
my-chart/ # Chart 名称
├── Chart.yaml # Chart 元数据(必须)
├── values.yaml # 默认配置值(必须)
├── values.schema.json # values 校验规则(可选)
├── charts/ # 依赖的子 Chart(可选)
├── templates/ # Kubernetes 资源模板(必须)
│ ├── NOTES.txt # 安装后显示的说明
│ ├── _helpers.tpl # 公共模板函数(以 _ 开头)
│ ├── deployment.yaml # Deployment 资源
│ ├── service.yaml # Service 资源
│ ├── ingress.yaml # Ingress 资源
│ └── configmap.yaml # ConfigMap 资源
├── .helmignore # 打包时忽略的文件
└── README.md # Chart 说明文档(可选)
4.2 Chart.yaml 详解
apiVersion: v2 # Chart API 版本(v2=Helm3, v1=Helm2)
name: my-webapp # Chart 名称
description: A web application Helm chart for Kubernetes # 描述
type: application # 类型:application 或 library
version: 1.0.5 # Chart 版本(语义化版本)
appVersion: "2.1.0" # 应用本身的版本(如 Nginx 2.1.0)
deprecated: false # 是否已弃用
keywords:
- webapp
- nginx
- http
home: https://myapp.example.com # 项目主页
sources:
- https://github.com/myorg/myapp # 源码地址
maintainers: # 维护者
- name: John Doe
email: john@example.com
url: https://john.example.com
dependencies: # 依赖(Helm 3+ 支持)
- name: postgresql
version: "12.x.x"
repository: https://charts.bitnami.com/bitnami
condition: postgresql.enabled
- name: redis
version: "17.x.x"
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled
annotations:
category: WebApplication
licenses: Apache-2.0
4.3 values.yaml 详解
# ── 默认配置值 ──────────────────────────────────────────────
replicaCount: 3
# 镜像配置
image:
repository: nginx
pullPolicy: IfNotPresent
tag: "1.25-alpine"
# 镜像拉取密钥(需要先创建 secret)
imagePullSecrets: []
# - name: my-registry-secret
# 服务账号
serviceAccount:
create: true
name: "" # 不填则自动生成
annotations: {}
# 名称覆盖(影响所有资源名)
nameOverride: ""
fullnameOverride: ""
# 服务配置
service:
type: ClusterIP
port: 80
targetPort: 8080
annotations: {}
# Ingress 配置
ingress:
enabled: true
className: "nginx"
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
hosts:
- host: myapp.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: myapp-tls
hosts:
- myapp.example.com
# 资源限制
resources:
limits:
cpu: 500m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
# 健康检查
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
# 挂载配置
persistence:
enabled: true
storageClass: "nfs-client"
size: 10Gi
accessMode: ReadWriteOnce
# 配置项(注入为环境变量或挂载文件)
config:
LOG_LEVEL: info
DB_HOST: postgres
MAX_CONNECTIONS: "100"
# 节点亲和性
nodeSelector: {}
tolerations: []
affinity: {}
# 开启 PodDisruptionBudget
podDisruptionBudget:
enabled: true
minAvailable: 1
五、模板语法详解
5.1 Go 模板基础
Helm 模板基于 Go 的 text/template,常用语法:
// 引用值(双大括号 + 点号)
{{ .Values.image.repository }}
{{ .Release.Name }} // Release 名称
{{ .Release.Namespace }} // Release 命名空间
{{ .Release.Service }} // 服务名称(固定为 Helm)
{{ .Chart.Name }} // Chart 名称
{{ .Chart.Version }} // Chart 版本
{{ .Chart.AppVersion }} // 应用版本
{{ .Values.replicaCount }} // values.yaml 中的值
// 管道(管道操作,类似 Linux |)
{{ .Values.image.repository | upper | quote }}
// 输出: "NGINX"
{{ .Values.service.port | default 80 }}
// 如果未设置 port,默认使用 80
// with 控制作用域(限定 . 的指向)
{{- with .Values.image }}
image: {{ .repository }}:{{ .tag }}
{{- end }}
// if/else 条件
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
{{- end }}
// define 定义模板(在 _helpers.tpl 中)
{{- define "my-chart.labels" -}}
app: {{ .Chart.Name }}
version: {{ .Chart.Version }}
{{- end }}
// template 调用模板
{{- template "my-chart.labels" . }}
// default 设置默认值
{{ .Values.service.type | default "ClusterIP" }}
// 注释
{{- /* 这是一行注释,不会渲染到输出 */ -}}
5.2 _helpers.tpl 公共模板
templates/_helpers.tpl
{{/*
Expand the name of the chart.
*/}}
{{- define "my-chart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "my-chart.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 "my-chart.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "my-chart.labels" -}}
helm.sh/chart: {{ include "my-chart.chart" . }}
{{ include "my-chart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "my-chart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "my-chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "my-chart.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "my-chart.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
5.3 Deployment 模板示例
templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-chart.fullname" . }}
labels:
{{- include "my-chart.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "my-chart.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "my-chart.selectorLabels" . | nindent 8 }}
annotations:
{{- if .Values.prometheus.enabled }}
prometheus.io/scrape: "true"
prometheus.io/port: "{{ .Values.service.port }}"
prometheus.io/path: "/metrics"
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "my-chart.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
livenessProbe:
{{- toYaml .Values.livenessProbe | nindent 12 }}
readinessProbe:
{{- toYaml .Values.readinessProbe | nindent 12 }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
{{- range $key, $value := .Values.config }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
volumeMounts:
{{- if .Values.persistence.enabled }}
- name: data
mountPath: /data
{{- end }}
volumes:
{{- if .Values.persistence.enabled }}
- name: data
persistentVolumeClaim:
claimName: {{ include "my-chart.fullname" . }}-pvc
{{- end }}
5.4 高级模板技巧
多环境配置(多 values 文件)
# 加载多个 values 文件(后者覆盖前者)
helm install my-app ./my-chart \
-f values.yaml \ # 基础配置
-f values-prod.yaml # 生产环境覆盖
# 使用 --set 覆盖单个值
helm upgrade my-app ./my-chart \
--set replicaCount=5 \
--set image.tag=v2.0.0 \
--set "ingress.hosts[0].host=prod.example.com"
values 文件优先级
命令行 --set ← 优先级最高
values-prod.yaml ← 生产环境
values.yaml ← 默认值(优先级最低)
Chart.yaml (dependencies) ← 子 Chart 的 defaults
lookup 函数(查询集群资源)
# 获取现有 PVC 大小(如果已存在则使用,否则使用默认值)
{{- $pvc := lookup "v1" "PersistentVolumeClaim" .Release.Namespace (include "my-chart.fullname" . ++ "-pvc") }}
{{- $size := index $pvc "spec" "resources" "requests" "storage" | default "10Gi" }}
storage: {{ $size }}
控制流与逻辑
# and / or / not 逻辑
{{- if and .Values.ingress.enabled .Values.tls.enabled }}
{{- end }}
# eq/ne 比较
{{- if eq .Values.environment "production" }}
replicas: 5
{{- else }}
replicas: 2
{{- end }}
# 循环
{{- range $index, $host := .Values.ingress.hosts }}
- host: {{ $host.host }}
paths:
{{- range $host.paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
{{- end }}
{{- end }}
六、常用命令速查
6.1 安装与升级
# 从 Chart 安装(不指定名称,自动生成)
helm install my-nginx bitnami/nginx
# 指定名称安装
helm install my-nginx bitnami/nginx --generate-name
# 指定版本安装
helm install my-nginx bitnami/nginx --version 15.0.0
# 从本地 Chart 安装
helm install my-app ./my-chart
# 带自定义 values 安装
helm install my-app ./my-chart -f my-values.yaml
helm install my-app ./my-chart --set replicaCount=5,service.port=8080
# 查看渲染后的模板(不实际安装)
helm template my-app ./my-chart
helm template my-app ./my-chart --debug
# 升级(如果 release 不存在则安装)
helm upgrade my-app ./my-chart
helm upgrade my-app bitnami/nginx -f values-prod.yaml
# 升级并原子回滚(失败自动回退到上一版本)
helm upgrade my-app ./my-chart --atomic
# 安装或升级(幂等操作,最常用)
helm upgrade --install my-app ./my-chart --wait --timeout 5m
6.2 查看与调试
# 列出所有 release
helm list
helm list -A # 所有命名空间
helm list --pending # 仅列出 Pending 状态
helm list --failed # 仅列出失败
# 查看 release 状态
helm status my-app
# 查看 release 历史
helm history my-app
# 查看 release 详情
helm get all my-app
helm get values my-app # 查看安装时的 values
helm get manifest my-app # 查看渲染后的所有资源清单
helm get hooks my-app # 查看 hooks
# 检查 Chart 语法
helm lint ./my-chart
# 模板调试(显示模板输出)
helm template my-app ./my-chart | kubectl apply --dry-run=server
6.3 回滚与卸载
# 回滚到上一版本
helm rollback my-app
# 回滚到指定版本
helm rollback my-app 3
# 回滚并等待完成
helm rollback my-app --wait
# 卸载 release
helm uninstall my-app
# 卸载但保留历史
helm uninstall my-app --keep-history
# 卸载所有已删除 release(在集群中彻底清理)
helm sha256digests # 仅 Helm 2 需要
6.4 依赖管理
# 更新 Chart 依赖
helm dependency update ./my-chart
# 构建依赖(从 Chart.lock 更新 charts/ 目录)
helm dependency build ./my-chart
# 查看依赖列表
helm dependency list ./my-chart
# 列出已安装 Chart 的所有依赖
helm list -A --dependency-update
七、实战:部署生产级应用
7.1 场景:使用 Helm 部署一个带数据库的 Web 应用
Step 1:创建 Chart
helm create my-webapp
cd my-webapp
Step 2:修改 values.yaml(根据实际需求配置)
Step 3:使用 Helmfile 管理多环境
# helmfile.yaml
# 需要先安装 helmfile: brew install helmfile
repositories:
- name: bitnami
url: https://charts.bitnami.com/bitnami
- name: ingress-nginx
url: https://kubernetes.github.io/ingress-nginx
environments:
dev:
values:
- environments/dev.yaml
prod:
values:
- environments/prod.yaml
releases:
# ── Nginx Ingress ─────────────────────────────────────
- name: ingress-nginx
namespace: ingress-nginx
createNamespace: true
chart: ingress-nginx/ingress-nginx
version: "4.8.0"
condition: ingress-nginx.enabled
values:
- ingress-nginx/values.yaml
# ── 证书管理 ───────────────────────────────────────────
- name: cert-manager
namespace: cert-manager
createNamespace: true
chart: jetstack/cert-manager
version: "1.13.0"
condition: cert-manager.enabled
values:
- cert-manager/values.yaml
# ── 后端应用 ───────────────────────────────────────────
- name: my-webapp
namespace: {{ .Environment.Name }}
createNamespace: true
chart: ./charts/my-webapp
condition: my-webapp.enabled
values:
- my-webapp/values-{{ .Environment.Name }}.yaml
secrets:
- my-webapp/secrets-{{ .Environment.Name }}.yaml.gpg
# environments/dev.yaml
ingress-nginx:
enabled: true
cert-manager:
enabled: false
my-webapp:
enabled: true
replicaCount: 1
service:
type: NodePort
ingress:
enabled: false
resources:
limits:
cpu: 500m
memory: 512Mi
# environments/prod.yaml
ingress-nginx:
enabled: true
cert-manager:
enabled: true
my-webapp:
enabled: true
replicaCount: 5
service:
type: ClusterIP
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
resources:
limits:
cpu: 2000m
memory: 2Gi
podDisruptionBudget:
enabled: true
minAvailable: 2
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 70
Step 4:执行部署
# 部署到开发环境
helmfile --environment dev apply
# 部署到生产环境(确认提示)
helmfile --environment prod apply
# 查看部署状态
helmfile --environment prod status
# 销毁环境
helmfile --environment dev destroy
八、Helm Hooks(生命周期钩子)
8.1 Hook 简介
Helm Hook 允许在 Release 生命周期的特定阶段执行 Job,用于:
| 场景 | 说明 |
|---|---|
| 数据库迁移 | 安装前执行数据库 schema 迁移 |
| 数据备份 | 升级前备份数据 |
| 配置加载 | 安装后加载初始化配置 |
| 证书申请 | 安装前通过 cert-manager 申请证书 |
| 清理工作 | 卸载前执行清理任务 |
8.2 Hook 注解
| 注解 | 说明 |
|---|---|
helm.sh/hook: pre-install | 在模板渲染后、安装前执行 |
helm.sh/hook: post-install | 安装完成后执行 |
helm.sh/hook: pre-upgrade | 升级前执行 |
helm.sh/hook: post-upgrade | 升级完成后执行 |
helm.sh/hook: pre-rollback | 回滚前执行 |
helm.sh/hook: post-rollback | 回滚后执行 |
helm.sh/hook: pre-delete | 删除前执行 |
helm.sh/hook: post-delete | 删除后执行 |
helm.sh/hook: test | 执行测试 |
helm.sh/hook-weight: "-1" | 越小越先执行 |
helm.sh/hook-delete-policy: before-hook-creation | 新 hook 启动前删除旧 hook |
helm.sh/hook-delete-policy: hook-succeeded | hook 成功后删除 |
helm.sh/hook-delete-policy: hook-failed | hook 失败后删除 |
8.3 Hook 示例:数据库迁移 Job
templates/job-migrate.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "my-chart.fullname" . }}-migrate
labels:
{{- include "my-chart.labels" . | nindent 4 }}
annotations:
# 安装前执行,执行权重为 -1(优先于其他 hook)
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-weight: "-1"
# 如果 Job 已存在,新执行前先删除旧的
helm.sh/hook-delete-policy: before-hook-creation
spec:
backoffLimit: 3
template:
metadata:
labels:
{{- include "my-chart.labels" . | nindent 8 }}
spec:
restartPolicy: OnFailure
containers:
- name: migrate
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
command:
- /bin/sh
- -c
- |
echo "Running database migrations..."
./migrate.sh
env:
- name: DATABASE_URL
value: {{ .Values.config.database_url | quote }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
8.4 Hook 示例:备份 Job
templates/job-backup.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "my-chart.fullname" . }}-backup
labels:
{{- include "my-chart.labels" . | nindent 4 }}
annotations:
# 升级前执行
helm.sh/hook: pre-upgrade
helm.sh/hook-weight: "1"
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: bitnami/minideb:stretch
command:
- /bin/sh
- -c
- |
echo "Backing up data before upgrade..."
tar czf /backup/data-$(date +%Y%m%d%H%M%S).tar.gz /data
# 上传到对象存储(需配置 credentials)
# rclone copy /backup s3:my-bucket/backups/
volumeMounts:
- name: data
mountPath: /data
- name: backup
mountPath: /backup
volumes:
- name: data
persistentVolumeClaim:
claimName: {{ include "my-chart.fullname" . }}-pvc
- name: backup
emptyDir: {}
九、测试与质量保障
9.1 Chart 测试(Helm Test)
templates/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "my-chart.fullname" . }}-test-connection"
labels:
{{- include "my-chart.labels" . | nindent 4 }}
annotations:
helm.sh/hook: test
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
spec:
restartPolicy: Never
containers:
- name: wget
image: busybox:1.36
command:
- /bin/sh
- -c
- |
echo "Testing application endpoint..."
wget -q --spider --timeout=5 http://{{ include "my-chart.fullname" . }}:{{ .Values.service.port }}/health
EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
echo "✅ Health check passed!"
else
echo "❌ Health check failed!"
exit 1
fi
# 运行测试
helm test my-app
helm test my-app --logs # 查看测试日志
# 运行特定测试
helm test my-app --filter name=test-connection
9.2 CI/CD 中集成 Helm 测试
# .gitlab-ci.yml
stages:
- test
- build
- deploy
helm-lint:
stage: test
image: alpine/helm:3.14
script:
- helm lint ./my-chart
- helm template my-app ./my-chart --debug | kubeval --strict
- helm test ./my-chart --cleanup
helm-deploy:
stage: deploy
image: alpine/helm:3.14
script:
- kubectl config use-context production
- helm upgrade --install my-app ./my-chart --wait --timeout 10m --atomic
environment:
name: production
only:
- main
9.3 OCI 镜像支持(Helm 3.8+)
# 启用 OCI 支持
export HELM_EXPERIMENTAL_OCI=1
# 登录镜像仓库
helm registry login registry.example.com
# 打包 Chart 为 OCI 格式
helm chart save ./my-chart registry.example.com/my-chart:v1.0.0
# 推送 Chart 到仓库
helm chart push registry.example.com/my-chart:v1.0.0
# 拉取 Chart
helm chart pull registry.example.com/my-chart:v1.0.0
# 安装 OCI Chart
helm install my-app oci://registry.example.com/my-chart --version v1.0.0
十、常见问题排错
❌ 问题 1:render 失败 — 模板语法错误
# 错误示例
# Error: UPGRADE FAILED: template: my-chart/templates/deployment.yaml: error
# during parsee: unexpected "}"
# 排查:
helm template my-app ./my-chart --debug
# 常见原因:
# 1. {{ }} 中使用了大括号但未转义
# 解决:在 {{ $data := "{" }} 中使用引号包裹
# 2. YAML 缩进使用了 Tab
# 解决:全部使用空格
# 3. Go 模板注释 {{/* ... */}} 未正确闭合
❌ 问题 2:values 覆盖不生效
# 排查步骤:
# 1. 查看当前生效的 values
helm get values my-app
# 2. 查看合并后的完整 values(包含默认值)
helm get values my-app --all
# 3. 对比命令行传入的参数
helm upgrade my-app ./my-chart --dry-run --debug
# 4. 常见原因:
# - values 文件路径错误
# - key 名称不匹配(区分大小写)
# - 多文件优先级问题
❌ 问题 3:资源未创建/状态卡在 Pending
# 1. 检查 release 状态
helm status my-app
# 2. 查看失败原因
helm history my-app
helm get manifest my-app
# 3. 检查集群资源
kubectl get all -n <namespace>
kubectl describe pod -n <namespace>
# 4. 检查 PVC 绑定状态
kubectl get pvc
# 5. 检查 Helm 是否在等待
helm list --pending
❌ 问题 4:升级失败无法回滚
# 手动回滚
helm rollback my-app <revision-number>
helm history my-app
# 查看失败详情
kubectl get events -n <namespace> --sort-by='.lastTimestamp'
# 如果 release 卡在 pending-upgrade
kubectl get pod -n <namespace>
# 删除卡住的 pod,Helm 会重新调度
❌ 问题 5:Chart 依赖无法解析
# 更新依赖
helm dependency update ./my-chart
# 查看依赖列表
helm dependency list ./my-chart
# 检查 Chart.yaml 中 repository 地址是否正确
# 如果在内网环境,需要先添加对应仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# 如果使用私有 Chart 仓库
helm repo add my-private https://charts.example.com --username admin --password <token>
❌ 问题 6:Ingress 证书申请失败
# 检查 cert-manager 状态
kubectl get pod -n cert-manager
# 检查 Certificate 资源
kubectl describe certificate myapp-tls
# 检查 CertificateRequest
kubectl get certificaterequest
kubectl describe certificaterequest <name>
# 查看 cert-manager 日志
kubectl logs -n cert-manager deploy/cert-manager
❌ 问题 7:权限不足(RBAC)
# 错误:failed to create: ... is forbidden: cannot set block ownership
# 解决:创建 ServiceAccount 并绑定 RBAC
# templates/rbac.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "my-chart.fullname" . }}
labels:
{{- include "my-chart.labels" . | nindent 4 }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "my-chart.fullname" . }}
labels:
{{- include "my-chart.labels" . | nindent 4 }}
rules:
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "my-chart.fullname" . }}
labels:
{{- include "my-chart.labels" . | nindent 4 }}
subjects:
- kind: ServiceAccount
name: {{ include "my-chart.fullname" . }}
namespace: {{ .Release.Namespace }}
roleRef:
kind: Role
name: {{ include "my-chart.fullname" . }}
apiGroup: rbac.authorization.k8s.io
❌ 问题 8:Chart 版本冲突
# 查看已安装 Chart 版本
helm list --all
# 强制升级(忽略版本检查)
helm upgrade my-app ./my-chart --force
# 查看当前 release 的 Chart 版本
helm show chart ./my-chart
# 卸载后重装(最后手段)
helm uninstall my-app --keep-history
helm install my-app ./my-chart
十一、Helm 最佳实践
11.1 Chart 编写规范
| 规范 | 说明 |
|---|---|
| 语义化版本 | Chart 版本使用 SemVer2(主.次.修订) |
| AppVersion | appVersion 是应用本身版本(如 Nginx 1.25),独立于 Chart 版本 |
| 默认值 | values.yaml 中所有值都应有默认值 |
| 命名空间 | 使用 {{ .Release.Namespace }} 确保资源在同一命名空间 |
| 资源清理 | 卸载时清理 PVC/PV(通过 Helm hook 或 PVC 注解) |
| 安全上下文 | 始终设置 securityContext 和 podSecurityContext |
| 资源限制 | 必须设置 resources.limits 防止应用耗尽集群资源 |
| 健康检查 | 必须设置 livenessProbe 和 readinessProbe |
11.2 values 命名规范
# ✅ 推荐:使用嵌套结构
image:
repository: nginx
tag: "1.25-alpine"
pullPolicy: IfNotPresent
# ❌ 避免:所有 key 平铺
nginxImage: nginx
nginxTag: "1.25-alpine"
nginxPullPolicy: IfNotPresent
11.3 生产环境检查清单
部署前检查:
□ Chart 已通过 helm lint
□ 模板已通过 helm template --debug 渲染验证
□ 已设置合理的资源限制(CPU / 内存)
□ 已配置 liveness/readiness Probe
□ 已配置 PodDisruptionBudget(多副本应用)
□ 已配置 HorizontalPodAutoscaler(如需)
□ Ingress TLS 证书已就绪
□ 敏感配置使用 Secret/values.secret
□ 回滚方案已测试(helm history / helm rollback)
□ 监控告警已配置(Prometheus metrics endpoint)
附录:命令速查表
# 基础操作
helm create <name> # 创建新 Chart
helm package <chart> # 打包 Chart
helm repo add <name> <url> # 添加仓库
helm repo update # 更新仓库索引
helm search hub <keyword> # 搜索官方 Hub
helm search repo <keyword> # 搜索本地仓库
# 安装与升级
helm install <name> <chart> # 安装
helm upgrade <name> <chart> # 升级
helm upgrade --install <name> <chart> # 安装或升级(幂等)
helm rollback <name> [rev] # 回滚
helm uninstall <name> # 卸载
# 查看
helm list -A # 列出所有 release
helm get all <name> # 查看 release 详情
helm get values <name> # 查看 values
helm get manifest <name> # 查看渲染后的清单
helm status <name> # 查看 release 状态
helm history <name> # 查看版本历史
helm template <name> <chart> # 本地渲染模板
# 调试
helm lint <chart> # 检查 Chart 语法
helm template <name> <chart> --debug # 渲染并调试
helm test <name> # 运行测试
helm pull <chart> # 拉取 Chart 到本地
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END














暂无评论内容