跳过正文

Helm 使用指南:从入门到生产实践

·1312 字·7 分钟·
目录

核心概念
#

在动手之前,先理清四个核心概念的关系:

概念说明类比
ChartHelm 的打包格式,包含一组 K8s 资源模板apt 的 .deb 包
ReleaseChart 在集群中的一次部署实例,有独立名称和版本安装好的软件实例
Repository存放 Chart 的仓库(HTTP 服务)apt 的软件源
Values渲染模板时注入的变量,可层叠覆盖配置文件

一个 Chart 可以在同一集群中安装多次,每次产生一个独立的 Release,互不影响。例如:同一个 redis Chart 可以安装为 redis-cacheredis-session 两个 Release。


安装与配置
#

# 安装 Helm(Linux)
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# 验证
helm version

# 添加常用 Chart 仓库
helm repo add stable https://charts.helm.sh/stable
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo add jetstack https://charts.jetstack.io
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts

# 更新仓库索引
helm repo update

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

常用命令
#

搜索与查看
#

# 在仓库中搜索 Chart
helm search repo nginx

# 查看 Chart 所有可用版本
helm search repo bitnami/redis --versions

# 查看 Chart 的默认 values
helm show values bitnami/redis

# 查看 Chart 详情(README)
helm show readme bitnami/redis

# 查看 Chart 将生成的所有 K8s 资源(不实际部署)
helm template my-redis bitnami/redis -f my-values.yaml

安装
#

# 基础安装
helm install <release-name> <chart> -n <namespace>

# 安装并等待就绪,失败自动回滚(生产推荐)
helm install my-app ./my-chart \
  -n production \
  --create-namespace \
  --wait \
  --timeout 5m \
  --atomic

# 指定 values 文件安装
helm install my-redis bitnami/redis \
  -n database \
  -f values-prod.yaml \
  --set auth.password=mysecretpassword

# 安装指定版本
helm install my-redis bitnami/redis \
  --version 18.6.1 \
  -n database

升级与回滚
#

# 升级 Release
helm upgrade my-app ./my-chart -n production -f values.yaml

# 安装不存在时安装,已存在时升级(CI/CD 常用)
helm upgrade --install my-app ./my-chart \
  -n production \
  --create-namespace \
  -f values.yaml \
  --wait \
  --atomic \
  --timeout 5m

# 查看 Release 历史版本
helm history my-app -n production

# 回滚到指定版本
helm rollback my-app 2 -n production

# 回滚到上一个版本
helm rollback my-app -n production

查看与管理
#

# 列出所有 Release
helm list -A
helm list -n production

# 查看 Release 状态
helm status my-app -n production

# 查看 Release 实际使用的 values(包含默认值)
helm get values my-app -n production
helm get values my-app -n production --all  # 包含所有默认值

# 查看 Release 生成的 manifest
helm get manifest my-app -n production

# 卸载(默认保留历史记录)
helm uninstall my-app -n production

# 卸载并删除历史记录
helm uninstall my-app -n production --keep-history=false

Values 覆盖方式与优先级
#

Helm 支持多层 values 叠加,优先级从低到高:

Chart 内置 values.yaml
  ↓ 被覆盖
-f values-base.yaml
  ↓ 被覆盖
-f values-prod.yaml      ← 多个 -f 后者覆盖前者
  ↓ 被覆盖
--set key=value          ← 最高优先级
# 多文件覆盖(常用于环境差异配置)
helm upgrade --install my-app ./chart \
  -f values/base.yaml \
  -f values/production.yaml \
  --set image.tag=v1.2.3 \
  --set replicaCount=3

# --set 设置嵌套值
--set ingress.hosts[0].host=example.com
--set persistence.storageClass=gp3

# --set-string 强制字符串类型(避免数字被解析为 int)
--set-string annotations."app\.kubernetes\.io/version"=1.0

# --set-file 从文件读取值
--set-file config.nginx=nginx.conf

推荐的多环境 values 目录结构:

chart/
├── values.yaml           # 默认值(所有环境通用)
├── values/
│   ├── base.yaml         # 公共覆盖
│   ├── staging.yaml      # Staging 环境
│   └── production.yaml   # 生产环境

