跳转至

函数和管道

现在我们已经了解了如何将信息加入到模板中,但是这些信息都是直接原样的放置过去的,有时候,我们希望以一种对我们更有用的方式来转换提供的数据。

下面让我们从一个最佳实践开始:将 .Values 对象中的字符串注入模板时,我们应该引用这些字符串,我们可以通过在 template 指令中调用 quote 函数来实现,比如:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ quote .Values.favorite.drink }}
  food: {{ quote .Values.favorite.food }}

模板函数遵循的语法规则是 functionName arg1 arg2...,在上面的代码片段中,quote .Values.favorite.drink 会调用 quote 函数并传递一个单个参数。

Helm 有60多种可用的函数,其中一些是由 Go 模板语言本身定义的,其他大多数都是 Sprig 模板库提供的,接下来我们会通过部分示例来逐步介绍其中的一些功能函数。

Helm 模板

当我们谈论 Helm 模板语言 的时候,就好像是特定于 Helm 一样,但实际上它是 Go 模板语言加上一些额外的函数以及各种封装程序的组合,以将某些对象暴露给模板。当我们需要学习模板的时候,Go 模板上有许多资源会对我们有所帮助的。

管道

模板语言有一个强大的功能就是管道(Pipeline)概念,管道利用 UNIX 的概念,将一系列模板命令链接在一起,一起对外提供服务,换句话说,管道是按顺序完成多项工作的有效方式,我们来使用管道重写上面的示例模板:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | quote }}
  food: {{ .Values.favorite.food | quote }}

在这里我们没有调用 quote ARGUMENT 函数,而是颠倒了下顺序,我们使用管道符(|)将参数发送给函数:.Values.favorite.drink | quote,使用管道,我们可以将多个功能链接在一起:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | quote }}
  food: {{ .Values.favorite.food | upper | quote }}

管道顺序

反转顺序是模板中常见的做法,我们会看到 .val | quotequote .val 用法更多,虽然两种方法都是可以的。

最后,模板渲染后,会产生如下所示的结果:

$ helm install --generate-name --dry-run --debug ./mychart
install.go:148: [debug] Original chart version: ""
install.go:165: [debug] CHART PATH: /Users/ych/devs/workspace/yidianzhishi/course/k8strain/content/helm/manifests/mychart

NAME: mychart-1575966483
LAST DEPLOYED: Tue Dec 10 16:28:04 2019
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
favorite:
  drink: coffee
  food: pizza
favoriteDrink: coffee

HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-1575966483-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"

我们可以看到 values 中的 pizza 值已经被转换成了 "PIZZA"。当这样传递参数的时候,第一个求值结果(.Values.favorite.drink)会作为一个参数发送给函数,我们可以修改上面的 drink 示例,用一个带有两个参数的函数进行说明:repeat COUNT STRING

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | repeat 5 | quote }}
  food: {{ .Values.favorite.food | upper | quote }}

repeat 函数将重复字符串给定的次数,渲染后我们可以得到如下的输出结果:

# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-1575966939-configmap
data:
  myvalue: "Hello World"
  drink: "coffeecoffeecoffeecoffeecoffee"
  food: "PIZZA"

default 函数

在模板中经常会使用到的一个函数是 default 函数:default DEFAULT_VALUE GIVEN_VALUE,该函数允许你在模板内部指定默认值,我们来修改上面示例中的模板:

food: {{ .Values.favorite.food | default "rice" | upper | quote }}

正常运行,我们还是可以得到 values.yaml 文件中定义的 pizza:

# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-1575966939-configmap
data:
  myvalue: "Hello World"
  drink: "coffeecoffeecoffeecoffeecoffee"
  food: "PIZZA"

现在我们从 values.yaml 文件中移除 food 的定义:

favorite:
  drink: coffee
  # food: pizza

现在我们重新运行 helm install --generate-name --dry-run --debug ./mychart 将渲染成如下的 YAML 文件:

# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-1575967394-configmap
data:
  myvalue: "Hello World"
  drink: "coffeecoffeecoffeecoffeecoffee"
  food: "RICE"

在一个真实的 chart 模板中,所有的静态默认值都应位于 values.yaml 文件中,并且不应该重复使用 default 函数,但是,默认命令非常适合计算不能在 values.yaml 文件中声明的 values 值,例如:

food: {{ .Values.favorite.food | default (printf "%s-rice" (include "fullname" .)) }}

不过在有些地方,if 条件语句可能比 default 函数更合适,我们会在后面了解到。

模板函数和管道是将数据转换后然后将其插入到 YAML 文件中的一种强大方法,但是有的时候有必要添加一些模板逻辑,这些逻辑比仅仅插入字符串要复杂得多,下面我们将来了解模板语言中提供的控制流程。

运算符函数

另外需要注意的是在模板中,运算符(eq、ne、lt、gt、and、or 等等)均实现为函数,在管道中,运算符可以用括号()进行分割。

接下来我们可以去了解控制流程条件语句、循环和作用域修饰符的使用。