本文参考 Helm 官网编写,接近照抄,只是为了让自己更快吸收这些东西

在上一遍中,使用 helm create xxx 创建好了一个 chart 包的模板,生成的内容有关 go 模板的东西是看不懂的,至少我看不懂,比如

{{- toYaml . | nindent 8 }}
{{- with .Values.nodeSelector }}
...

toYamlwith 都是什么意思,有很多 go 函数是需要明白,才可以继续进行模板的开发的

内置对象

对象从模板引擎传递到模板中,在代码中可以传递对象,也有一种方法可以在模板宏创建新的对象,比如 tuple 函数。对象可以很简单,也可以包含其他对象或函数,例如,Release 对象就包含几个对象(比如 Release.Name),Files 对象就包含几个函数。

前面提到过可以在模板中使用 {{ .Release.Name }} 获取 release 的名称,Release 是可以在模板中访问的几个顶级对象之一:

  • Release:该对象描述了 release 本身的相关信息,它内部有几个对象:

    • Release.Name:release 名称
    • Release.Namespace:release 安装到的命名空间
    • Release.IsUpgrade:如果当前操作是升级或回滚,则该值为 true
    • Release.IsInstall:如果当前操作是安装,则将其设置为 true
    • Release.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 installhelm 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"

变量

在模板中,变量的使用频率较低,但是,还是可以使用他们来简化代码,以及更好地使用 withrange

如以下模板会渲染失败

{{- 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 懒

说实话后面的东西不想写了,我累了跟着上面的链接看吧,挺好的

评论




正在载入...
PoweredHexo
HostedAliyun
DNSAliyun
ThemeVolantis
UV
PV
BY-NC-SA 4.0