本文参考 Helm 官网编写,接近照抄,只是为了让自己更快吸收这些东西
在上一遍中,使用 helm create xxx
创建好了一个 chart 包的模板,生成的内容有关 go 模板的东西是看不懂的,至少我看不懂,比如
{{- toYaml . | nindent 8 }}
{{- with .Values.nodeSelector }}
...
toYaml
和 with
都是什么意思,有很多 go 函数是需要明白,才可以继续进行模板的开发的
内置对象
对象从模板引擎传递到模板中,在代码中可以传递对象,也有一种方法可以在模板宏创建新的对象,比如 tuple
函数。对象可以很简单,也可以包含其他对象或函数,例如,Release 对象就包含几个对象(比如 Release.Name),Files 对象就包含几个函数。
前面提到过可以在模板中使用 {{ .Release.Name }}
获取 release 的名称,Release 是可以在模板中访问的几个顶级对象之一:
Release
:该对象描述了 release 本身的相关信息,它内部有几个对象:Release.Name
:release 名称Release.Namespace
:release 安装到的命名空间Release.IsUpgrade
:如果当前操作是升级或回滚,则该值为 trueRelease.IsInstall
:如果当前操作是安装,则将其设置为 trueRelease.Revision
:release 的 revision 版本号,在安装的时候,值为1,每次升级或回滚都会增加Reelase.Service
:渲染当前模板的服务,在 Helm 上,实际上该值始终为 Helm
Values
:从values.yaml
文件和用户提供的 values 文件传递到模板的 Values 值,默认情况下,Values 是空的。Chart
:获取Chart.yaml
文件的内容,该文件中的任何数据都可以访问,例如{{ .Chart.Name }}-{{ .Chart.Version}}
可以渲染成mychart-0.1.0
,该对象下面可用的字段前面我们已经提到过了。Files
:可以访问 chart 中的所有非特殊文件,虽然无法使用它来访问模板文件,但是可以来访问 chart 中的其他文件。Files.Get
:用于根据名称获取文件(比如.Files.Get config.ini
)Files.GetBytes
:用于以 bytes 数组而不是字符串的形式来获取文件内容的函数,这对于类似于图片之类的东西很有用Files.Glob
:用于返回名称于给定的 shell glob 模式匹配的文件列表Files.Lines
:可以逐行读取文件的函数,对于遍历文件中的每行内容很有用Files.AsSecrets
:将文件内容以 Base64 编码的字符串返回的函数Files.AsConfig
:将文件正文作为 YAML 字典返回的函数
Capabilities
:提供了获取有关 Kubernetes 集群支持功能的信息的对象Capabilities.APIVersions
:支持的版本集合Capabilities.APIVersions.Has $version
:判断一个版本(比如batch/v1
)或资源(比如apps/v1/Deployment
)是否可用Capabilities.Kube.Version
:Kubernetes 的版本Capabilities.Kube
:是 Kubernetes 版本的缩写Capabilities.Kube.Major
:Kubernetes 主版本Capabilities.Kube.Minor
:Kubernetes 的次版本
Template
:包含当前正在执行的模板的相关信息Name
:当前模板的命名空间文件路径(比如mychart/templates/mytemplate.yaml
)BaePath
:当前 chart 的模板目录的命名空间路径(比如mychart/templates
)
需要注意的是内置的对象始终是以大写字母开头的,这也是符合 Go 的命名约定的,创建自己的名称的时候,可以自由使用适合你团队的约定,一些团队,比如 Kubernetes Charts 团队,选择仅使用首字母小写,以区分本地名称和内置名称,这里我们也会遵循该约定。
Values 文件
values 文件的使用也是来自内置对象 Values
,该对象提供对传递到 chart 中的 values 值的访问,其内容主要有4个来源:
- chart 文件中的
values.yaml
文件,也就是 chart 依赖中的 - 如果该 chart 作为另一个 chart 的依赖,除了通过自己的 values.yaml之外,还可以通过上级或者父 chart 的
values.yaml
文件 - 用
-f
参数传递给helm install
或helm upgrade
的 values 值文件(例如helm install -f myvals.yaml ./mychart
) - 用
--set
传递的各个参数(例如helm install --set foo=bar ./mychart
)
应用先后顺序为:**–set/-f > 父chart > 子chart**
函数与管道
函数与管道就涉及到在本文最开始提到的那种不知道作用的单词
现有如下 values.yaml
image:
name: nginx
repository: harbor.feiyi.com
pullPolicy: IfNotPresent
使用这一点配置来理解学习一下管道和函数
模板语言有一个强大的功能就是管道(Pipeline)概念,管道利用 UNIX 的概念,将一系列模板命令链接在一起,一起对外提供服务,换句话说,管道是按顺序完成多项工作的有效方式
quote:为值增加引号
image: {{ .Values.image.name | quote }}
# 解析后为
image: "nginx"
upper:将值转换为大写
image: {{ .Values.image.name | upper | quote }}
# 解析后为
image: "NGINX"
title:单词首字母大写
image: {{ .Values.image.name | title | quote }}
# 解析后为
image: "Nginx"
repeat:将值重复n次
image: {{ .Values.image.name | repeat 3 | quote }}
# 解析后为
image: "nginxnginxnginx"
default:当values.yaml中没有配置值的情况下,将采用该函数配置的默认值
tags: {{ .Values.image.tags | default "v1" | quote }}
# 解析后为
tags: "v1"
在一个真实的 chart 模板中,所有的静态默认值都应位于 values.yaml
文件中,并且不应该重复使用 default
函数,但是,默认命令非常适合计算不能在 values.yaml
文件中声明的 values 值.
不过在有些地方,if
条件语句可能比 default 函数更合适
缩进函数
indent: 在值前面添加缩进的空格数量
tags: {{ .Values.image.tags | default "v1" | quote | indent 2 }}
# 解析后为
tags: "v1"
模板函数和管道是将数据转换后然后将其插入到 YAML 文件中的一种强大方法,但是有的时候有必要添加一些模板逻辑,这些逻辑比仅仅插入字符串要复杂得多
运算符函数
另外需要注意的是在模板中,运算符(eq、ne、lt、gt、and、or 等等)均实现为函数,在管道中,运算符可以用括号()
进行分割。
需要了解更多函数请访问官方链接:https://helm.sh/zh/docs/chart_template_guide/function_list/
流程控制
控制流程为模板作者提供了控制模板生成流程的功能,Helm 的模板语言提供了以下一些流程控制:
if/else
条件语句with
指定一个作用域范围range
提供类似于for each
这样的循环样式
除此之外,还提供了一些声明和使用命名模板的操作:
define
在模板内部声明一个新的命名模板template
导入一个命名模板block
声明了一种特殊的可填充模板区域。
在使用中慢慢来理解执行流程控制的操作。
if/else
首先我们先来了解下有条件地在模板中包含一个文本区域,就是 if/else
,这个条件判断的基本结构如下所示:
{{ if PIPELINE }}
{{ else if OTHER PIPELINE }}
{{ else }}
{{ end }}
所有语言的 if 语句都是同样的逻辑,就不多解释了
可以看到我们这里判断的是管道而不是一个 values 值,这是因为控制结构可以执行整个管道,而不仅仅是判断值。如果值为以下的一些内容,则将管道判断为 false:
- 布尔 false
- 数字零
- 一个空字符串
- nil(empty 或者 null)
- 一个空集合(map、slice、tuple、dict、array)
在其他条件下,条件都为真。
现有如下 values.yaml
# 0 为 false,条件不成立,可以用作开关来用
hpa:
enable: 0
运用到模板中,如下所示
{{ if .Values.hpa.enable }}
apiversion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name:
namespace:
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment
maxReplicas:
minReplicas:
{{ end }}
以上表示,.Values.hpa.enable
的结果为 true 时,将创建并应用 hpa 资源模板。
空格控制
还有一个非常重要的功能点就是关于空格的控制,因为空格对于 YAML 文件非常重要的,不是说任意缩进就可以,依然还是以前面的例子为例,来格式化下模板格式以更易于阅读
如果使用以下格式写,会影响阅读
{{ if .Values.hpa.enable }}123{{ end }}
# 解析后为
123
如果使用以下格式下,上一行会有空格
{{ if .Values.hpa.enable }}
123
{{ end }}
# 解析后为
123
为了更易于阅读,可以使用 -
来去除这样的空格或者空行,换行符也算是空格
{{- }}: 表示去除前面的空格
{{ -}}: 表示去除后面的空格
{{- -}}: 表示去除前后的空格
注意符号要和中间的语句空开,尽量在模板中使用 {{- }}
,频繁的不整齐的使用会使模板渲染后的文件错乱
更改后如下:
{{- if .Values.hpa.enable }}
123
{{- end }}
# 解析后为
123
with
通过 with
修改作用域
这里要解释清楚的是作用域的概念,默认的作用域 .
,而调用变量时,作用域是 .Values
这样的
with 语法 和 if 类似
{{ with PIPELINE }}
{{ end }}
不使用 with
之前如下:
{{- if .Values.hpa.enable }}
123
{{- end }}
使用 with
之后
{{- with .Values.hpa }}
{{- if .enable }}
123
{{- end }}
{{- end }}
看完示例应该会很直观的,使用 with
之后 .enable
中的 .
= .Values.hpa
range
range 是一种循环操作,类似 Ansible
中的 with_items
,用来循环读取列表。同时也具备 with 的特性,也就是作用域的更改
比如,k8s yaml 中的一个 command 在 values.yaml 中这样写:
exec:
- sh
- -c
- sleep 60
使用 range
调用
tags:
{{- range .Values.exec }}
- {{ . | quote }} # 这里的 . = .Values.exec 循环到的每个值
{{- end }}
# 渲染后
tags:
- "sh"
- "-c"
- "sleep 60"
变量
在模板中,变量的使用频率较低,但是,还是可以使用他们来简化代码,以及更好地使用 with
和 range
。
如以下模板会渲染失败
{{- with .Values.hpa }}
{{- if .enable }}
apiversion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name:
namespace:
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ .Release.Name }}
maxReplicas:
minReplicas:
{{- end }}
{{- end }}
渲染失败的原因是在使用 with 进入另一个作用域后,在 with 范围内 .Release.Name
会被渲染为 .Values.hpa.Release.Name
可以使用变量的形式将 .Release.Name
事先定义好,也就是说定义的变量是在 with 作用域范围外的。
在 Helm 模板中,变量是对另外一个对象的命名引用。它遵循 $name
格式,变量使用特殊的赋值运算符进行赋值 :=
,修改上面的模板,为 Release.Name
声明一个变量:
{{- $releasename := .Release.Name -}}
{{- with .Values.hpa }}
{{- if .enable }}
apiversion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name:
namespace:
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ $releasename }} # 引用变量即可
maxReplicas:
minReplicas:
{{- end }}
{{- end }}
变量在 range
循环里面非常有用,它们可以用于类似于列表的对象来捕获索引和 value 值:
---
# values.yaml
exec:
- sh
- -c
- sleep 60
---
# 模板
tags:
{{- range $index, $exec := .Values.exec }}
{{ $index }}: {{ $exec }}
{{- end }}
# 渲染后
tags:
0: sh
1: -c
2: sleep 60
对于同时具有 key 和 value 的数据结构,也可以使用 range
来获得 key、value 的值,这块就和 Python 的遍历变量有点相似了。
---
# values.yaml
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: 1024m
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/ssl-redirect: false
---
# 模板
annotations:
{{- range $key, $val := .Values.annotations }}
{{ $key}}: {{ $val | quote }}
{{- end }}
# 渲染后
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "1024m"
nginx.ingress.kubernetes.io/rewrite-target: "/$1"
nginx.ingress.kubernetes.io/ssl-redirect: "false"
命名模板(_helpers.tpl)
一开始不懂命名模板是个什么也没关系,往下看看就会懂,但是我没法表达,正儿八经只能意会
所以贴个链接,不想写了。https://helm.sh/zh/docs/chart_template_guide/named_templates/
note guide clear 懒
说实话后面的东西不想写了,我累了跟着上面的链接看吧,挺好的!