流控制
控制结构(在模板语言中称为 “actions” )提供给你和模板作者控制模板迭代流的能力。 Helm 的模板语言提供了以下控制结构
if/else
, 用来创建条件语句with
, 用来指定范围range
, 提供 “for each” 类型的循环
除了这些之外,还提供了一些声明和使用命名模板的关键字:
define
在模板中声明一个新的命名模板template
导入一个命名模板block
声明一种特殊的可填充的模板块
if / else
1. 概述
第一个控制结构是在按照条件在一个模板中包含一个块文本。即if/else
块;基本的条件结构看起来像这样:
{{ if PIPELINE }}
# Do something
{{ else if OTHER PIPELINE }}
# Do something else
{{ else }}
# Default case
{{ end }}
说明: 我们讨论的是
PIPELINE ()管道)
而不是值。这样做的原因是要清楚地说明控制结构可以执行整个管道,而不仅仅是计算一个值
如果是以下值时,管道会被设置为 false
:
- 整型:
0
- 字符串:
""
- 列表:
[]
- 字典:
{}
- 布尔:
false
- 以及所有的:
nil (或 null)
在所有其他条件下,条件都为true
。
2. 示例
假设values.ymal
文件如下:
# cat values.yaml
favorite:
drink: coffee
food: pizza
配置映射中添加一个简单的条件。如果饮品是coffee
会添加另一个配置:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}
{{ if eq .Values.favorite.drink "coffee" }}mug: true{{ end }}
说明: 当
values.yaml
文件中存在drink: coffee
, 输出中就会包含mug: true
, 输出中就不会包含mug: true
标识。
3. 控制空行
- yaml 文件
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}
{{ if eq .Values.favorite.drink "coffee" }}
mug: true
{{ end }}
- 输出
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: true
注意在YAML中有一个空行,为什么?当模板引擎运行时,它 移除了 {{ 和 }}
里面的内容,但是留下的空白完全保持原样。
YAML认为空白是有意义的,因此管理空白变得很重要。幸运的是,Helm模板有些工具可以处理此类问题。
首先,模板声明的大括号语法可以通过特殊的字符修改,并通知模板引擎取消空白。{{-
(包括添加的横杠和空格) 表示向左删除空白, 而 -}}
表示右边的空格应该被去掉。 一定注意空格就是换行
说明: 要确保
-
和其他命令之间有一个空格。{{- 3 }}
表示 “删除左边空格并打印3” ,而{{-3 }}
表示 “打印-3” 。
with
with 操作用来控制变量范围。回想一下,.
是对 当前作用域 的引用。因此 .Values
就是告诉模板在当前作用域查找 Values 对象。
with
的语法与if语句类似:
{{ with PIPELINE }}
# restricted scope
{{ end }}
作用域可以被改变。with
允许你为特定对象设定当前作用域(.)
。比如,我们已经在使用.Values.favorite
。 修改配置映射中的.的作用域指向.Values.favorite
:
- 定义模板
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ .Release.Name }}
{{- end }}
说明: 我们从之前的模板中移除了if条件, 注意现在我们可以引用
.drink
和.food
了,而不必限定他们。因为with
语句设置了.
指向.Values.favorite
。.
被重置为{{ end }}
之后的上一个作用域。
但是这里有个注意事项,在限定的作用域内,无法使用.
访问父作用域的对象
这样会报错因为Release.Name
不在.
限定的作用域内。但是如果对调最后两行就是正常的, 因为在{{ end }}
之后作用域被重置了
- 修改模板
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
release: {{ .Release.Name }}
或者,我们可以使用$
从父作用域中访问Release.Name
对象。当模板开始执行后$
会被映射到根作用域,且执行过程中不会更改。
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ $.Release.Name }}
{{- end }}
range
很多编程语言支持使用for
循环,foreach
循环,或者类似的方法机制。 在Helm的模板语言中,在一个集合中迭代的方式是使用range
操作符
- 假设
values.yaml
值如下
favorite:
drink: coffee
food: pizza
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
- 模板映射
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
toppings: |-
{{- range .Values.pizzaToppings }}
- {{ . | title | quote }}
{{- end }}
说明:仔细看看 toppings: 列表。range 方法“涵盖”(迭代)pizzaToppings 列表。但现在发生了有意思的事情。 就像 with 设置了
.
的作用域,range 操作符也做了同样的事。每一次循环,.
都会设置为当前的披萨配料。 也就是说,第一次.
设置成了 mushrooms,第二次迭代设置成了 cheese ,以此内推。
- 模板输出
apiVersion: v1
kind: ConfigMap
metadata:
name: edgy-dragonfly-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
toppings: |-
- "Mushrooms"
- "Cheese"
- "Peppers"
- "Onions"
说明:
- 我们可以直接发送
.
的值给管道,因此当我们执行 {{ . | title | quote }} 时,它会发送.
到 title 然后发送到 quotetoppings: |-
行是声明的多行字符串。所以这个配料列表实际上不是 YAML 列表, 是个大字符串。为什么要这样做?因为在配置映射 data 中的数据是由键值对组成,key 和 value 都是简单的字符串。- Kubernetes ConfigMap 文档
- 快速创建列表
有时能在模板中快速创建列表然后迭代很有用,Helm模板的 tuple 可以很容易实现该功能。在计算机科学中, 元组表示一个有固定大小的类似列表的集合,但可以是任意数据类型。
- 定义模板
sizes: |-
{{- range tuple "small" "medium" "large" }}
- {{ . }}
{{- end }}
2. 模板输出
sizes: |-
- small
- medium
- large
补充:除了列表和元组,range 可被用于迭代有键值对的集合(像 map 或 dict )。