ljzsdut
GitHubToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage
Edit page

04 Helm模板之控制流程和变量

模板函数和管道是通过转换信息并将其插入到 YAML 文件中的强大方法。但有时候需要添加⼀些比插入字符串更复杂的模板逻辑。这就需要使用到模板语⾔中提供的控制结构了。

控制流程为我们提供了控制模板生成流程的⼀种能力,Helm 的模板语⾔提供了以下几种流程控制:

  • if/else 条件块
  • with 指定范围
  • range 循环块

除此之外,它还提供了⼀些声明和使用命名模板段的操作:

  • define 在模板中声明⼀个新的命名模板
  • template 导入⼀个命名模板
  • block 声明了⼀种特殊的可填写的模板区域

关于 命名模板 的相关知识点,我们会在后⾯文章中详细讲解,这里我们暂时介绍 if/else 、 with 、 range 这3中控制流程的用法。更多的内容可以去Helm3官方文档中详细查看:点击查看

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 )

除了上⾯的这些情况外,其他所有条件都为 真 。

注:我们在if语句中谈论的是管道(PIPELINE)而不是值。这样做的原因是要明确控制结构可以执行整个管道,而不仅仅是评估值。

同样还是以上⾯的 ConfigMap 模板文件为例,添加⼀个简单的条件判断,如果 python 被设置为django,则添加⼀个 web: true

➜  ~ vim mychart/templates/configmap.yaml
➜  ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: {{ .Values.hello |default "Hello World" | quote}}
  k8s: {{ .Values.course.k8s | quote | upper }}
  python: {{ .Values.course.python | repeat 3 | quote }}
  {{ if eq .Values.course.python "django" }}web: true{{ end }}
➜  ~
➜  ~ helm install mychart mychart/  --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 15:22:04 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"
  k8s: "DEVOPS"
  python: "djangodjangodjango"
  web: true

在上⾯的模板文件中我们增加了⼀个条件语句判断 {{ if eq .Values.course.python “django” }}web:true{{ end }} ,其中运算符 eq 是判断是否相等的操作,除此之外,还有 ne 、 lt 、 gt 、 and 、 or 等运算符都是 Helm 模板已经实现了的,直接使用即可。这里 {{ .Values.course.python }} 的值在 values.yaml 文件中默认被设置为了django,所以正常来说下⾯的条件语句判断为真,所以模板文件最终被渲染后会有 web: true 这样的的⼀个条目。

可以看到上⾯模板被渲染后出现了 web: true 的条目,如果我们在安装的时候覆盖下 python 的值呢, 比如我们改成 ai :

➜  ~ helm install mychart mychart/  --dry-run --set course.python='ai'
NAME: mychart
LAST DEPLOYED: Tue Feb 23 15:26:52 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"
  k8s: "DEVOPS"
  python: "aiaiai"

根据我们模板⽂件中的定义,如果 {{ .Values.course.python }} 的值为 django 的话就会新增 web:true 这样的⼀个条目,但是现在我们是不是通过参数 –set 将值设置为了 ai,所以这里条件判断为假,正常来说就不应该出现这个条⽬了,上⾯我们通过 debug 模式查看最终被渲染的值也没有出现这个条目,证明条件判断是正确的。

运算符

  • eq
  • ne
  • lt
  • gt
  • and
  • or

空白控制

上⾯的条件判断语句是在⼀整行中的,如果平时经常写代码的同学可能非常不习惯了,我们⼀般会将其格式化为更容易阅读的形式,比如:

{{ if eq .Values.course.python "django" }}
web: true
{{ end }}

这样的话看上去比之前要清晰很多了,我们通过模板引擎来渲染⼀下,会得到如下结果:

➜  ~ vim mychart/templates/configmap.yaml
➜  ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: {{ .Values.hello |default "Hello World" | quote}}
  k8s: {{ .Values.course.k8s | quote | upper }}
  python: {{ .Values.course.python | repeat 3 | quote }}
  {{ if eq .Values.course.python "django" }}
  web: true
  {{ end }}
➜  ~
➜  ~ helm install mychart mychart/ --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 15:29:43 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"
  k8s: "DEVOPS"
  python: "djangodjangodjango"

  web: true

