07-模板函数

Helm使用Go模板 Go Template 来生成模板和资源文件。虽然Go提供了几个内置函数,但是Helm还添加了其他的函数。

Sprig库 中添加了几乎所有的函数。出于安全考虑,删除了envexpandenv这两个函数,这两个函数让chart作者能访问Tiller的环境变量,同时新增两个特殊的模板函数:includerequired

模板函数

模板函数遵循语法functionName arg1 arg2 ...,调用函数并将参数传递给它。常用的函数包括:

  • define:在模板中声明一个新的命名模板
  • template:允许引入另一个命名模板
  • include:允许引入另一个命名模板,然后将结果传递给其他函数
  • required:声明必须的值条目
  • tpl:将字符串计算为模板内的模板
  • default:设置默认值
  • block:声明一个特殊的可填写模板区域(提供一个默认的实现,后续将被覆盖)【不推荐使用】

命名模板(也称为子模板)是限定在一个文件内部的模板,并给它起一个名称。

命名模板的模板名称是全局的。如果声明两个具有相同名称的模板,则最后加载的那个模板是起作用的模板。由于子 chart 中的模板与顶级模板一起编译,因此注意小心地使用特定 chart 的名称来命名模板。

通用的命名约定是为每个定义的模板添加 chart 名称:{{define "mychart.labels"}}。通过使用特定 chart 名称作为前缀,可以避免由于同名模板的两个不同 chart 而可能出现的任何冲突。

define

该 define 操作允许我们在模板文件内创建一个命名模板。它的语法如下所示:

{{ define "MY.NAME" }}
  # body of template here
{{ end }}

# 例如,可以定义一个模板来封装一个 Kubernetes 标签块
{{- define "mychart.labels" }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
{{- end }}

Helm chart 通常将define创建的这些命名模板放入 partials 文件中,通常是helpers.tpl。按照惯例,define 函数应该有一个简单的文档块({{/* ... */}})来描述它所做的事情。

设置命名模板范围

上面定义的命名模板中,没有使用任何对象,只是使用函数。现在将命名模板修改为如下形式,以包含 chart 名称和 chart 版本:

{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
    chart: {{ .Chart.Name }}
    version: {{ .Chart.Version }}
{{- end }}

# 这将不会得到我们所期望的结果

# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: moldy-jaguar-configmap
  labels:
    generator: helm
    date: 2016-11-02
    chart:                   # 未获取到Chart.Name
    version:                 # 未获取到Chart.Version
                             # 上述两个值,不在我们定义的模板的范围内

当一个命名模板被渲染时,它将接收由该template调用传入的作用域

{{- template "mychart.labels" }}
# 没有范围被传入,因此在模板中无法访问任何内容

# 将范围传递给模板
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  {{- template "mychart.labels" . }}     # 在template末尾传递了`.`
                                         # `.`表示顶级范围,`.Values`范围,`.Values.favorite`范围

添加范围后,就可以得到正确的值。

template

{{template "name"}}
// 执行名为name的模板,提供给模板的参数为nil,如模板不存在输出为""

{{template "name" pipeline}}
// 执行名为name的模板,提供给模板的参数为pipeline的值
# 调用上述define中定义的命名模板
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 }}

即使这个定义在_helpers.tpl,它仍然可以在 configmap.yaml 以下位置访问,因为模板名称是全局的 。

include

虽然Go提供了template函数,能够将一个模板包含在另一个模板中,但是Go的template函数中不能使用管道来传递值到其他内置的函数中。

为了能够引入模板,然后对该模板的输出执行操作,Helm提供了include函数允许引入另一个模板,然后将结果传递给其他函数模板。

// 调用模板 mysql.labels,然后将结果缩进四个空格(在函数中使用管道来进行值的传递),其中 `.` 表示渲染的根对象
{{ include "mysql.labels" . | indent 4 }}

// 调用模板 toYaml,渲染$value的内容,然后将渲染的输出传递给 indent 函数
{{- include "toYaml" $value | nindent 2}}

因为YAML的缩进级别和空白很重要,所以使用indent函数是包含代码片段的好方法,并在相关的上下文中处理缩进。

required

required 函数允许根据模板渲染的要求声明特定的值条目。如果values.yaml中该条目值为空,则模板渲染将失败并显示用户提交的错误消息。

// 声明 .Values.who 条目是必需的,并且在缺少该条目(即未定义Values.who)时将显示错误消息
value: {{required "A valid .Values.who entry required!" .Values.who}}

tpl

tpl 函数允许开发人员将字符串计算为模板内的模板。 这对于将模板字符串作为值传递给 chart 或渲染外部配置文件很有用。

语法: {{tpl TEMPLATE_STRING VALUES}}

//  模板字符串  values.yaml文件
template: "{{.Values.name}}"
name: "Tom"

//  template
{{tpl .Values.template .}}

//  output
Tom


//  外部配置文件 conf/app.conf
firstName={{.Values.firstName}}
lastName={{.Values.lastName}}

//  values.yaml文件
firstName: Peter
lastName: Parkerk

//  template
{{tpl (.Files.Get "conf/app.conf") . }}

//  output
firstName=Peter
lastName=Parker

default

default函数,如:default DEFAULT_VALUE GIVEN_VALUE。该功能允许在模板内部指定默认值,以防该值被省略。

{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}

在实际的 chart 中:

  1. 所有静态默认值应该存在于 values.yaml 中,不应该使用 default 命令重复(否则它们将是重复多余的)。
  2. 但是,default 命令对于计算的值是合适的,因为计算值不能在 values.yaml 中声明。

运算符函数

对于模板,运算符(eq,ne,lt,gt,and,or 等等)都是已实现的功能。在管道中,运算符可以用圆括号(())分组。

将运算符放到声明的前面,后面跟着它的参数,就像使用函数一样。要多个运算符一起使用,将每个函数通过圆括号分隔

上次修改: 14 April 2020