03 Helm模板之函数和管道
今天我们来学习Helm3模板中的模板函数与管道。虽然我们通过Values把信息注入到了模板当中,但是这些信息都是直接传入模板引擎中进行渲染的,有的时候我们想要转换⼀下这些数据才进行渲染,这就需要使用到 Go 模板语⾔中的⼀些其他用法。
比如我们需要从 .Values中读取的值变成字符串的时候就可以通过调用"quote"模板函数来实现。
模板函数遵循调用的语法为:functionName arg1 arg2。
在下面的模板文件中, quote .Values.course.k8s 调用 quote 函数并将后面的值作为⼀个参数传递给它。
➜ ~ vim mychart/templates/configmap.yaml
➜ ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
k8s: {{ quote .Values.course.k8s }}
python: {{ .Values.course.python }}
最终被渲染下面的内容(templates/configmap.yaml):
➜ ~ helm install mychart mychart/ --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 14:37:05 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "Hello World"
k8s: "devops"
python: django
我们可以看到 .Values.course.k8s 被渲染成了字符串 devops 。
前面我们也提到过 Helm是⼀种 Go模板语⾔,拥有超过60多种可用的内置函数,⼀部分是由Go 模板语⾔本身定义的,其他大部分都是 Sprig 模板库提供的⼀部分。所以在我们遇到⼀些需求的时候,⾸先要想到的是前往模板函数列表中查看是否提供了对应的模板函数,这些模板函数都可以很好的解决我们的需求。
比如我们这里使用的 quote 函数就是提供的⼀种字符串函数,用途就是用双引号将字符串括起来,如果需要双引号 ” ,则需要添加 \ 来进行转义,而 squote 函数的用途则是用双引号将字符串括起来,而不会对内容进行转义。
模板语⾔除了提供了丰富的内置函数之外,其另⼀个强⼤的功能就是管道的概念。和Linux 中⼀样,管道我们通常称为 Pipeline ,是⼀个链在⼀起的⼀系列模板命令的⼯具,以紧凑地表达⼀系列转换。简单来说,管道是可以按顺序完成⼀系列事情的⼀种⽅法。比如我们用管道{{ .Values.course.k8s | quote }}来重写上面的 ConfigMap模板(templates/configmap.yaml):
➜ ~ vim mychart/templates/configmap.yaml
➜ ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
k8s: {{ .Values.course.k8s | quote }}
python: {{ .Values.course.python }}
➜ ~
➜ ~ helm install mychart mychart/ --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 14:47:13 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "Hello World"
k8s: "devops"
python: django
这里我们不直接调用 quote 函数,而是调换了⼀个顺序,使用⼀个管道符 | 将前⾯的参数发送给后⾯的模板函数: {{ .Values.course.k8s | quote }} ,使用管道我们可以将⼏个功能顺序的连接在⼀起,比如我们希望上⾯的 ConfigMap 模板中的 k8s 的 value 值被渲染后是大写的字符串,则我们就可以使用管道来修改(templates/configmap.yaml),这里我们在管道中增加了⼀个 upper 函数,表示将字符串每⼀个字⺟都变成⼤写。
➜ ~ vim mychart/templates/configmap.yaml
➜ ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
k8s: {{ .Values.course.k8s | quote | upper }}
python: {{ .Values.course.python }}
➜ ~
➜ ~ helm install mychart mychart/ --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 14:50:03 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "Hello World"
k8s: "DEVOPS"
python: django
我们可以看到之前我们的 devops 已经被渲染成了 “DEVOPS” 了,要注意的是使用管道操作的时候,前⾯的操作结果会作为参数传递给后⾯的模板函数,比如我们希望将上⾯模板中的 python 的值渲染为重复出现3次的字符串,则我们就可以使用到repeat函数,不过该函数需要传入⼀个参数 repeat COUNT STRING 表示重复的次数:
➜ ~ vim mychart/templates/configmap.yaml
➜ ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
k8s: {{ .Values.course.k8s | quote | upper }}
python: {{ .Values.course.python | repeat 3 | quote }}
➜ ~
➜ ~ helm install mychart mychart/ --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 14:55:01 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "Hello World"
k8s: "DEVOPS"
python: "djangodjangodjango"
当管道后面的函数有多个参数时,管道会将前一个计算的结果作为最后一个参数发送给函数(管道传过来的值作为后面模板函数的最后一个参数)。
另外⼀个我们会经常使用的函数是 default 函数 : default DEFAULT_VALUE GIVEN_VALUE 。如果GIVEN_VALUE未定义(nil),则DEFAULT_VALUE生效。
该函数允许我们在模板内部指定默认值,以防止该值被忽略掉了。比如我们来修改上⾯的 ConfigMap 的模板(templates/configmap.yaml):
➜ ~ vim mychart/templates/configmap.yaml
➜ ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: {{ .Values.hello | quote }}
k8s: {{ .Values.course.k8s | quote | upper }}
python: {{ .Values.course.python | repeat 3 | quote }}
➜ ~
➜ ~ cat mychart/values.yaml
course:
k8s: devops
python: django
➜ ~
➜ ~
➜ ~ helm install mychart mychart/ --dry-run
Error: unable to build kubernetes objects from release manifest: error validating "": error validating data: unknown object type "nil" in ConfigMap.data.myvalue
由于 values.yaml 文件中只定义了 course 结构的信息,并没有定义 hello 的值,原理上如果没有设置默认值的话是得不到 {{ .Values.hello }} 的值的。所以上面报错了。为了避免我们忘记指定默认值,可以使用default函数指定一个缺省的默认值。
➜ ~ vim mychart/templates/configmap.yaml
➜ ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: {{ .Value.hello |default "Hello World" | quote }}
k8s: {{ .Values.course.k8s | quote | upper }}
python: {{ .Values.course.python | repeat 3 | quote }}
➜ ~
➜ ~ helm install mychart mychart/ --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 15:03:16 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "Hello World"
k8s: "DEVOPS"
python: "djangodjangodjango"
我们可以看到 myvalue 值被渲染成了Hello World,而我们在values里面并没有去定义hello这个values、这也就证明了Helm自动为我们添加了默认值。
如果我们通过–set指定hello的值,则会使用指定的值进行渲染:
➜ ~ helm install mychart mychart/ --dry-run --set hello='ljzsdut'
NAME: mychart
LAST DEPLOYED: Tue Feb 23 15:09:20 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "ljzsdut"
k8s: "DEVOPS"
python: "djangodjangodjango"
printf 函数可以自定义格式化输出。
$ kubectl get pods --all-namespaces -o go-template --template='{{range .items}}{{printf "%s\n" .metadata.uid}}{{end}}'
等同于
$ kubectl get pods --all-namespaces -o go-template --template='{{range .items}}{{.metadata.uid}}{{"\n"}}{{end}}'
$ kubectl get pods --all-namespaces -o go-template --template='{{range .items}}{{printf "|%-20s|%-50s|%-30s|\n" .metadata.namespace .metadata.name .metadata.uid}}{{end}}'
|default |details-v1-64b86cd49-85vks |2e7a2a66-533e-11e8-b722-005056a1bc83|
|default |productpage-v1-84f77f8747-7tkwb |2eb4e840-533e-11e8-b722-005056a1bc83|
|default |ratings-v1-5f46655b57-qlrxp |2e89f981-533e-11e8-b722-005056a1bc83|
...
404.html: {{ include "error_page_404" . | b64enc | quote }} #可以在secret中使用