Helm Kubernetes 包管理

适用环境:Kubernetes 1.19+ | Helm 3.x

目标读者:云原生开发 / DevOps / SRE / 运维工程师


一、Helm 是什么?

1.1 核心概念

Helm 是 Kubernetes 的包管理器,类似于 Linux 中的 aptyum,或前端的 npmpip。它将 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 核心概念

概念说明
ChartHelm 包,即一个 Kubernetes 应用的完整描述包(YAML 模板 + 配置)
RepositoryChart 仓库,存储和分发 Chart 的仓库(类似 Docker Hub)
ReleaseChart 的运行实例,同一个 Chart 可以部署多次,每次生成一个 Release
Values配置值,用于渲染 Chart 模板
TemplateGo 模板文件,渲染后生成最终 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
PrometheusPrometheus 官方 Chartprometheus-community.github.io/helm-charts
GrafanaGrafana 官方 Chartgrafana.github.io/helm-charts
Ingress-NGINXNginx Ingress Controllerkubernetes.github.io/ingress-nginx
ElasticELK 官方 Charthelm.elastic.co
HarborHarbor 镜像仓库 Charthelm.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-succeededhook 成功后删除
helm.sh/hook-delete-policy: hook-failedhook 失败后删除

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(主.次.修订)
AppVersionappVersion 是应用本身版本(如 Nginx 1.25),独立于 Chart 版本
默认值values.yaml 中所有值都应有默认值
命名空间使用 {{ .Release.Namespace }} 确保资源在同一命名空间
资源清理卸载时清理 PVC/PV(通过 Helm hook 或 PVC 注解)
安全上下文始终设置 securityContextpodSecurityContext
资源限制必须设置 resources.limits 防止应用耗尽集群资源
健康检查必须设置 livenessProbereadinessProbe

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
喜欢就支持一下吧
点赞12 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容