路线图

18-Helm

星辉 2026-07-02 阅读 4 min 765 字 路线图
18-Helm 封面

Helm 是 Kubernetes 的包管理工具,被喻为"K8s 的 apt/yum"。它的核心价值是把散乱的 YAML 模板化、参数化,让同一份 Chart 能部署到多个环境。K8s 路线已覆盖 Helm 基础用法,本章侧重工程化实践——Chart 结构规范、多环境 values 管理、私有仓库与 CI/CD 集成。

Chart 结构#

一个合理的 Chart 目录结构是工程化的基础:

text
my-service/
├── Chart.yaml              # Chart 元数据(名称、版本、依赖)
├── values.yaml             # 默认值,也是配置项文档
├── values-dev.yaml         # 开发环境覆盖
├── values-staging.yaml     # 预发环境覆盖
├── values-prod.yaml        # 生产环境覆盖
├── templates/
│   ├── _helpers.tpl        # 公共模板函数(命名、label)
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── configmap.yaml
│   ├── hpa.yaml
│   └── NOTES.txt           # 安装后提示信息
└── charts/                 # 子 Chart 依赖

Chart.yaml#

yaml
apiVersion: v2
name: my-service
description: A Helm chart for my-service
type: application
version: 1.2.3          # Chart 版本(SemVer)
appVersion: "1.2.3"     # 应用版本
dependencies:
  - name: postgresql
    version: 12.x.x
    repository: https://charts.bitnami.com/bitnami   # ⚠ Bitnami 免费 charts 2025-09 起转 Broadcom 订阅/停更;新项目改用 Chainguard(iamguarded) 等 fork 维护版
    condition: postgresql.enabled

values.yaml 的双重职责#

values.yaml 既是默认值提供者,也是配置项的文档——每个字段都应有注释说明用途:

yaml
# values.yaml
replicaCount: 2

image:
  repository: registry.example.com/my-service
  pullPolicy: IfNotPresent
  tag: ""              # 留空,部署时通过 --set image.tag=xxx 传入

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 100m
    memory: 128Mi

autoscaling:
  enabled: false
  minReplicas: 2
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70

_helpers.tpl:模板复用#

_helpers.tpl 集中定义公共模板函数,下划线前缀让 Helm 知道这个文件不会直接渲染为 K8s 资源。最常用的是命名和 label 生成:

