3. 模板引擎入门:Go模板语法基础、{{ .Values }} 上下文、模板函数与管道
Helm 的核心能力在于通过 Go 模板引擎 将静态的 YAML 清单转化为动态、可配置的部署描述。本章将系统讲解模板引擎的三大支柱:基础语法、数据上下文(.Values)以及模板函数与管道操作。掌握这些知识后,你就能理解 Helm 如何将 values.yaml 中的参数注入到模板文件中,实现“一份模板,多环境复用”。
3.1 Go 模板语法基础
Helm 使用 Go 标准库 text/template 作为模板引擎,并扩展了 sprig 函数库。所有模板指令都包裹在双花括号 {{ }} 中,称为“动作(action)”。
3.1.1 动作类型速查表
| 动作类型 | 语法示例 | 说明 |
|---|---|---|
| 输出值 | {{ .Values.replicaCount }} |
将上下文中的值渲染到当前位置 |
| 注释 | {{/* 这是注释 */}} |
注释不会出现在最终输出中 |
| 条件判断 | {{ if .Values.enabled }} ... {{ end }} |
根据布尔值或存在性控制输出 |
| 循环迭代 | {{ range .Values.ports }} ... {{ end }} |
遍历数组或 map,每次迭代会重置上下文 |
| 变量赋值 | {{ $name := .Values.name }} |
在模板内定义临时变量,以 $ 开头 |
| with 作用域 | {{ with .Values.database }} ... {{ end }} |
将上下文点 . 临时切换为指定对象 |
3.1.2 条件与循环实战
以下是一个典型的 Deployment 模板片段,展示了条件判断和循环的配合使用:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.name | default "my-app" }}
spec:
replicas: {{ .Values.replicaCount }}
template:
spec:
containers:
- name: {{ .Values.name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
{{- range .Values.service.ports }}
- containerPort: {{ .port }}
protocol: {{ .protocol | default "TCP" }}
{{- end }}
{{- if .Values.env }}
env:
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- end }}
{{- 和 -}} 中使用短横线可以去除模板动作前后的空白字符,避免 YAML 格式错误。例如 {{- range }} 会吃掉前面的换行和缩进。
3.2 {{ .Values }} 上下文:数据从哪里来?
在 Helm 模板中,. 代表当前上下文(context)。默认情况下,顶级上下文 . 指向整个 values 对象,因此 {{ .Values }} 就是访问用户提供的所有配置值。
3.2.1 上下文层级结构
Helm 在渲染模板时,会将多个来源的值合并为一个全局上下文。其优先级从高到低为:
- 用户命令行传入:
--set或--set-string参数 - 用户自定义 values 文件:
-f my-values.yaml - Chart 包内的 values.yaml:默认值文件
- Chart 内置的全局变量:如
.Chart、.Release、.Files
以下 SVG 展示了 Helm 模板渲染时的上下文数据流:
3.2.2 内置上下文对象
除了 .Values,Helm 还提供了几个重要的内置对象,可以在模板中直接引用:
| 对象 | 类型 | 常用字段 | 示例 |
|---|---|---|---|
.Chart |
对象 | .Name, .Version, .AppVersion |
{{ .Chart.Name }}-{{ .Chart.Version }} |
.Release |
对象 | .Name, .Namespace, .IsInstall, .IsUpgrade |
{{ .Release.Name }}-svc |
.Files |
对象 | .Get, .GetBytes, .Glob |
{{ .Files.Get "config/app.conf" }} |
.Capabilities |
对象 | .APIVersions, .KubeVersion |
{{ .Capabilities.KubeVersion.Version }} |
range 或 with 块内部,. 会被重新赋值为当前迭代元素或指定对象。如果需要访问全局 .Values,必须使用 $.Values($ 始终指向根上下文)。
3.3 模板函数与管道
Helm 内置了超过 100 个模板函数,涵盖字符串处理、数学运算、类型转换、日期格式化、编码解码等场景。这些函数可以通过 管道(pipeline) 机制串联使用,形成强大的数据处理链。
3.3.1 常用函数分类
| 类别 | 函数 | 作用 | 示例 |
|---|---|---|---|
| 字符串 | quote, upper, lower, trim, replace |
格式化与清理字符串 | {{ .Values.name | upper | quote }} |
| 默认值 | default |
当值为空或 nil 时提供回退值 | {{ .Values.port | default 8080 }} |
| 类型转换 | int, float64, toString, toJson |
强制类型转换 | {{ .Values.replicas | int }} |
| 集合操作 | has, uniq, first, last, merge |
列表与字典处理 | {{ has "prod" .Values.envs }} |
| 编码 | b64enc, b64dec, fromYaml, toYaml |
Base64 与 YAML 互转 | {{ .Values.secret | b64enc }} |
| 逻辑 | and, or, not, eq, ne, empty |
条件判断辅助 | {{ if and .Values.enabled (not .Values.paused) }} |
3.3.2 管道链:从数据到输出
管道(|)将前一个命令的输出作为后一个命令的输入,形成从左到右的数据流。以下是一个典型的管道链:
{{- /* 原始值:imageTag: "v1.0.0-beta" */ -}}
{{- $safeTag := .Values.imageTag | lower | replace "+" "-" | trimSuffix "-beta" | default "latest" -}}
image: myapp:{{ $safeTag }}
上述管道链的执行过程:
lower:将标签转为小写replace "+" "-":将加号替换为短横线(符合 Docker 标签规范)trimSuffix "-beta":移除末尾的-beta后缀default "latest":如果结果为空,则使用latest
最终输出:image: myapp:v1.0.0
toYaml 函数可以将复杂的嵌套结构直接输出为 YAML 格式,避免手动拼接。例如 {{ .Values.resources | toYaml | nindent 8 }} 可以将 resources 对象缩进 8 个空格后嵌入到 Deployment 模板中。
3.3.3 函数与管道在模板中的位置
以下 SVG 展示了模板函数和管道在 Helm 模板渲染流程中的具体位置:
3.4 综合示例:从 values.yaml 到 Deployment
将以上知识点串联起来,看一个完整的实战案例。假设 values.yaml 内容如下:
replicaCount: 3
image:
repository: nginx
tag: "1.25.0"
service:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 80
- name: https
port: 443
targetPort: 443
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "250m"
memory: "256Mi"
env:
LOG_LEVEL: info
NODE_ENV: production
对应的 Deployment 模板(templates/deployment.yaml)可以这样写:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-{{ .Chart.Name }}
labels:
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
replicas: {{ .Values.replicaCount | default 1 }}
selector:
matchLabels:
app.kubernetes.io/name: {{ .Chart.Name }}
template:
metadata:
labels:
app.kubernetes.io/name: {{ .Chart.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
{{- range .Values.service.ports }}
- containerPort: {{ .targetPort | default .port }}
name: {{ .name }}
protocol: TCP
{{- end }}
env:
{{- range $key, $value := .Values.env }}
- name: {{ $key | upper }}
value: {{ $value | quote }}
{{- end }}
resources:
{{- .Values.resources | toYaml | nindent 12 }}
{{ .Release.Name }}和{{ .Chart.Name }}来自内置上下文,确保资源名称唯一range遍历 ports 列表,targetPort | default .port提供安全回退range $key, $value := .Values.env遍历 map,$key | upper将环境变量名转为大写toYaml | nindent 12将 resources 对象格式化为 YAML 并缩进 12 个空格