2.10.6 自定义模板
本节我们将学习两种创建自定义模板的方式,然后在其他文件里面引用这个自定义的模板,并分析两种方法的异同。
在Helm中有3个关键字用来声明和管理模板,分别是def ine、template和block。本节我们会分别介绍这3个功能,同时还会学习include关键字,这个include功能和template很类似。
在学习自定义模板前有一个重要的前提,自定义模板是全局的,如果你在两个文件中定义了相同名称的模板,那么前一个模板就会被后一个模板覆盖,由于子Chart会和父Chart一起被编译,因此在定义模板时需要注意尽量避免和子Chart的模板名称相冲突。
一种比较流行的定义方式是使用Chart的名字作为模板名前缀,{def ine"myChart.labels"}},通过使用这种方式,我们就能最大限度地避免不同Chart模板间发生冲突。
1.以“_”开头的特殊文件
到目前为止,我们已经创建了一个模板,这个模板内含有一个单独的文件。Helm允许创建内嵌的自定义模板,同时能够使用名字来调用指定的模板功能。
在我们开始创建模板前,有一些需要提前说明的约定:
·大部分在templates/文件夹下的文件都被认为是Kubernetes资源文件;
·NOTES.txt是一个例外;
·但是以“_”开头的文件一般默认里面没有Kubernetes资源文件。这些文件不会被Helm渲染,但是这些文件内声明的函数可以在Chart的其他地方被调用。
这些文件一般被用来存放帮助函数。当我们创建第一个Chart myChart时,应该留意到一个名为_helpers.tpl的文件,这就是默认的存放帮助文件的地方。
2.使用define和template创建模板
def ine关键字允许在文件中创建一个自定义模板,基本格式如下所示。
{{ define "MY.NAME" }} # body of template here {{ end }}
举个例子,我们可以这样定义一个标签函数来简化生成标签的逻辑。
{{- define "myChart.labels" }} labels: generator: helm date: {{ now | htmlDate }} {{- end }}
现在我们就可以在ConfigMap中使用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 }}
当Helm模板引擎读到模板myChart.labels时,就会寻找这个模板的定义,然后运行定义去重新渲染当前的模板,最终的运行结果如下所示。
apiVersion: v1 kind: ConfigMap metadata: name: running-panda-configmap labels: generator: helm date: 2019-09-02 data: myvalue: "Hello World" drink: "coffee" food: "pizza"
一般来说,Helm的编写规范是把这样的函数移到_helpers.tpl文件中,同时在该文件中,应该有一些注释来表明该段模板的功能,一般书写格式如下所示。
{{/* Generate basic labels */}} {{- define "myChart.labels" }} labels: generator: helm date: {{ now | htmlDate }} {{- end }}
{{/*...*/}}就是注释的基本格式。虽然这个定义是在_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 }}
3.给自定义模板限定范围
在上面的模板定义中,我们没有使用任何内嵌对象。下面我们修改一下定义,增加Chart名称。
{{/* Generate basic labels */}} {{- define "myChart.labels" }} labels: generator: helm date: {{ now | htmlDate }} Chart: {{ .Chart.Name }} version: {{ .Chart.Version }} {{- end }}
如果我们运行这个模板,会得到如下的结果:
apiVersion: v1 kind: ConfigMap metadata: name: moldy-jaguar-configmap labels: generator: helm date: 2019-09-02 Chart: version:
产生这样结果的原因是什么呢?主要是因为这个对象不在我们模板的定义范围内。当一个被def ine定义的模板渲染时,它的调用范围是被外部template传递进来的。在我们的例子中,它是通过{{-template"myChart.labels"}}调用的,没有任何的调用范围被传递进来,因此在这个模板定义中我们是拿不到“.”这个对象的任何信息的。不过我们可以通过template将调用范围传递过去。
apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap {{- template "myChart.labels" . }}
请注意,我们是在template后面传递的“.”。其实我们也可以传递任何对象,比如.Values或者.Values.favorite。现在我们再次运行helm install--dry-run--debug./myChart,会得到如下信息。
apiVersion: v1 kind: ConfigMap metadata: name: plinking-anaco-configmap labels: generator: helm date: 2019-09-02 Chart: myChart version: 0.1.0
4.include函数
首先定义一个简单的模板。
{{- define "myChart.app" -}} app_name: {{ .Chart.Name }} app_version: "{{ .Chart.Version }}+{{ .Release.Time.Seconds }}" {{- 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" . }}
这个模板的输出结果如下。
apiVersion: v1 kind: ConfigMap metadata: name: measly-whippet-configmap labels: app_name: myChart app_version: "0.1.0+1478129847" data: myvalue: "Hello World" drink: "coffee" food: "pizza" app_name: myChart app_version: "0.1.0+1478129847"
注意,app_version这里的缩进是错误的,因为template模板是右对齐的,而且template是一个自定义模板引用,而不是一个函数,没有办法给template传递参数,所以所有的数据都是简单插入的。
在这种情况下,Helm提供了一种解决办法,既能将内容插入指定的模板中,又能以管道的方式继续调用其他函数。下面我们修改一下上述模板,使用nindent来将指定的内容向右缩进指定的空格。
apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-configmap labels: {{- include "myChart.app" . | nindent 4 }} data: myvalue: "Hello World" {{- range $key, $val := .Values.favorite }} {{ $key }}: {{ $val | quote }} {{- end }} {{- include "myChart.app" . | nindent 2 }}
下面一起看看输出的结果。
apiVersion: v1 kind: ConfigMap metadata: name: edgy-mole-configmap labels: app_name: myChart app_version: "0.1.0+1478129987" data: myvalue: "Hello World" drink: "coffee" food: "pizza" app_name: myChart app_version: "0.1.0+1478129987"
在实际使用中,更推荐使用include替代template,因为template能实现的功能,include都能提供,而且include的功能更强大,能够使用管道方式在后面继续使用函数处理。