yaml
{{/* 生成应用名称,最长 63 字符 */}}
{{- define "my-service.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/* 标准 labels,所有资源都应带上 */}}
{{- define "my-service.labels" -}}
helm.sh/chart: {{ include "my-service.chart" . }}
{{ include "my-service.selectorLabels" . }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/* Selector labels,用于 Service 选择 Pod */}}
{{- define "my-service.selectorLabels" -}}
app.kubernetes.io/name: {{ include "my-service.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

在 Deployment 中引用:

yaml
metadata:
  name: {{ include "my-service.fullname" . }}
  labels:
    {{- include "my-service.labels" . | nindent 4 }}
spec:
  selector:
    matchLabels:
      {{- include "my-service.selectorLabels" . | nindent 6 }}

多环境 values 管理#

用多个 values 文件覆盖默认值是最清晰的多环境管理方式。每个环境文件只写与默认值不同的部分:

yaml
# values-dev.yaml
replicaCount: 1
resources:
  limits:
    cpu: 200m
    memory: 256Mi
appEnv: "development"
autoscaling:
  enabled: false
yaml
# values-prod.yaml
replicaCount: 3
resources:
  limits:
    cpu: 2000m
    memory: 2Gi
  requests:
    cpu: 500m
    memory: 512Mi
appEnv: "production"
autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 20
  targetCPUUtilizationPercentage: 60

部署命令:

bash
# 开发环境
helm upgrade --install my-service ./my-service \
  -f values-dev.yaml \
  --set image.tag=v1.2.3 \
  -n dev

# 生产环境(必加 --atomic)
helm upgrade --install my-service ./my-service \
  -f values-prod.yaml \
  --set image.tag=v1.2.3 \
  -n prod \
  --atomic \
  --timeout 5m \
  --wait

-f 支持多次使用,后面的文件覆盖前面的值,适合叠加区域特定配置:

bash
helm upgrade --install my-service ./my-service \
  -f values-prod.yaml \
  -f values-prod-us.yaml \
  --set image.tag=v1.2.3

常用命令速查#

bash
# 创建新 Chart
helm create my-service

# 渲染模板(本地预览,不部署)
helm template my-service ./my-service -f values-prod.yaml

# 语法检查
helm lint ./my-service

# 安装/升级
helm upgrade --install my-service ./my-service -f values-prod.yaml -n prod

# 查看历史版本
helm history my-service -n prod

# 回滚到上一版本
helm rollback my-service -n prod

# 回滚到指定版本
helm rollback my-service 3 -n prod --wait

# 查看当前值
helm get values my-service -n prod

helm-diff 插件(强烈推荐)#

升级前预览变更,避免"盲发":

bash
helm plugin install https://github.com/databus23/helm-diff

helm diff upgrade my-service ./my-service \
  -f values-prod.yaml \
  --set image.tag=v1.2.4 \
  -n prod

Chart 仓库与 CI/CD#

推送到 Harbor OCI 仓库#

bash
# 登录
helm registry login registry.example.com \
  --username admin \
  --password-stdin <<< "$HARBOR_PASSWORD"

# 打包
helm package ./my-service --version 1.2.3

# 推送(OCI 格式)
helm push my-service-1.2.3.tgz oci://registry.example.com/helm-charts

CI/CD 自动推送#

bash
#!/bin/bash
set -e
CHART_NAME="my-service"
CHART_VERSION="${CI_COMMIT_TAG:-0.0.0-dev}"
REGISTRY="registry.example.com"

sed -i "s/^version:.*/version: ${CHART_VERSION}/" Chart.yaml
sed -i "s/^appVersion:.*/appVersion: \"${CHART_VERSION}\"/" Chart.yaml

helm package .
helm push "${CHART_NAME}-${CHART_VERSION}.tgz" "oci://${REGISTRY}/helm-charts"

常见坑#

坑1:toYaml 缩进#

toYaml 必须配合 nindent 或 indent 使用,否则会破坏 YAML 结构:

yaml
# 错误:没有正确缩进
resources:
  {{ toYaml .Values.resources }}

# 正确:使用 nindent(自动加换行)
resources:
  {{- toYaml .Values.resources | nindent 2 }}

坑2:range 循环中的变量作用域#

在 range 循环内访问外层变量(如 .Release.Name)会失效,因为 . 被重新绑定:

yaml
# 错误:循环内 .Release.Name 为空
{{- range .Values.hosts }}
  - host: {{ . }}
    svc: {{ .Release.Name }}-service
{{- end }}

# 正确:循环前保存外层 context
{{- $releaseName := .Release.Name }}
{{- range .Values.hosts }}
  - host: {{ . }}
    svc: {{ $releaseName }}-service
{{- end }}

坑3:字符串值忘记加 quote#

YAML 中某些值看起来像数字或布尔,Helm 渲染时可能类型错误:

yaml
# 可能出错
port: {{ .Values.service.port }}

# 始终用 quote 包裹不确定的值
port: {{ .Values.service.port | quote }}

坑4:upgrade 时 secret 丢失#

如果 values 中有敏感字段,每次 helm upgrade 都需要重新传入,否则会被重置为默认值。更安全的做法是把敏感配置放进 K8s Secret,通过 envFrom 注入,不放在 values 里。

Helmfile:多 Chart 编排#

当项目有多个相互依赖的 Chart 时,可以用 Helmfile 做编排:

yaml
# helmfile.yaml
releases:
  - name: postgresql
    namespace: db
    chart: bitnami/postgresql   # 同上:Bitnami 已转订阅,评估 Chainguard/RapidFort 等替代
    version: 12.x.x
    values:
      - values/postgresql.yaml

  - name: my-service
    namespace: app
    chart: ./charts/my-service
    values:
      - values/my-service-{{ .Environment.Name }}.yaml
    needs:
      - db/postgresql    # 先部署 postgresql

environments:
  dev:
    values:
      - env: dev
  prod:
    values:
      - env: prod
bash
helmfile -e prod sync    # 部署到 prod
helmfile -e prod diff    # 只 diff 不实际操作

小结#

Helm 工程化的核心就几条:Chart 目录结构和命名要统一,_helpers.tpl 集中放公共模板函数;多环境 values 只写差异,主 values.yaml 保持完整默认值充当文档;生产必用 --atomic,上线前 helm diff 预览变更;私有仓库 + CI/CD 自动推送,版本号对齐 Git tag。最深的坑是 toYaml 缩进和 range 作用域——这两个不会报错,只会悄悄产出错 YAML,养成 helm template 先本地渲染一遍再 upgrade 的习惯能省不少麻烦。