Chart 目录结构
#

my-chart/
├── Chart.yaml            # Chart 元数据(必须)
├── values.yaml           # 默认配置值
├── values.schema.json    # values 校验 Schema(可选,推荐)
├── charts/               # 依赖的子 Chart
├── templates/            # K8s 资源模板
│   ├── _helpers.tpl      # 模板辅助函数(不生成资源)
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── configmap.yaml
│   ├── hpa.yaml
│   └── NOTES.txt         # 安装完成后显示的说明
└── .helmignore           # 打包时忽略的文件

Chart.yaml
#

apiVersion: v2
name: my-app
description: A Helm chart for my application
type: application      # application 或 library
version: 0.1.0         # Chart 版本(语义化版本)
appVersion: "1.2.3"    # 应用版本(字符串)

dependencies:
  - name: redis
    version: "18.x.x"
    repository: https://charts.bitnami.com/bitnami
    condition: redis.enabled   # 可通过 values 控制是否启用

_helpers.tpl — 模板辅助函数
#

{{/*
生成应用完整名称,最多 63 字符
*/}}
{{- define "my-app.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}

{{/*
公共标签
*/}}
{{- define "my-app.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector 标签(不能变,否则会导致 Deployment 无法更新)
*/}}
{{- define "my-app.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

模板语法基础
#

访问 Values
#

# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-app.fullname" . }}
  labels:
    {{- include "my-app.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "my-app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "my-app.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - containerPort: {{ .Values.service.port }}
          env:
            - name: ENV
              value: {{ .Values.env | quote }}        # quote 防止布尔值/数字被误解析
          resources:
            {{- toYaml .Values.resources | nindent 12 }}  # 将 values 中的对象直接渲染为 YAML

if / else 条件
#

{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "my-app.fullname" . }}
  {{- if .Values.ingress.annotations }}
  annotations:
    {{- toYaml .Values.ingress.annotations | nindent 4 }}
  {{- end }}
spec:
  {{- if .Values.ingress.tls }}
  tls:
    {{- range .Values.ingress.tls }}
    - hosts:
        {{- range .hosts }}
        - {{ . | quote }}
        {{- end }}
      secretName: {{ .secretName }}
    {{- end }}
  {{- end }}
{{- end }}

range 循环
#

# 遍历列表
env:
  {{- range .Values.extraEnvVars }}
  - name: {{ .name }}
    value: {{ .value | quote }}
  {{- end }}

# 遍历 map
podAnnotations:
  {{- range $key, $value := .Values.podAnnotations }}
  {{ $key }}: {{ $value | quote }}
  {{- end }}

with 上下文切换
#

{{- with .Values.nodeSelector }}
nodeSelector:
  {{- toYaml . | nindent 8 }}
{{- end }}

{{- with .Values.tolerations }}
tolerations:
  {{- toYaml . | nindent 8 }}
{{- end }}

生产实践
#

必备参数
#

# 生产环境部署标准命令
helm upgrade --install <release> <chart> \
  -n <namespace> \
  --create-namespace \
  -f values.yaml \
  --atomic \          # 失败时自动回滚
  --wait \            # 等待所有资源就绪
  --timeout 10m \     # 超时时间(根据应用启动时间调整)
  --history-max 5 \   # 保留最近 5 个版本
  --cleanup-on-fail   # 失败时清理新创建的资源

values.schema.json — 值校验
#

{
  "$schema": "https://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["image"],
  "properties": {
    "replicaCount": {
      "type": "integer",
      "minimum": 1
    },
    "image": {
      "type": "object",
      "required": ["repository", "tag"],
      "properties": {
        "repository": { "type": "string" },
        "tag": { "type": "string" },
        "pullPolicy": {
          "type": "string",
          "enum": ["Always", "IfNotPresent", "Never"]
        }
      }
    }
  }
}

Chart 依赖管理
#

# 下载依赖(在 Chart 目录下执行)
helm dependency update ./my-chart

# 构建依赖(使用 charts/ 目录中已有的)
helm dependency build ./my-chart

# 查看依赖状态
helm dependency list ./my-chart

常用公共 Chart 安装示例
#

ingress-nginx
#

helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
  -n ingress-nginx \
  --create-namespace \
  --set controller.replicaCount=2 \
  --set controller.resources.requests.cpu=100m \
  --set controller.resources.requests.memory=90Mi \
  --wait

cert-manager
#

# 安装 cert-manager(需要先安装 CRD)
helm upgrade --install cert-manager jetstack/cert-manager \
  -n cert-manager \
  --create-namespace \
  --version v1.13.0 \
  --set installCRDs=true \
  --wait
# 安装完后创建 ClusterIssuer(Let's Encrypt)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
      - http01:
          ingress:
            class: nginx

kube-prometheus-stack
#

# values-monitoring.yaml
cat > values-monitoring.yaml << 'EOF'
grafana:
  adminPassword: "changeme"
  ingress:
    enabled: true
    hosts:
      - grafana.example.com

prometheus:
  prometheusSpec:
    retention: 15d
    storageSpec:
      volumeClaimTemplate:
        spec:
          storageClassName: gp3
          resources:
            requests:
              storage: 50Gi

alertmanager:
  alertmanagerSpec:
    storage:
      volumeClaimTemplate:
        spec:
          storageClassName: gp3
          resources:
            requests:
              storage: 10Gi
EOF

helm upgrade --install kube-prometheus-stack \
  prometheus-community/kube-prometheus-stack \
  -n monitoring \
  --create-namespace \
  -f values-monitoring.yaml \
  --version 55.5.0 \
  --wait \
  --timeout 10m

Helm vs Kustomize 取舍
#

维度HelmKustomize
学习曲线较高(模板语法)较低(纯 YAML)
打包分发强(Chart 仓库)弱(git 引用)
多环境差异values 文件覆盖overlay 目录
参数化能力强(完整模板语言)弱(仅 patch)
官方工具集成完整(Helm Hub)kubectl 内置
版本管理内置(helm history)依赖 git
调试体验helm template 预渲染kustomize build
ArgoCD 支持原生支持原生支持

选型建议:

  • 使用第三方软件(nginx、prometheus、cert-manager)→ 优先选 Helm,这些软件官方维护的 Helm Chart 质量高,直接用
  • 管理自己的业务应用 → Kustomize 更适合,YAML 原生,结构清晰,适合 GitOps
  • 已有 Helm Chart 且需要多环境差异 → Helm + values 多文件
  • 复杂多环境、需要精细 patch → Kustomize 的 overlay 机制更灵活

实际生产中常见方案:第三方依赖用 Helm,自研服务用 Kustomize,ArgoCD 统一管理。


常见问题排查
#

# 查看 Helm 操作历史
helm history my-app -n production

# Release 升级卡住/失败后强制回滚
helm rollback my-app -n production

# 处理 "cannot re-use a name that is still in use" 错误
# 先检查是否真的存在
helm list -A | grep my-app
# 删除后重装
helm uninstall my-app -n production

# 处理 "rendered manifests contain a resource that already exists" 错误
# 通常是 --install 时已有同名资源,用 --replace 或先手动删除冲突资源

# 渲染模板检查(本地验证)
helm template my-app ./chart -f values.yaml | kubectl apply --dry-run=client -f -

# 查看实际部署的资源版本
helm get manifest my-app -n production | grep "image:"
Wenzhuo Huang
作者
Wenzhuo Huang
搞运维的工程师,写代码的运维人。专注 Kubernetes、AWS、GitOps 与基础设施可靠性。这个博客既是我的技术笔记本,也是我踩过的坑的受害者档案。

相关文章

Helm 工程化实践:从 Chart 设计到多环境管理

·1169 字·6 分钟
基于生产踩坑经验,系统梳理 Helm Chart 结构设计、_helpers.tpl 复用技巧、多环境 values 管理策略、私有 Harbor 仓库推送流程,以及 –atomic 升级与回滚的正确姿势。

Kubernetes Ingress 配置实践

·1214 字·6 分钟
从 Ingress 概念到生产实践:nginx/traefik/ALB 选型对比、TLS 自动签发、canary 灰度发布、限速超时等常用 annotations 详解。