我们可以看到渲染出来会有多余的空行,这是因为当模板引擎运行时,它将⼀些值渲染过后,之前的指令被删除,但它之前所占的位置完全按原样保留剩余的空白了,所以就出现了多余的空行(主要是保留了换行符)。 YAML 文件中的空白是非常严格的,所以对于空白的管理非常重要,⼀不小心就会导致你的 YAML 文件格式错误。

其实我们可以通过使用在模板标识 {{ 后⾯添加破折号和空格{{- 来表示将空白左移,而在 }} 前面添加⼀个空格和破折号 -}} 表示应该删除右边的空白,另外需要注意的是换行符也是空白,也会被 -}} 删除!而且要注意的是,删除空白只对当前行有效。

使用这个语法,我们来修改我们上⾯的模板文件去掉多余的空白:

➜  ~ vim mychart/templates/configmap.yaml
➜  ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: {{ .Values.hello |default "Hello World" | quote}}
  k8s: {{ .Values.course.k8s | quote | upper }}
  python: {{ .Values.course.python | repeat 3 | quote }}
  {{- if eq .Values.course.python "django" }}
  web: true
  {{- end }}
➜  ~
➜  ~ helm install mychart mychart/ --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 15:37:29 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"
  k8s: "DEVOPS"
  python: "djangodjangodjango"
  web: true

是不是没有多余的空白了,但是我们需要谨慎地在同一行中同时使用{{--}} ,例如我们同时在 if 条件后⾯增加 -}} ,渲染是会报错的(准确地说是渲染不会报错,但k8s进行格式校验会报错):

➜  ~ vim mychart/templates/configmap.yaml
➜  ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: {{ .Values.hello |default "Hello World" | quote}}
  k8s: {{ .Values.course.k8s | quote | upper }}
  python: {{ .Values.course.python | repeat 3 | quote }}
  {{- if eq .Values.course.python "django" -}}
  web: true
  {{- end }}
➜  ~
➜  ~ helm install mychart mychart/ --dry-run
Error: YAML parse error on mychart/templates/configmap.yaml: error converting YAML to JSON: yaml: line 7: did not find expected key

其实,这个的模板渲染是没有问题的,这里的报错是因为helm在检验k8s资源的格式时,因渲染后的模板不符合yaml语法而报错。我们可以使用helm template --debug来验证:

➜  ~ helm template mychart mychart --debug
install.go:172: [debug] Original chart version: ""
install.go:189: [debug] CHART PATH: /Users/lijuzhang/mychart

---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"
  k8s: "DEVOPS"
  python: "djangodjangodjango"web: true
Error: YAML parse error on mychart/templates/configmap.yaml: error converting YAML to JSON: yaml: line 7: did not find expected key
helm.go:94: [debug] error converting YAML to JSON: yaml: line 7: did not find expected key
YAML parse error on mychart/templates/configmap.yaml
helm.sh/helm/v3/pkg/releaseutil.(*manifestFile).sort
	/private/tmp/helm-20200811-57904-1ok4z2o/pkg/releaseutil/manifest_sorter.go:146
helm.sh/helm/v3/pkg/releaseutil.SortManifests
	/private/tmp/helm-20200811-57904-1ok4z2o/pkg/releaseutil/manifest_sorter.go:106
helm.sh/helm/v3/pkg/action.(*Configuration).renderResources
	/private/tmp/helm-20200811-57904-1ok4z2o/pkg/action/action.go:162
helm.sh/helm/v3/pkg/action.(*Install).Run
	/private/tmp/helm-20200811-57904-1ok4z2o/pkg/action/install.go:239
main.runInstall
	/private/tmp/helm-20200811-57904-1ok4z2o/cmd/helm/install.go:242
main.newTemplateCmd.func2
	/private/tmp/helm-20200811-57904-1ok4z2o/cmd/helm/template.go:70
github.com/spf13/cobra.(*Command).execute
	/Users/brew/Library/Caches/Homebrew/go_mod_cache/pkg/mod/github.com/spf13/cobra@v1.0.0/command.go:842
github.com/spf13/cobra.(*Command).ExecuteC
	/Users/brew/Library/Caches/Homebrew/go_mod_cache/pkg/mod/github.com/spf13/cobra@v1.0.0/command.go:950
