前面我们学习了 Helm 模板中的⼀些常用方法,但都是操作的⼀个模板文件,在实际的应用中,很多都是相对比较复杂的,往往会超过⼀个模板,如果有多个应用模板,我们应该如何进行处理呢?这就需要用到新的概念:命名模板。
命名模板我们也可以称为子模板,是限定在⼀个文件内部的模板,然后给⼀个名称。在使用命名模板的时候有⼀个需要特别注意的是:模板名称是全局的,如果我们声明了两个相同名称的模板,最后加载的⼀个模板会覆盖掉另外的模板,由于子 chart 中的模板也是和顶层的模板⼀起编译的,所以在命名的时候⼀定要注意,不能重名了。为了避免重名,有个通用的约定就是为每个定义的模板添加上 chart 名称: {{define”mychart.labels”}} , define 关键字就是用来声明命名模板的,加上 chart 名称就可以避免不同chart 间的模板出现冲突的情况。
1、声明和使用命名模板
使用 define 关键字就可以允许我们在模板文件内部创建⼀个命名模板,它的语法格式如下:
{{ define "ChartName.TplName" }}
# 模板内容区域
{{ end }}
比如,现在我们可以定义⼀个模板来封装⼀个 label 标签:
{{- define "mychart.labels" }}
labels:
from: helm
date: {{ now | htmlDate }}
{{- end }}
然后我们可以将该模板嵌⼊到现有的 ConfigMap 中,然后使⽤ template 关键字在需要的地⽅包含进来即可:
上面这个模板⽂件被渲染过后的结果如下所示:
我们可以看到 define 区域定义的命名模板被嵌入到了 template 所在的区域,但是如果我们将命名模板全都写入到⼀个模板文件中的话无疑会增大模板的复杂性。还记得我们在创建 chart 包的时候,templates 目录下⾯默认会生成⼀个 _helpers.tpl 文件吗?我们前面也提到过 templates 目录下⾯除了 NOTES.txt 文件和以下划线 _ 开头命令的文件之外,都会被当做 kubernetes 的资源清单文件,而这个下划线开头的文件不会被当做资源清单外,还可以被其他chart 模板中调用,这个就是 Helm 中的 partials 文件,所以其实我们完全就可以将命名模板定义在这些 partials 文件中,默认就是 _helpers.tpl 文件了。
现在我们将上⾯定义的命名模板移动到 templates/_helpers.tpl 文件中去:
{{/* 生成基本的 labels 标签 */}}
{{- define "mychart.labels" }}
labels:
from: helm
date: {{ now | htmlDate }}
{{- end }}
⼀般情况下⾯,我们都会在命名模板头部加⼀个简单的文档块,⽤ /**/ 包裹起来,用来描述命名模板的用途。现在我们将命名模板从模板文件 templates/configmap.yaml 中移除,当然还是需要保留 template 来嵌入命名模板内容,名称还是之前的 mychart.lables,这是因为模板名称是全局的,所以我们可以直接获取到。我们再用 DEBUG 模式来调试下是否符合预期:
2、模板范围
上面我们定义的命名模板中,没有使用任何对象,只是使用了⼀个简单的函数,如果我们在里面加入 chart 对象相关信息呢 templates/_helpers.tpl :
{{/* 生成基本的 labels 标签 */}}
{{- define "mychart.labels" }}
labels:
from: helm
date: {{ now | htmlDate }}
chart: {{ .Chart.Name }}
version: {{ .Chart.Version }}
{{- end }}
如果这样的直接进行渲染测试的话,不会得到我们预期的结果:
chart 的名称和版本都没有正确被渲染,这是因为他们不在我们定义的模板范围内,当命名模板被渲染时,它会接收由 template 调用时传⼊的作用域,有我们我们这里并没有传⼊对应的作用域,因此模板中我们⽆法调用到 .Chart 对象,要解决也非常简单,我们只需要在 template 后面加上作用域范围即可:
我们在 template 末尾传递了 . ,表示当前的最顶层的作用范围,如果我们想要在命名模板中使用 .Values 范围内的数据,当然也是可以的,现在我们再来渲染下模板:
我们可以看到 chart 的名称和版本号都已经被正常渲染出来了。
3、include函数
假如现在我们将上面定义的 labels 单独提取出来放置到 _helpers.tpl 文件中;然后我们将该命名模板插入到 configmap 模板文件的 labels 部分和 data 部分:
然后同样的查看下渲染的结果:
我们可以看到渲染结果是有问题的,不是⼀个正常的 YAML 文件格式。app_version在两个位置上的缩进都是错误的。为什么?因为替换的模板的文本右对齐。template 只是表示⼀个嵌入动作而已,不是⼀个函数,所以原本命名模板中是怎样的格式就是怎样的格式被嵌入进来了,那如果我们在命名模板中给内容区域都空了两个空格,会渲染出什么呢?有兴趣的小伙伴可以自己尝试debug一下看看哦。
操作之后你可以看到 data 区域里面的内容是渲染正确的,但是上⾯ labels 区域是不正常的,因为命名模板里⾯的内容是属于 labels 标签的,是不符合预期的,但是我们又不可能再去把命名模板里面的内容再增加两个空格,因为这样的话 data 里面的格式又不符合预期了。为了解决这个问题,Helm 提供了另外⼀个⽅案来代替 template ,那就是使⽤ include 函数,在需要控制空格的地⽅使⽤ indent 管道函数来⾃⼰控制,比如上⾯的例⼦我们替换成 include 函数:
在 labels 区域我们需要4个空格,所以在管道函数 indent 中,传入参数4就可以,而在 data 区域我们只需要2个空格,所以我们传入参数2即可以,现在我们来渲染下我们这个模板看看是否符合预期呢:
可以看到是符合我们的预期,所以在 Helm 模板中我们使⽤ include 函数要比 template 更好,可以更好地处理 YAML ⽂件输出格式。