Helm Chart 结构与模板语法
核心问题:用
kubectl apply一堆 YAML 文件管理应用太麻烦——Helm 怎样把 Kubernetes 应用打包成可配置、可版本化的"包"?
什么是 Helm
Helm 是 Kubernetes 的包管理器,类比:
- Helm ≈ apt / brew(包管理器)
- Chart ≈ deb / formula(包格式)
- Release ≈ 安装实例(一个 Chart 可安装多个 Release)
graph LR
CHART["Helm Chart
(带参数的 K8s YAML 模板集合)"] VALUES["values.yaml
(默认参数)"] OVERRIDE["自定义 values
(环境差异)"] K8S["Kubernetes 集群
(实际资源)"] CHART + VALUES + OVERRIDE -->|helm install / upgrade| K8S
(带参数的 K8s YAML 模板集合)"] VALUES["values.yaml
(默认参数)"] OVERRIDE["自定义 values
(环境差异)"] K8S["Kubernetes 集群
(实际资源)"] CHART + VALUES + OVERRIDE -->|helm install / upgrade| K8S
Chart 目录结构
my-app/ # Chart 名称
├── Chart.yaml # Chart 元数据(必须)
├── values.yaml # 默认参数(必须)
├── templates/ # K8s YAML 模板(必须)
│ ├── _helpers.tpl # 模板辅助函数(下划线开头不生成资源)
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── serviceaccount.yaml
│ ├── hpa.yaml
│ └── NOTES.txt # 安装后显示的说明文字
├── charts/ # 子 Chart 依赖目录
└── Chart.lock # 依赖版本锁文件
Chart.yaml
# Chart.yaml
apiVersion: v2 # Helm 3 使用 v2
name: my-app
description: My Application Helm Chart
type: application # application | library
version: "1.2.3" # Chart 版本(每次更新 Chart 要递增)
appVersion: "v2.1.0" # 应用版本(对应镜像 tag)
keywords:
- nodejs
- api
dependencies:
- name: postgresql
version: "13.2.0"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled # 可通过 values 开关控制
- name: redis
version: "18.1.0"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled
values.yaml:默认参数
# values.yaml
replicaCount: 2
image:
repository: myorg/my-app
tag: "" # 空值 = 使用 Chart.yaml 中的 appVersion
pullPolicy: IfNotPresent
imagePullSecrets: []
service:
type: ClusterIP
port: 80
targetPort: 3000
ingress:
enabled: false
className: nginx
annotations: {}
hosts:
- host: my-app.example.com
paths:
- path: /
pathType: Prefix
tls: []
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
autoscaling:
enabled: false
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 60
env: {}
# NODE_ENV: production
# LOG_LEVEL: warn
config:
dbHost: "postgres.default.svc.cluster.local"
dbPort: 5432
postgresql:
enabled: false # 是否安装 PostgreSQL 子 Chart
nodeSelector: {}
tolerations: []
affinity: {}
_helpers.tpl:模板辅助函数
{{/* _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 }}
{{/*
公共 labels(所有资源都加)
*/}}
{{- define "my-app.labels" -}}
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | quote }}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Values.image.tag | default .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "my-app.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
镜像 tag:优先 values.image.tag,默认 appVersion
*/}}
{{- define "my-app.image" -}}
{{- printf "%s:%s" .Values.image.repository (.Values.image.tag | default .Chart.AppVersion) }}
{{- end }}
templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-app.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "my-app.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "my-app.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "my-app.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
image: {{ include "my-app.image" . | quote }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
{{- if .Values.env }}
env:
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
内置对象
| 对象 | 说明 | 示例 |
|---|---|---|
.Release.Name | Release 名称 | my-app-prod |
.Release.Namespace | 安装的命名空间 | production |
.Release.IsInstall | 是否首次安装 | true |
.Release.IsUpgrade | 是否升级 | false |
.Chart.Name | Chart 名称 | my-app |
.Chart.Version | Chart 版本 | 1.2.3 |
.Chart.AppVersion | 应用版本 | v2.1.0 |
.Values | values.yaml 的值 | .Values.replicaCount |
.Files | 访问 Chart 中的文件 | .Files.Get "config.json" |
模板调试命令
# 渲染模板(不安装,只输出 YAML)
helm template my-release ./my-app -f values/prod.yaml
# 调试模式(输出详细信息)
helm template my-release ./my-app --debug
# 验证 Chart 格式
helm lint ./my-app
# 验证 + 渲染 + 对比集群当前状态
helm diff upgrade my-release ./my-app -f values/prod.yaml
# 需要安装 helm-diff 插件:helm plugin install https://github.com/databus23/helm-diff
下一节:安装、升级与回滚