github.com/spf13/cobra.(*Command).Execute
	/Users/brew/Library/Caches/Homebrew/go_mod_cache/pkg/mod/github.com/spf13/cobra@v1.0.0/command.go:887
main.main
	/private/tmp/helm-20200811-57904-1ok4z2o/cmd/helm/helm.go:93
runtime.main
	/usr/local/Cellar/go/1.14.6/libexec/src/runtime/proc.go:203
runtime.goexit
	/usr/local/Cellar/go/1.14.6/libexec/src/runtime/asm_amd64.s:1373

我们可以发现渲染后的内容为python: "djangodjangodjango"web: trueweb: true直接跟在上一行的末尾了,这就导致不符合yaml的文件格式了。为了避免这个错误出现,我们一般只使用{{-即可。

注:有关模板中空白控制的详细信息,请参阅官方 Go 模板文档:Official Go template documentation

with修改范围

接下来我们来看下 with 关键词的使用,它用来控制变量作用域。前面的文章中 {{ .Release.xxx}} 或者 {{ .Values.xxx }} 的写法就是表示对当前范围的引用, .Values 就是告诉模板在当前范围中查找 Values 对象的值。而 with 语句就可以来控制变量的作用域范围,其语法和⼀个简单的 if 语句比较类似:

{{ with PIPELINE }}
# restricted scope
{{ end }}

with 语句可以允许将当前范围 . 设置为特定的对象,比如前⾯⼀直使用的 .Values.course ,我们可以使用 with 来将 . 范围指向 .Values.course:

➜  ~ vim mychart/templates/configmap.yaml
➜  ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: {{ .Values.hello |default "Hello World" | quote}}
  {{- with .Value.course }} #with语句
  k8s: {{ .Values.course.k8s | quote | upper }}
  python: {{ .Values.course.python | repeat 3 | quote }}
  {{- if eq .Values.course.python "django" }}
  web: true
  {{- end }}
  {{- end }}
➜  ~
➜  ~
➜  ~ helm install mychart mychart/ --dry-run
Error: template: mychart/templates/configmap.yaml:8:17: executing "mychart/templates/configmap.yaml" at <.Values.course.k8s>: nil pointer evaluating interface {}.course

上面我们增加了⼀个 {{- with .Values.course }}xxx{{- end }} 的块,这样的话我们就可以在当前的块里面直接引用 .python 和 .k8s 了,而不需要进⾏限定了,这是因为该 with 声明将 . 指向了 .Values.course ,在 {{- end }} 后 . 就会复原其之前的作用范围了,我们可以使用模板引擎来渲染上面的模板查看是否符合预期结果。

➜  ~ vim mychart/templates/configmap.yaml
➜  ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: {{ .Values.hello |default "Hello World" | quote}}
  {{- with .Values.course }}
  k8s: {{ .k8s | quote | upper }}
  python: {{ .python | repeat 3 | quote }}
  {{- if eq .python "django" }}
  web: true
  {{- end }}
  {{- end }}
➜  ~
➜  ~
➜  ~ helm install mychart mychart/ --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 15:57:16 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"
  k8s: "DEVOPS"
  python: "djangodjangodjango"
  web: true

不过需要注意的是在 with 声明的范围内,此时将无法从父范围访问到其他对象了,比如上面的模板渲染的时候将会报错,因为显然 .Release 根本就不在当前的 mychart 范围内:

➜  ~ vim mychart/templates/configmap.yaml
➜  ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: {{ .Values.hello |default "Hello World" | quote}}
  {{- with .Values.course }}
  k8s: {{ .k8s | quote | upper }}
  python: {{ .python | repeat 3 | quote }}
  {{- if eq .python "django" }}
  web: true
  {{- end }}
  release: {{ .Release.Name }}
  {{- end }}
➜  ~
➜  ~ helm install mychart mychart/ --dry-run
Error: template: mychart/templates/configmap.yaml:13:22: executing "mychart/templates/configmap.yaml" at <.Release.Name>: nil pointer evaluating interface {}.Name

当然如果我们最后两行交换下位置就正常了,因为 {{- end }} 之后范围就被重置了:

ame>: nil pointer evaluating interface {}.Name
➜  ~
➜  ~ vim mychart/templates/configmap.yaml
➜  ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: {{ .Values.hello |default "Hello World" | quote}}
  {{- with .Values.course }}
  k8s: {{ .k8s | quote | upper }}
  python: {{ .python | repeat 3 | quote }}
  {{- if eq .python "django" }}
  web: true
  {{- end }}
  {{- end }}
  release: {{ .Release.Name }}
➜  ~
➜  ~ helm install mychart mychart/ --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 16:03:26 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"
  k8s: "DEVOPS"
  python: "djangodjangodjango"
  web: true
  release: mychart

range循环

如果大家对编程语⾔熟悉的话,几乎所有的编程语⾔都支持类似于 for 、 foreach 或者类似功能的循环机制,在 Helm 模板语言中,是使用 range 关键字来进行循环操作。range可以用来遍历map,array或者slice。

相关语法:

{{- range .Values.course }}{{ . }}{{ end }}  #使用上下文
{{- range $key, $value := .Values.course }}  #同时声明key和value变量名称
{{- range $value := .Values.course }}        #仅声明value变量名称

我们在 values.yaml 文件中添加上⼀个 course 列表:

course:
  k8s: devops
  python: django
courselist:
- k8s
- python
- search
- golang

现在我们有⼀个 course 列表,修改 ConfigMap 模板文件来循环打印出该列表:

➜  ~ vim mychart/values.yaml
➜  ~ cat mychart/values.yaml
course:
  k8s: devops
  python: django
courselist:
- k8s
- python
- search
- golang


➜  ~ vim mychart/templates/configmap.yaml
➜  ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: {{ .Values.hello |default "Hello World" | quote}}
  {{- with .Values.course }}
  k8s: {{ .k8s | quote | upper }}
  python: {{ .python | repeat 3 | quote }}
  {{- if eq .python "django" }}
  web: true
  {{- end }}
  {{- end }}
  release: {{ .Release.Name }}
  courselist: |-
  {{- range .Values.courselist }}
    - {{ . | title | quote }}
  {{- end }}

可以看到最下面我们使用了⼀个 range 函数,该函数将会遍历 {{ .Values.courselist }} 列表,循环内部我们使用的是⼀个 . ,这是因为当前的作用域就在当前循环内,这个 . 从列表的第⼀个元素⼀直遍历到最后⼀个元素,然后在遍历过程中使用了 title 和 quote 这两个函数,前⾯这个函数是将字符串⾸字母变成大写,后⾯就是加上双引号变成字符串,所以按照上面这个模板被渲染过后的结果为:

➜  ~ helm install mychart mychart/ --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 17:20:07 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"
  k8s: "DEVOPS"
  python: "djangodjangodjango"
  web: true
  release: mychart
  courselist: |-
    - "K8s"
    - "Python"
    - "Search"
    - "Golang"

我们可以看到 courselist 按照我们的要求循环出来了。除了 list 或者 tuple,range 还可以用于遍历具有键和值的集合(如map 或 dict),这个就需要用到变量的概念了。类似于{{- range $index, $course := .Values.coursemap }},上面的示例是同时声明key和value变量名称,也可以只声明value变量的名称,例如{{- range $value := .Values.coursemap }}

变量

前面我们已经学习了函数、管理以及控制流程的使用方法,我们知道编程语言中还有⼀个很重要的概念叫:变量,在 Helm 模板中,使用变量的场合不是特别多,但是在合适的时候使用变量可以很好的解决我们的问题。如下面的模板:

{{- with .Values.course }} 
k8s: {{ .k8s | upper | quote }} 
python: {{ .python | repeat 3 | quote }} 
release: {{ .Release.Name }}
{{- end }}

我们在 with 语句块内添加了⼀个 .Release.Name 对象,但这个模板是错误的,编译的时候会失败,这是因为 .Release.Name 不在该 with 语句块限制的作用范围之内。

➜  ~ vim mychart/templates/configmap.yaml
➜  ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: {{ .Values.hello |default "Hello World" | quote}}
  {{- with .Values.course }}
  k8s: {{ .k8s | quote | upper }}
  python: {{ .python | repeat 3 | quote }}
  {{- if eq .python "django" }}
  web: true
  {{- end }}
  release: {{ .Release.Name }}
  {{- end }}
  courselist: |-
  {{- range .Values.courselist }}
    - {{ . | title | quote }}
  {{- end }}
➜  ~
➜  ~ helm install mychart mychart/ --dry-run
Error: template: mychart/templates/configmap.yaml:13:22: executing "mychart/templates/configmap.yaml" at <.Release.Name>: nil pointer evaluating interface {}.Name

我们可以将该对象赋值给⼀个变量可以来解决这个问题:

➜  ~ vim mychart/templates/configmap.yaml
➜  ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: {{ .Values.hello |default "Hello World" | quote}}
  {{- $releaseName := .Release.Name }}
  {{- with .Values.course }}
  k8s: {{ .k8s | quote | upper }}
  python: {{ .python | repeat 3 | quote }}
  {{- if eq .python "django" }}
  web: true
  {{- end }}
  release: {{ $releaseName }}
  {{- end }}
  courselist: |-
  {{- range .Values.courselist }}
    - {{ . | title | quote }}
  {{- end }}
➜  ~
➜  ~ helm install mychart mychart/ --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 21:12:49 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"
  k8s: "DEVOPS"
  python: "djangodjangodjango"
  web: true
  release: mychart
  courselist: |-
    - "K8s"
    - "Python"
    - "Search"
    - "Golang"

我们可以看到我们在 with 语句上⾯增加了⼀句{{- $releaseName := .Release.Name }},其中$releaseName 就是后面的对象的⼀个引用变量,赋值操作使用 := ,这样with语句块内部的releaseName 变量仍然指向的是 .Release.Name 。

range变量字典

另外变量在 range 循环中也非常有用,我们可以在循环中用变量来同时捕获索引的值:

例如上⾯的这个列表,我们在 range 循环中使用index和course 两个变量来接收后⾯列表循环的索引和对应的值,最终可以得到如下结果:

➜  ~ vim mychart/templates/configmap.yaml
➜  ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: {{ .Values.hello |default "Hello World" | quote}}
  {{- $releaseName := .Release.Name }}
  {{- with .Values.course }}
  k8s: {{ .k8s | quote | upper }}
  python: {{ .python | repeat 3 | quote }}
  {{- if eq .python "django" }}
  web: true
  {{- end }}
  release: {{ $releaseName }}
  {{- end }}
  courselist: |-
  {{- range $index, $course := .Values.courselist }}
    - {{ $index }}: {{ $course | title | quote }}
  {{- end }}
➜  ~
➜  ~ helm install mychart mychart/ --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 21:32:39 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"
  k8s: "DEVOPS"
  python: "djangodjangodjango"
  web: true
  release: mychart
  courselist: |-
    - 0: "K8s"
    - 1: "Python"
    - 2: "Search"
    - 3: "Golang"

我们可以看到 courselist 下⾯将索引和对应的值都打印出来了,实际上具有键和值的数据结构我们都可以使⽤ range 来循环获得⼆者的值,比如我们可以对 .Values.course 这个字典来进行循环:

 ➜  ~ vim mychart/templates/configmap.yaml
➜  ~ cat mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: {{ .Values.hello |default "Hello World" | quote}}
  {{- $releaseName := .Release.Name }}
  {{- with .Values.course }}
  k8s: {{ .k8s | quote | upper }}
  python: {{ .python | repeat 3 | quote }}
  {{- if eq .python "django" }}
  web: true
  {{- end }}
  release: {{ $releaseName }}
  {{- end }}
  courselist: |-
  {{- range $index, $course := .Values.courselist }}
    - {{ $index }}: {{ $course | title | quote }}
  {{- end }}
  {{- range $key, $value := .Values.course }}
  {{ $key }}: {{ $value | upper | quote }}
  {{- end }}
➜  ~
➜  ~ helm install mychart mychart/ --dry-run
NAME: mychart
LAST DEPLOYED: Tue Feb 23 21:37:15 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"
  k8s: "DEVOPS"
  python: "djangodjangodjango"
  web: true
  release: mychart
  courselist: |-
    - 0: "K8s"
    - 1: "Python"
    - 2: "Search"
    - 3: "Golang"
  k8s: "DEVOPS"
  python: "DJANGO"

直接使用 range 循环,用变量key、value 来接收字段 .Values.course 的键和值。这就是变量在Helm 模板中的使用方法。