现在我们可以从函数和管道转向流控制,条件,循环和范围修饰符。
5.8 流程控制5.8.1 流程控制控制结构(模板说法中称为 “动作”)为模板作者提供了控制模板生成流程的能力。Helm 的模板语言提供了以下控制结构:
if/else 用于创建条件块with 指定范围range,它提供了一个 “for each” 风格的循环除此之外,它还提供了一些声明和使用命名模板段的操作:
define 在模板中声明一个新的命名模板template 导入一个命名模板block 声明了一种特殊的可填写模板区域在本节中,我们将谈论 if,with 和 range。其他内容在本指南后面的 “命名模板” 一节中介绍。
5.8.2 if/else我们要看的第一个控制结构是用于在模板中有条件地包含文本块。这就是 if/else 块。
条件的基本结构如下所示:
{{if PIPELINE}} # Do something{{else if OTHER PIPELINE}} # Do something else{{else}} # Default case{{end}}
注意,我们现在讨论的是管道而不是值。其原因是要明确控制结构可以执行整个管道,而不仅仅是评估一个值。
如果值为如下情况,则管道评估为 false。
一个布尔型的假一个数字零一个空的字符串一个 nil(空或 null)一个空的集合(map,slice,tuple,dict,array)在其他情况下, 条件值为 true 此管道被执行。
我们为 ConfigMap 添加一个简单的条件。如果饮料被设置为咖啡,我们将添加另一个设置:
apiVersion: v1kind: ConfigMapmetadata: name: {{.Release.Name}}-configmapdata: myvalue: \"Hello World\" drink: {{.Values.favorite.drink | default \"tea\" | quote}} food: {{.Values.favorite.food | upper | quote}} {{if and .Values.favorite.drink (eq .Values.favorite.drink \"coffee\") }}mug: true{{ end }}
注意 .Values.favorite.drink 必须已定义,否则在将它与 “coffee” 进行比较时会抛出错误。由于我们在上一个例子中注释掉了 drink:coffee,因此输出不应该包含 mug:true 标志。但是如果我们将该行添加回 values.yaml 文件中,输出应该如下所示:
# Source: mychart/templates/configmap.yamlapiVersion: v1kind: ConfigMapmetadata: name: eyewitness-elk-configmapdata: myvalue: \"Hello World\" drink: \"coffee\" food: \"PIZZA\" mug: true5.8.3 控制空格
在查看条件时,我们应该快速查看模板中的空格控制方式。让我们看一下前面的例子,并将其格式化为更容易阅读的格式:
apiVersion: v1kind: ConfigMapmetadata: name: {{.Release.Name}}-configmapdata: myvalue: \"Hello World\" drink: {{.Values.favorite.drink | default \"tea\" | quote}} food: {{.Values.favorite.food | upper | quote}} {{if eq .Values.favorite.drink \"coffee\"}} mug: true {{end}}
最初,这看起来不错。但是如果我们通过模板引擎运行它,我们会得到一个错误的结果:
$ helm install --dry-run --debug ./mychartSERVER: \"localhost:44134\"CHART PATH: /Users/mattbutcher/Code/Go/src/k8s.io/helm/_scratch/mychartError: YAML parse error on mychart/templates/configmap.yaml: error converting YAML to JSON: yaml: line 9: did not find expected key
发生了什么?由于上面的空格,我们生成了不正确的 YAML。
# Source: mychart/templates/configmap.yamlapiVersion: v1kind: ConfigMapmetadata: name: eyewitness-elk-configmapdata: myvalue: \"Hello World\" drink: \"coffee\" food: \"PIZZA\" mug: true
mug 不正确地缩进。让我们简单地缩进那行,然后重新运行:
apiVersion: v1kind: ConfigMapmetadata: name: {{.Release.Name}}-configmapdata: myvalue: \"Hello World\" drink: {{.Values.favorite.drink | default \"tea\" | quote}} food: {{.Values.favorite.food | upper | quote}} {{if eq .Values.favorite.drink \"coffee\"}} mug: true {{end}}
当我们发送该信息时,我们会得到有效的 YAML,但仍然看起来有点意思:
# Source: mychart/templates/configmap.yamlapiVersion: v1kind: ConfigMapmetadata: name: telling-chimp-configmapdata: myvalue: \"Hello World\" drink: \"coffee\" food: \"PIZZA\" mug: true
请注意,我们在 YAML 中收到了一些空行。为什么?当模板引擎运行时,它将删除 {{ 和 }} 中的空白内容,但是按原样保留剩余的空白。
YAML 中的缩进空格是严格的,因此管理空格变得非常重要。幸运的是,Helm 模板有几个工具可以帮助我们。
首先,可以使用特殊字符修改模板声明的大括号语法,以告诉模板引擎填充空白。{{-(添加了破折号和空格)表示应该将格左移,而 -}} 意味着应该删除右空格。注意!换行符也是空格!
确保 - 和其他指令之间有空格。-3 意思是 “删除左空格并打印 3”,而 -3 意思是 “打印 -3”。
使用这个语法,我们可以修改我们的模板来摆脱这些新行:
apiVersion: v1kind: ConfigMapmetadata: name: {{.Release.Name}}-configmapdata: myvalue: \"Hello World\" drink: {{.Values.favorite.drink | default \"tea\" | quote}} food: {{.Values.favorite.food | upper | quote}} {{- if eq .Values.favorite.drink \"coffee\"}} mug: true {{- end}}
为了清楚说明这一点,让我们调整上面的内容,将空格替换为 *, 按照此规则将每个空格将被删除。一个在该行的末尾的 * 指示换行符将被移除
apiVersion: v1kind: ConfigMapmetadata: name: {{.Release.Name}}-configmapdata: myvalue: \"Hello World\" drink: {{.Values.favorite.drink | default \"tea\" | quote}} food: {{.Values.favorite.food | upper | quote}}***{{- if eq .Values.favorite.drink \"coffee\"}} mug: true***{{- end}}
牢记这一点,我们可以通过 Helm 运行我们的模板并查看结果:
# Source: mychart/templates/configmap.yamlapiVersion: v1kind: ConfigMapmetadata: name: clunky-cat-configmapdata: myvalue: \"Hello World\" drink: \"coffee\" food: \"PIZZA\" mug: true
小心使用 chomping 修饰符。这样很容易引起意外:
food: {{.Values.favorite.food | upper | quote}} {{- if eq .Values.favorite.drink \"coffee\" -}} mug: true {{- end -}}
这将会产生 food: \"PIZZA\"mug:true,因为删除了双方的换行符。
有关模板中空格控制的详细信息,请参阅官方 Go 模板文档 Official Go template documentation
最后,有时候告诉模板系统如何缩进更容易,而不是试图掌握模板指令的间距。因此,有时可能会发现使用 indent 函数({{indent 2 \"mug:true\"}})会很有用。
5.8.4 使用 with 修改范围下一个要看的控制结构是 with。它控制着变量作用域。回想一下,. 是对当前范围的引用。因此,.Values 告诉模板在当前范围中查找 Values 对象。
其语法 with 类似于一个简单的 if 语句:
{{with PIPELINE}} # restricted scope{{end}}
范围可以改变。with 可以允许将当前范围(.)设置为特定的对象。例如,我们一直在使用的 .Values.favorites。让我们重写我们的 ConfigMap 来改变 . 范围来指向 .Values.favorites:
apiVersion: v1kind: ConfigMapmetadata: name: {{.Release.Name}}-configmapdata: myvalue: \"Hello World\" {{- with .Values.favorite}} drink: {{.drink | default \"tea\" | quote}} food: {{.food | upper | quote}} {{- end}}
注意,现在我们可以引用 .drink 和 .food 无需对其进行限定。这是因为该 with 声明设置 . 为指向 .Values.favorite。在 {{end}} 后 . 复位其先前的范围。
但是请注意!在受限范围内,此时将无法从父范围访问其他对象。例如,下面会报错:
{{- with .Values.favorite}} drink: {{.drink | default \"tea\" | quote}} food: {{.food | upper | quote}} release: {{.Release.Name}} {{- end}}
它会产生一个错误,因为 Release.Name 它不在 . 限制范围内。但是,如果我们交换最后两行,所有将按预期工作,因为范围在 之后被重置。
{{- with .Values.favorite}} drink: {{.drink | default \"tea\" | quote}} food: {{.food | upper | quote}} {{- end}} release: {{.Release.Name}}
看下 range,我们看看模板变量,它提供了一个解决上述范围问题的方法。
5.8.5 循环 range 动作许多编程语言都支持使用 for 循环,foreach 循环或类似的功能机制进行循环。在 Helm 的模板语言中,遍历集合的方式是使用 range 操作子。
首先,让我们在我们的 values.yaml 文件中添加一份披萨配料列表:
favorite: drink: coffee food: pizzapizzaToppings: - mushrooms - cheese - peppers - onions
现在我们有一个列表(模板中称为 slice)pizzaToppings。我们可以修改我们的模板,将这个列表打印到我们的 ConfigMap 中:
apiVersion: v1kind: ConfigMapmetadata: name: {{.Release.Name}}-configmapdata: myvalue: \"Hello World\" {{- with .Values.favorite}} drink: {{.drink | default \"tea\" | quote}} food: {{.food | upper | quote}} {{- end}} toppings: |- {{- range .Values.pizzaToppings}} - {{. | title | quote}} {{- end}}
让我们仔细看看 toppings:list。该 range 函数将遍历 pizzaToppings 列表。但现在发生了一些有趣的事. 就像 withsets 的范围 .,range 操作子也是一样。每次通过循环时,. 都设置为当前比萨饼顶部。也就是第一次 . 设定 mushrooms。第二个迭代它设置为 cheese,依此类推。
我们可以直接向管道发送 . 的值,所以当我们这样做时 {{. | title | quote}},它会发送 . 到 title(标题 case 函数),然后发送到 quote。如果我们运行这个模板,输出将是:
# Source: mychart/templates/configmap.yamlapiVersion: v1kind: ConfigMapmetadata: name: edgy-dragonfly-configmapdata: myvalue: \"Hello World\" drink: \"coffee\" food: \"PIZZA\" toppings: |- - \"Mushrooms\" - \"Cheese\" - \"Peppers\" - \"Onions\"
现在,在这个例子中,我们碰到了一些棘手的事情。该 toppings: |- 行声明了一个多行字符串。所以我们的 toppings list 实际上不是 YAML 清单。这是一个很大的字符串。我们为什么要这样做?因为 ConfigMaps 中的数据 data 由键 / 值对组成,其中键和值都是简单的字符串。要理解这种情况,请查看 Kubernetes ConfigMap 文档.。但对我们来说,这个细节并不重要。
YAML 中的 |- 标记表示一个多行字符串。这可以是一种有用的技术,用于在清单中嵌入大块数据,如此处所示。
有时能快速在模板中创建一个列表,然后遍历该列表是很有用的。Helm 模板有一个功能可以使这个变得简单:tuple。在计算机科学中,元组是类固定大小的列表类集合,但是具有任意数据类型。这粗略地表达了 tuple 的使用方式。
sizes: |- {{- range tuple \"small\" \"medium\" \"large\"}} - {{.}} {{- end}} sizes: |- - small - medium - large
除了list和tuple之外,range还可以用于遍历具有键和值的集合(如map 或 dict)。当在下一节我们介绍模板变量时,将看到如何做到这一点。
5.9 变量我们已经了解了函数,管道,对象和控制结构,我们可以在许多编程语言中找到更基本的用法之一:变量。在模板中,它们使用的频率较低。我们将看到如何使用它们来简化代码,并更好地使用 with 和 range。
在前面的例子中,我们看到这段代码会失败:
{{- with .Values.favorite}} drink: {{.drink | default \"tea\" | quote}} food: {{.food | upper | quote}} release: {{.Release.Name}} {{- end}}
Release.Name 不在该 with 块中限制的范围内。解决范围问题的一种方法是将对象分配给可以在不考虑当前范围的情况下访问的变量。
在 Helm 模板中,变量是对另一个对象的命名引用。它遵循这个形式 $name。变量被赋予一个特殊的赋值操作符::=。我们可以使用变量重写上面的 Release.Name。
apiVersion: v1kind: ConfigMapmetadata: name: {{.Release.Name}}-configmapdata: myvalue: \"Hello World\" {{- $relname := .Release.Name -}} {{- with .Values.favorite}} drink: {{.drink | default \"tea\" | quote}} food: {{.food | upper | quote}} release: {{$relname}} {{- end}}
注意,在我们开始 with 块之前,我们赋值 $relname :=.Release.Name。现在在 with 块内部,$relname 变量仍然指向发布名称。
会产生这样的结果:
# Source: mychart/templates/configmap.yamlapiVersion: v1kind: ConfigMapmetadata: name: viable-badger-configmapdata: myvalue: \"Hello World\" drink: \"coffee\" food: \"PIZZA\" release: viable-badger
变量在 range 循环中特别有用。它们可以用于类似列表的对象以同时捕获索引和值:
toppings: |- {{- range $index, $topping := .Values.pizzaToppings}} {{$index}}: {{ $topping }} {{- end}}
注意,range 首先是变量,然后是赋值运算符,然后是列表。这将分配整数索引(从零开始)给 $index,值给 $topping。运行它将产生:
toppings: |- 0: mushrooms 1: cheese 2: peppers 3: onions
对于同时具有键和值的数据结构,我们可以使用 range 来获得两者。例如,我们可以对 .Values.favorite 像这样循环:
apiVersion: v1kind: ConfigMapmetadata: name: {{.Release.Name}}-configmapdata: myvalue: \"Hello World\" {{- range $key, $val := .Values.favorite}} {{$key}}: {{ $val | quote }} {{- end}}
现在在第一次迭代中,$key 是 drink,$val 是 coffee,第二次,$key 是 food,$val 会 pizza。运行上面的代码会生成下面这个:
# Source: mychart/templates/configmap.yamlapiVersion: v1kind: ConfigMapmetadata: name: eager-rabbit-configmapdata: myvalue: \"Hello World\" drink: \"coffee\" food: \"pizza\"
变量通常不是 “全局” 的。它们的范围是它们所在的块。之前,我们在模板的顶层赋值 $relname。该变量将在整个模板的范围内起作用。但在我们的最后一个例子中,$key 和 $val 只会在该 {{range...}}{{end}} 块的范围内起作用。
然而,总有一个变量是全局 $ 变量 - 这个变量总是指向根上下文。当你在需要知道 chart 发行名称的范围内循环时,这非常有用。
举例说明:
{{- range .Values.tlsSecrets}}apiVersion: v1kind: Secretmetadata: name: {{.name}} labels: # Many helm templates would use `.` below, but that will not work, # however `$` will work here app.kubernetes.io/name: {{template \"fullname\" $}} # I cannot reference .Chart.Name, but I can do $.Chart.Name helm.sh/chart: \"{{$.Chart.Name}}-{{ $.Chart.Version }}\" app.kubernetes.io/instance: \"{{$.Release.Name}}\" app.kubernetes.io/managed-by: \"{{$.Release.Service}}\"type: kubernetes.io/tlsdata: tls.crt: {{.certificate}} tls.key: {{.key}}{{- end}}
到目前为止,我们只查看了一个文件中声明的一个模板。但是Helm模板语言的强大功能之一是它能够声明多个模板并将它们一起使用。我们将在下一节中讨论。
5.10 命名模版现在是开始创建超过一个模板的时候了。在本节中,我们将看到如何在一个文件中定义命名模板,然后在别处使用它们。命名模板(有时称为部分或子模板)是限定在一个文件内部的模板,并起一个名称。我们有两种创建方法,以及几种不同的使用方法。
在 “流量控制” 部分中,我们介绍了声明和管理模板三个动作:define,template,和 block。在本节中,我们将介绍这三个动作,并介绍一个 include 函数,与 template 类似功能。
在命名模板时要注意一个重要的细节:模板名称是全局的。如果声明两个具有相同名称的模板,则最后加载一个模板是起作用的模板。由于子 chart 中的模板与顶级模板一起编译,因此注意小心地使用特定 chart 的名称来命名模板。
通用的命名约定是为每个定义的模板添加 chart 名称:{{define \"mychart.labels\"}}。通过使用特定 chart 名称作为前缀,我们可以避免由于同名模板的两个不同 chart 而可能出现的任何冲突。
5.10.1 partials 和 _ 文件到目前为止,我们已经使用了一个文件,一个文件包含一个模板。但 Helm 的模板语言允许创建指定的嵌入模板,可以通过名称访问。
在我们开始编写这些模板之前,有一些文件命名约定值得一提:
大多数文件 templates/ 被视为包含 Kubernetes manifestsNOTES.txt 是一个例外名称以下划线(_)开头的文件被假定为没有内部 manifest。这些文件不会渲染 Kubernetes 对象定义,而是在其他 chart 模板中随处可用以供调用。这些文件用于存储 partials 和辅助程序。事实上,当我们第一次创建时 mychart,我们看到一个叫做文件 _helpers.tpl。该文件是模板 partials 的默认位置。
5.10.2 用 define 和 template 声明和使用模板6.1 制作charts将用slate做好的go2cloud-api-doc 利用helm做成charts,方便后续部署helm create go2cloud-api-doc[root@master go2cloud-api-doc]# tree ├── charts├── Chart.yaml├── templates│ ├── deployment.yaml│ ├── _helpers.tpl│ ├── NOTES.txt│ ├── service.yaml│ └── tests│ └── test-connection.yaml└── values.yaml3 directories, 8 files
本文链接: http://helm.immuno-online.com/view-765527.html