文章目录
变量
1. 概念
函数、管道符、对象和控制结构都可以控制,我们转向很多编程语言中更基本的思想之一:变量
。 在模板中,很少被使用。但是我们可以使用变量简化代码,并更好地使用 with 和 range。
在例子中,我们看到下面的代码会失败:
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ .Release.Name }}
{{- end }}
Release.Name 不在 with 块的限制范围内。解决作用域问题的一种方法是将对象分配给可以不考虑当前作用域而访问的变量。
2. 语法格式
Helm模板中,变量是对另一个对象的命名引用。遵循 $name 变量的格式且指定了一个特殊的赋值运算符::=
。 我们可以使用针对 Release.Name 的变量重写上述内容。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- $relname := .Release.Name -}}
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ $relname }}
{{- end }}
说明: 在 with 块开始之前,赋值
$relname := .Release.Name
。 现在在 with 块中,$relname 变量仍会执行版本名称
# 运行结果
apiVersion: v1
kind: ConfigMap
metadata:
name: viable-badger-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
release: viable-badger
3. 示例
数据结构为单一数据
- value.yaml
# values.yaml
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
- 定义模板
变 量 在 变量在 变量在range
循 环 中 特 别 有 用 。 可 以 用 于 类 似 列 表 的 对 象 , 以 捕 获 索 引 和 值 循环中特别有用。可以用于类似列表的对象,以捕获索引和值 循环中特别有用。可以用于类似列表的对象,以捕获索引和值
toppings: |-
{{- range $index, $topping := .Values.pizzaToppings }}
{{ $index }}: {{ $topping }}
{{- end }}
- 输出结果
注 意 先 是 注意先是 注意先是range
, 然 后 是 变 量 , 然 后 是 赋 值 运 算 符 , 然 后 是 列 表 。 会 将 整 型 索 引 ( 从 0 开 始 ) 赋 值 给 ,然后是变量,然后是赋值运算符,然后是列表。会将整型索引(从0开始)赋值给 ,然后是变量,然后是赋值运算符,然后是列表。会将整型索引(从0开始)赋值给$index
并 将 值 赋 值 给 并将值赋值给 并将值赋值给$topping
toppings: |-
0: mushrooms
1: cheese
2: peppers
3: onions
数据结构有key和value
- values.yaml
favorite:
drink: coffee
food: pizza
- 定义模板
对 于 数 据 结 构 有 对于数据结构有 对于数据结构有 key 和 和 和 value , 可 以 使 用 ,可以使用 ,可以使用 range 获 取 获取 获取 key 和 和 和 value 。 比 如 , 可 以 通 过 。比如,可以通过 。比如,可以通过.Values.favorite
进 行 循 环 进行循环 进行循环
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
- 输出结果
第 一 次 迭 代 , 第一次迭代, 第一次迭代,$key
会 是 会是 会是 drink 且 且 且$val
会 是 会是 会是 coffee , 第 二 次 迭 代 ,第二次迭代 ,第二次迭代$key
会 是 会是 会是 food 且 且 且$val
会 是 会是 会是 pizza
apiVersion: v1
kind: ConfigMap
metadata:
name: eager-rabbit-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
4. 补充说明
变量一般不是"全局的"
。作用域是其声明所在的块。上面我们在模板的顶层赋值了 $relname。变量的作用域会是整个模板。 但在最后一个例子中 $key 和 $val 作用域会在{{ range... }}{{ end }}
块内。
但有个变量一直是全局的 - $ -
这个变量一直是指向根的上下文。当在一个范围内循环时会很有用,同时你要知道chart的版本名称。
{{- range .Values.tlsSecrets }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .name }}
labels:
# Many helm templates would use `.` below, but that will not work,
# however `$` will work here
app.kubernetes.io/name: {{ template "fullname" $ }}
# I cannot reference .Chart.Name, but I can do $.Chart.Name
helm.sh/chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}"
app.kubernetes.io/instance: "{{ $.Release.Name }}"
# Value from appVersion in Chart.yaml
app.kubernetes.io/version: "{{ $.Chart.AppVersion }}"
app.kubernetes.io/managed-by: "{{ $.Release.Service }}"
type: kubernetes.io/tls
data:
tls.crt: {{ .certificate }}
tls.key: {{ .key }}
---
{{- end }}
命名模板
1. 概念
命名模板 (有时称作一个 部分
或一个 子模板
) 仅仅是在文件内部定义的模板,并使用了一个名字。有两种创建方式和几种不同的使用方法。
三种声明和管理模板的方法
define
在模板中声明一个新的命名模板template
导入一个命名模板block
声明一种特殊的可填充的模板块
注意:
模板名称是全局的
。如果您想声明两个相同名称的模板,哪个最后加载就使用哪个。 因为在子 chart 中的模板和顶层模板一起编译,命名时要注意 chart 特定名称。- 一个常见的命名惯例是用 chart 名称作为模板前缀:
{{ define "mychart.labels" }}
。使用特定 chart 名称作为前缀可以避免可能因为 两个不同 chart 使用了相同名称的模板而引起的冲突。
2. 局部的和 _文件
单个文件中包含了单个模板。但Helm的模板语言允许你创建命名的嵌入式模板, 这样就可以在其他位置按名称访问。
templates/
中的大多数文件被视为包含 Kubernetes 清单NOTES.txt
是个例外- 命名以下划线
(_)
开始的文件则假定 没有 包含清单内容。这些文件不会渲染为 Kubernetes 对象定义,但在其他 chart 模板中都可用
这些文件用来存储局部和辅助对象,实际上当我们第一次创建mychart时,会看到一个名为_helpers.tpl的文件,这个文件时模板局部的默认位置
3. define 和 template 声明和使用模板
define 操作允许我们在模板文件中创建一个命名模板
{{ define "MY.NAME" }}
# body of template here
{{ end }}
- 定义一个模板封装 Kubernetes 的标签:
default
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
- 将模板嵌入到了已有的配置映射中:
template
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
{{- template "mychart.labels" }}
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
- 渲染结果
当 模 板 引 擎 读 取 该 文 件 时 , 它 会 存 储 当模板引擎读取该文件时,它会存储 当模板引擎读取该文件时,它会存储 mychart.labels 的 引 用 直 到 的引用直到 的引用直到template "mychart.labels"
被 调 用 。 然 后 会 按 行 渲 染 模 板 被调用。 然后会按行渲染模板 被调用。然后会按行渲染模板
apiVersion: v1
kind: ConfigMap
metadata:
name: running-panda-configmap
labels:
generator: helm
date: 2021-05-16
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
注意:define 不会有输出,除非像本示例一样用模板调用它。
4. _helpers.tpl 文件
Helm chart 将这些模板放置在局部文件中,一般是 _helpers.tpl
- 定义模板
# _helpers.tpl
{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
说明:define 方法会有个简单的文档块
{{/* ... */}}
来描述要做的事
- 调用模板
尽 管 这 个 定 义 是 在 尽管这个定义是在 尽管这个定义是在 _helpers.tpl 中 , 但 它 仍 能 访 问 中,但它仍能访问 中,但它仍能访问 configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
{{- template "mychart.labels" }}
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
5. include方法
- 假设定义了一个简单模板如下:
{{- define "mychart.app" -}}
app_name: {{ .Chart.Name }}
app_version: "{{ .Chart.Version }}"
{{- end -}}
- 需求:我想把这个插入到模板的 labels: 部分和 data: 部分:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
labels:
{{ template "mychart.app" . }}
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
{{ template "mychart.app" . }}
- 输出错误信息
$ helm install --dry-run measly-whippet ./mychart
Error: unable to build kubernetes objects from release manifest: error validating "": error validating data: [ValidationError(ConfigMap): unknown field "app_name" in io.k8s.api.core.v1.ConfigMap, ValidationError(ConfigMap): unknown field "app_version" in io.k8s.api.core.v1.ConfigMap]
要查看渲染了什么,可以用
--disable-openapi-validation
参数重新执行:helm install --dry-run --disable-openapi-validation measly-whippet ./mychart
apiVersion: v1
kind: ConfigMap
metadata:
name: measly-whippet-configmap
labels:
app_name: mychart
app_version: "0.1.0"
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
app_name: mychart
app_version: "0.1.0"
注意: 两处的 app_version 缩进都不对,为啥?因为被替换的模板中文本是左对齐的。由于 template 是一个行为,不是方法,无法将 template 调用的输出传给其他方法,数据只是简单地按行插入
- 修改模板
Helm 提 供 了 一 个 提供了一个 提供了一个 template 的 可 选 项 , 可 以 将 模 板 内 容 导 入 当 前 管 道 , 然 后 传 递 给 管 道 中 的 其 他 方 法 , 使 用 的可选项,可以将模板内容导入当前管道,然后传递给管道中的其他方法,使用 的可选项,可以将模板内容导入当前管道,然后传递给管道中的其他方法,使用 indent 正 确 地 缩 进 正确地缩进 正确地缩进 mychart.app 模 板 模板 模板
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
labels:
{{ include "mychart.app" . | indent 4 }}
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
{{ include "mychart.app" . | indent 2 }}
- 输出信息
apiVersion: v1
kind: ConfigMap
metadata:
name: edgy-mole-configmap
labels:
app_name: mychart
app_version: "0.1.0"
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
app_name: mychart
app_version: "0.1.0"
6. 补充说明
- Helm 模板中使用 include 而不是 template 被认为是更好的方式 只是为了更好地处理YAML文档的输出格式。
- 有时我们需要导入内容,但不是作为模板,也就是按字面意义导入文件内容,可以通过使用 .Files 对象访问文件来实现
(下一章节)