18-Helm
Helm 是 Kubernetes 的包管理工具,被喻为"K8s 的 apt/yum"。它的核心价值是把散乱的 YAML 模板化、参数化,让同一份 Chart 能部署到多个环境。K8s 路线已覆盖 Helm 基础用法,本章侧重工程化实践——Chart 结构规范、多环境 values 管理、私有仓库与 CI/CD 集成。
Chart 结构#
一个合理的 Chart 目录结构是工程化的基础:
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#
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.enabledvalues.yaml 的双重职责#
values.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 生成:
{{/* 生成应用名称,最长 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 中引用:
metadata:
name: {{ include "my-service.fullname" . }}
labels:
{{- include "my-service.labels" . | nindent 4 }}
spec:
selector:
matchLabels:
{{- include "my-service.selectorLabels" . | nindent 6 }}多环境 values 管理#
用多个 values 文件覆盖默认值是最清晰的多环境管理方式。每个环境文件只写与默认值不同的部分:
# values-dev.yaml
replicaCount: 1
resources:
limits:
cpu: 200m
memory: 256Mi
appEnv: "development"
autoscaling:
enabled: false# 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部署命令:
# 开发环境
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 支持多次使用,后面的文件覆盖前面的值,适合叠加区域特定配置:
helm upgrade --install my-service ./my-service \
-f values-prod.yaml \
-f values-prod-us.yaml \
--set image.tag=v1.2.3常用命令速查#
# 创建新 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 prodhelm-diff 插件(强烈推荐)#
升级前预览变更,避免"盲发":
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 prodChart 仓库与 CI/CD#
推送到 Harbor OCI 仓库#
# 登录
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-chartsCI/CD 自动推送#
#!/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 结构:
# 错误:没有正确缩进
resources:
{{ toYaml .Values.resources }}
# 正确:使用 nindent(自动加换行)
resources:
{{- toYaml .Values.resources | nindent 2 }}坑2:range 循环中的变量作用域#
在 range 循环内访问外层变量(如 .Release.Name)会失效,因为 . 被重新绑定:
# 错误:循环内 .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 渲染时可能类型错误:
# 可能出错
port: {{ .Values.service.port }}
# 始终用 quote 包裹不确定的值
port: {{ .Values.service.port | quote }}坑4:upgrade 时 secret 丢失#
如果 values 中有敏感字段,每次 helm upgrade 都需要重新传入,否则会被重置为默认值。更安全的做法是把敏感配置放进 K8s Secret,通过 envFrom 注入,不放在 values 里。
Helmfile:多 Chart 编排#
当项目有多个相互依赖的 Chart 时,可以用 Helmfile 做编排:
# 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: prodhelmfile -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 的习惯能省不少麻烦。