Helm Chart 结构与模板语法
High Contrast
Dark Mode
Light Mode
Sepia
Forest
1 min read195 words

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

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

下一节安装、升级与回滚