控制结构与变量
Control Structures 控制结构
参考:官方文档
控制结构在模板板中被称为 actions(动作)
Helm 模板中有如下几种控制结构:
- if/else # 一个条件判断的代码块
- with # 用于更改当前作用域
- range # 用于循环遍历数组或者 map。
除此之外,还提供了一些声明和使用命名模板的控制结构:
- define # 在模板中声明一个新的命名模板
- template # 导入一个命名模板
- block # 声明了一种特殊的可填写模板区域
define、template、block 这三种控制结构,放在 named template(命名模板) 中进行详解,详见:Named Templates(命名模板)
在下文的各种示例中,我们使用下面这种数据,来让各种控制结构进行处理,values.yaml 文件如下:
favorite:
drink: water
food: sushi
game: 'WOW & PAL'
sushiKinds:
- sashimi
- name: hot
- name: handRoll
rice: more
- name:
IF/ELSE
if/else 判断语句的语法如下:
{{ if PIPELINE }}
# Do something
{{ else if OTHER PIPELINE }}
# Do something else
{{ else }}
# Default case
{{ end }}
当 PIPELINE 值为以下内容,判定为 false:
- 布尔值 false
- 数字零
- 一个空字符串
- nil
- 一个空的集合(map,slice,tuple,dict,array)
下列模板将判断如果 .Values.favorite.drink == “water” 则新增 mug: true 。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}
{{ if eq .Values.favorite.drink "water" }}mug: true{{ end }}
With
{{ with PIPELINE }}
# with声明的作用域
{{ end }}
复制代码
with 用于更改当前作用域(.)。上文提到在{{ .Release.Name }}中,最左边的(.)表示当前作用域下的顶层命名空间,.Values 告诉模板在当前作用域范围的顶层命名空间下查找 Values 对象。使用 with 可以改变模板变量的当前作用域,把(.)赋值给另一个对象:
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 }}
在上面的例子中,在 with 的作用范围内({- with .xxxx} 到 {{- end}}之间)可以直接引用.drink 和.food,这是因为{{- with .Values.favorite}}把 Values.favorite 赋值给了当前作用域(.)。
range
用于循环遍历 array 或 map 。range 与 go 语言中的 for…range 关键字的行为相同,只是语法不同。语法如下:
{{ range [$STRING1, $STRING2 :=] PIPELINE }}
# do something
{{end}}
- PIPELINE 用于产生 map 或者 array 类型的数据;非这两类的数据,range 无法处理。
- $STRING1 与 $STRING2 是可选的。通过 range 处理的 PIPELINE 可以返回两个参数。
range 在处理 array 与 map 这两类数据时,方式是不同的。在 data 字段下,展示 range 处理 map 与 array 这两类数据时的四种不同情况:
- map # 使用 range 循环处理 map。map 范围下的 {{ . }} 为每个 map 中键值对的值
- mapVariable # 两个变量分别为 map 数据的 key 和 value。也就是说 {{ . }} 的值与 $element 的值相同。
- array # 使用 range 循环处理 array。array 范围下的 {{ . }} 为数组中每个元素的值。
- arrayVariables # 两个变量分别为 array 数据的 索引 和 元素。也就是说 {{ . }} 的值与 $value 的值相同。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-range-configmap
data:
map:
{{.Values.favorite}}
{{- range .Values.favorite}}
{{ . }}
{{- end }}
mapVariable:
{{- range $key, $val := .Values.favorite}}
{{ $key }}: {{ $val }}
{{- end }}
array:
{{- /* 如果要添加下面这行,则需要在 array:后面添加 | 符号,否则会报错:helm did not find expected ',' or ']' */}}
{{/*.Values.sushiKinds*/}}
{{- range .Values.sushiKinds}}
{{ . }}
{{- end }}
arrayVariables:
{{- range $index, $element := .Values.sushiKinds}}
索引 {{ $index }} 号元素的值为:{{ $element }}
{{- end }}
渲染结果如下:
[root@master-1 control_structures]# helm template ctrl . -s templates/range.yaml
---
# Source: control_tructures/templates/range.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: ctrl-range-configmap
data:
map:
map[drink:water food:sushi game:WOW & PAL]
water
sushi
WOW & PAL
mapVariable:
drink: water
food: sushi
game: WOW & PAL
array: |-
[sashimi map[name:hot] map[name:handRoll rice:more] map[name:<nil>]]
sashimi
map[name:hot]
map[name:handRoll rice:more]
map[name:<nil>]
arrayVariables:
索引 0 号元素的值为:sashimi
索引 1 号元素的值为:map[name:hot]
索引 2 号元素的值为:map[name:handRoll rice:more]
索引 3 号元素的值为:map[name:<nil>]
注意:如果想要继续获取 map[] 中的每个 key/value 对的值,则需要再次使用 range 来获取 map[] 中的值。就是在 sushiKinds1-2 中使用 sushiKinds1-1 的指令。只不过有一点需要主要,在这个例子中,3 号元素值并不是 map ,也就无法使用 range。所以这种不同类型的数据结构,最好不要混用,否则模板很难处理。
也就是说 Helm 里的 range 控制结构如法处理 map 与 array 的混合数据数据类型,只能同类处理。
map 与 array 的混合数据(比如这种 - sashimi: good 结构的数据),{{- range $key, $val := .Values.favorite}} 这种指令渲染效果不好。渲染结果是这样的: 0: map[sashimi:good],并不能将 map 中的键值对直接拆开
通过 range 来梳理.
范围内的对象
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-test-configmap
datadot: {{ . }}
datadotrange: |-
{{- range $index, $value := .Release}}
{{$index}}: {{ $value }}
{{- end}}
从这里可以看到输出结果:
[root@master-1 test]# helm template test .
---
# Source: test/templates/test.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-test-configmap
# 实际上, . 范围内的数据就是一个具有6个 map 的数组。是 map 与 array 的混合结构数据
datadot: map[Capabilities:0x2a66d80 Chart:0xc00015aa20 Files:map[] Release:map[IsInstall:true IsUpgrade:false Name:test Namespace:default Revision:1 Service:Helm] Template:map[BasePath:test/templates Name:test/templates/test.yaml] Values:map[]]
# 而 .Release 范围内的数据,也具有多个元素。
datadotrange: |-
IsInstall: true
IsUpgrade: false
Name: test
Namespace: default
Revision: 1
Service: Helm
从输出结果来看, . 范围下的对象有 Capabilities、Chart、Files、Release、Template、Values 这几个。正好与 Helm Template 介绍 中描述的 内置对象 匹配上。
toYaml 函数
toYaml 用来遍历 PIPELINE 范围内的每一行,toYAML 的效果相当于 range 的简化版,把 yaml 文件中 PIPELINE 范围内的所有内容原封不动导入到模板中。常用来处理注释类数据。
语法:
{{toYAML PIPELINE}}
示例:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-test-configmap
data:
{{- toYaml .Values | nindent 2}}
这时,会将 annotations 下的一组键值对都传进模板,如果不用 toYaml,是无法实现的,因为传递的值中有冒号。渲染结果如下:
[root@master-1 test]# helm template test .
---
# Source: test/templates/test.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-test-configmap
data:
favorite:
drink: water
food: sushi
game: WOW & PAL
sushiKinds:
- sashimi
- name: hot
- name: handRoll
rice: more
- name: null
range 中的 tuple 函数
有时能够快速在模板中创建一个列表,然后遍历该列表很有用。 Helm 模板具有简化此功能的功能:元组。在计算机科学中,元组是固定大小的列表式集合,但是具有任意数据类型。这大致传达了元组的使用方式。
sizes: |-
{{- range tuple "small" "medium" "large" }}
- {{ . }}
{{- end }}
上面会产生这个:
sizes: |-
- small
- medium
- large
Whitespace(空格)处理
在上述的模板示例中,我们会在一些模板指令里面会出现中划线-
这个符号,例如{{- xxx}}或者{{xxx -}}。这个中划线的作用就是消除多于空格。例如有如下的模板:
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 }}
其渲染结果是:
apiVersion: v1
kind: ConfigMap
metadata:
name: telling-chimp-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: true
可以看到,在 mug: true 前后各多了一个空行,这是因为在模板渲染的过程中,删除了{{
和}}
中的内容,但保留了其余的空白。使用-
符号来消除模板语句占用的空格,为直观展示删除效果,在下列示例中,星号(*)表示被删除的空格:
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 }}
渲染结果:
...
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: true
...
中横线在左边{{- xxx}}
表示消除左边的空格,中横线在右边{{xxx -}}
表示消除右边的空格。要小心不要写成了:
...
food: {{ .Values.favorite.food | upper | quote }}
{{- if eq .Values.favorite.drink "coffee" -}}
mug: true
{{- end -}}
...
这样渲染出来的结果会是food: "PIZZA"mug:true
。 除了使用-
消除模板的空格外,Helm 还提供了 indent 函数增加空格来进行缩进:
...
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
{{ "mug: true" | indent2 }} # 为"mug: true"增加两个空格的缩进。
...
Variables 变量
变量在大部分变成语言都是基本组成部分,但是在 Helm Template 中使用率较低。一般常用来优化 with 与 range 控制结构。
比如下面的示例,引用对象的范围不在在 with 中指定的范围内时,这时候可以通过变量来解决。
{{- with .Values.favorite}}
drink: {{.drink | default "tea" | quote}}
food: {{.food | upper | quote}}
release: {{.Release.Name}}
{{- end}}
这个示例中 release: {{.Release.Name}} 引用将会失败,因为该引用在 with 规定的 .Valuse.favorite 这个范围内,在这个范围内,没有 Release 对象。
这时候,变量就派上用场了。
变量的定义与引用格式:
# 定义一个名为 NAME 的变量。通过 := 符号对变量进行赋值
$NAME := PIPELINE
# 引用变量 NAME
{{ $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 控制结构中的 release 就有值了~
有一个始终是全局变量 $ ,此变量将始终指向根上下文。当您在一个范围内循环并且需要知道图表的发行名称时,这可能非常有用。
$ 符号可以起到转义符的作用,试得在一个范围内的 . 符号可以在全局中引用其内的对象。比如
{{- 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" $ }}
# 无法引用.Chart.Name,但可以执行 $.Chart.Name 来引用.Chart.Name
helm.sh/chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}"
app.kubernetes.io/instance: "{{ $.Release.Name }}"
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 }}
反馈
此页是否对你有帮助?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.