侧边栏壁纸
博主头像
孔子说JAVA博主等级

成功只是一只沦落在鸡窝里的鹰,成功永远属于自信且有毅力的人!

  • 累计撰写 285 篇文章
  • 累计创建 125 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

Helm3入门教程-21:Helm3 的命名模板

孔子说JAVA
2022-05-01 / 0 评论 / 0 点赞 / 154 阅读 / 6,528 字 / 正在检测是否收录...

Helm3入门教程全系列,26小时轻松掌握Helm

到目前为止,我们已经使用了单个文件,且单个文件中包含了单个模板,在实际的应用中,很多都是相对比较复杂的,往往会超过⼀个模板,如果有多个应用模板,我们应该如何进行处理呢?Helm模板语言一个很强大的特性命名模板,就是能够声明多个模板并将它们一起使用。在本节中,我们将看到如何在一个文件中定义命名模板,然后在其他位置使用它们。

  • 前面的文章中我们学习的是在 template 目录下定义模板文件,这些模板文件严格上来说都是 Kubernetes 的清单文件,也就是在执行 install 命令时会将渲染后的文件传递给 Kubernetes 来进行部署。

1、了解命名模板

命名模板(有时称为部分或子模板)是限定在一个文件内部的模板,并使用了一个名字。在 “流程控制” 部分,我们介绍了声明和管理模板三种操作:define,template,和 block。在本节中,我们将介绍这三种操作,并介绍一个特殊用途的 include 函数,类似于template操作。

  • 命名模板时要记住一个重要细节:模板名称是全局的。如果您声明了两个相同名称的模板,则最后加载的那个模板才是起作用的模板。 因为在子chart中的模板和顶层模板一起编译,命名时要注意使用特定 chart 的名称来命名模板。

  • 一个常见的命名惯例是用chart名称作为模板前缀:{{ define "mychart.labels" }}。使用特定chart名称作为前缀可以避免可能因为两个不同chart使用了相同名称的模板而引起的冲突。

  • 子模板文件可以在任意模板文件中进行引用。这样做可以大大减少主模板文件的代码量,也可以更灵活的进行复用。

在我们开始编写命名模板之前,有一些文件命名约定值得一提:

  • templates/中的大多数文件被视为包含Kubernetes manifests(Kubernetes清单).
  • NOTES.txt 是一个例外
  • 名称以下划线 _ 开头的文件被假定为没有包含manifest。这些文件不会渲染为 Kubernetes 对象定义,但在其他chart模板中都可用。

我们前面提到过 templates 目录下⾯除了 NOTES.txt 文件和以下划线 _ 开头命令的文件之外,都会被当做 kubernetes 的资源清单文件,而这个下划线开头的文件不会被当做资源清单外,还可以被其他chart 模板中调用,这个就是 Helm 中的 partials 文件,我们完全就可以将命名模板定义在这些 partials 文件中,默认就是 _helpers.tpl 文件了。(这些文件用于存储 partials 和辅助对象)

2、用define声明模板,template使用模板

使用 define 关键字就可以允许我们在模板文件内部创建⼀个命名模板,它的语法格式如下:

{{ define "MY.NAME" }}
  # 模板内容区域
{{ end }}

例如,我们可以定义一个模板来封装一个 Kubernetes 标签块:

{{- define "mychart.labels" }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
{{- end }}

然后我们可以将此模板嵌入到现有的 ConfigMap 中,然后使⽤ template 关键字在需要的地⽅包含进来即可:

{{- define "mychart.labels" }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
{{- end }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  {{- template "mychart.labels" }}
data:
  myvalue: "Hello World"
  {{- range $key, $val := .Values.favorite }}
  {{ $key }}: {{ $val | quote }}
  {{- end }}

当模板引擎读取该文件时,它将存储引用 mychart.labels 直到 template "mychart.labels" 被调用。然后它将在文件内渲染该模板。结果如下所示:

# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: running-panda-configmap
  labels:
    generator: helm
    date: 2022-04-13
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "pizza"

我们可以看到 define 区域定义的命名模板被嵌入到了 template 所在的区域,但是如果我们将命名模板全都写入到⼀个模板文件中的话无疑会增大模板的复杂性。还记得我们在创建 chart 包的时候,templates 目录下⾯默认会生成⼀个 _helpers.tpl 文件吗?通常,Helm chart 通常将这些模板放入 partials 文件中,也就是 _helpers.tpl文件中。

现在我们将上⾯定义的命名模板移动到 templates/_helpers.tpl 文件中去:

{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
{{- end }}

按照惯例,define 函数应该有一个简单的文档块来描述他们所做的事情。

⼀般情况下⾯,我们都会在命名模板头部加⼀个简单的文档块({{/* ... */}}),用来描述命名模板的用途。现在我们将命名模板从模板文件 templates/configmap.yaml 中移除,当然还是需要保留 template 来嵌入命名模板内容,名称还是之前的 mychart.lables,这是因为模板名称是全局的,所以我们可以直接获取到。

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  {{- template "mychart.labels" }}
data:
  myvalue: "Hello World"
  {{- range $key, $val := .Values.favorite }}
  {{ $key }}: {{ $val | quote }}
  {{- end }}

我们再用 DEBUG 模式来调试下,可以看到完全符合预期。

如上所述,模板名称是全局的 。因此,如果两个模板被命名为相同的名称,则最后一次使用的模板将被使用。由于子 chart 中的模板与顶级模板一起编译,因此最好使用 chart 专用名称命名模板。一个流行的命名约定是为每个定义的模板添加 chart 名称:{{ define “mychart.labels” }}。

3、设置模板的范围

上面我们定义的命名模板中,没有使用任何对象,只是使用了⼀个简单的函数,如果我们在里面加入 chart 对象相关信息呢 templates/_helpers.tpl

{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
    chart: {{ .Chart.Name }}
    version: {{ .Chart.Version }}
{{- end }}

如果我们这样做,将不会得到我们所期望的结果:

# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: moldy-jaguar-configmap
  labels:
    generator: helm
    date: 2016-11-02
    chart:
    version:

chart 的名称和版本都没有正确被渲染,这是因为他们不在我们定义的模板范围内,当一个已命名的模板(用于创建 define)被渲染时,它会接收由 template 调用时传⼊的作用域,而我们这里 {{- template "mychart.labels" }} 并没有传⼊对应的作用域,因此模板中我们⽆法调用到 .Chart 对象,要解决也非常简单,我们只需要在 template 后面加上作用域范围即可:

# 注意后面的点 .
{{- template "mychart.labels" . }}

我们在 template 末尾传递了 . ,表示当前的最顶层的作用范围,我们可以很容易地通过 .Values 或者 .Values.favorite 或者我们想要的任何范围获取数据。现在我们使用命令 helm install --dry-run --debug ./mychart 再来渲染下模板:

# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: plinking-anaco-configmap
  labels:
    generator: helm
    date: 2016-11-02
    chart: mychart
    version: 0.1.0

现在 {{ .Chart.Name }} 解析为 mychart,{{ .Chart.Version }} 解析为 0.1.0。

4、include 函数

假设我们在 _helpers.tpl 文件中已经定义了一个如下所示的简单模板:

{{- define "mychart.app" -}}
app_name: {{ .Chart.Name }}
app_version: "{{ .Chart.Version }}+{{ .Release.Time.Seconds }}"
{{- end -}}

然后我们将该命名模板插入到 configmap 模板文件的 labels 部分和 data 部分:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  labels:
    {{ template "mychart.app" .}}
data:
  myvalue: "Hello World"
  {{- range $key, $val := .Values.favorite }}
  {{ $key }}: {{ $val | quote }}
  {{- end }}
{{ template "mychart.app" . }}

输出不是我们所期望的:

# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: measly-whippet-configmap
  labels:
    app_name: mychart
app_version: "0.1.0+1478129847"
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "pizza"
app_name: mychart
app_version: "0.1.0+1478129847"

注意,app_version 缩进在两个地方都是错误的。为什么?因为被替换的模板具有与右侧对齐的文本。而template 只是表示⼀个嵌入动作而已,不是⼀个函数,所以原本命名模板中是怎样的格式,嵌入进来后还是同样的格式,那如果我们在命名模板中给内容区域都空了两个空格,会渲染出什么呢?有兴趣的小伙伴可以自己尝试debug一下看看哦。

操作之后你可以看到 data 区域里面的内容是渲染正确的,但是上⾯ labels 区域是不正常的,因为命名模板里⾯的内容是属于 labels 标签的,是不符合预期的,但是我们又不可能再去把命名模板里面的内容再增加两个空格,因为这样的话 data 里面的格式又不符合预期了。为了解决这个问题,Helm 提供了另外⼀个⽅案来代替 template ,那就是使⽤ include 函数,在需要控制空格的地⽅使⽤ indent 管道函数来⾃⼰控制,比如上⾯的例⼦我们替换成 include 函数,并用 indent 纠正正确缩进:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  labels:
{{ include "mychart.app" . | indent 4 }}
data:
  myvalue: "Hello World"
  {{- range $key, $val := .Values.favorite }}
  {{ $key }}: {{ $val | quote }}
  {{- end }}
{{ include "mychart.app" . | indent 2 }}

在 labels 区域我们需要4个空格,所以在管道函数 indent 中,传入参数4就可以,而在 data 区域我们只需要2个空格,所以我们传入参数2即可以,现在我们来渲染下我们这个模板看看是否符合预期呢:

# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: edgy-mole-configmap
  labels:
    app_name: mychart
    app_version: "0.1.0+1478129987"
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "pizza"
  app_name: mychart
  app_version: "0.1.0+1478129987"

可以看到是符合我们的预期,现在生成的 YAML 每个部分都正确缩进的。

所以在 Helm 模板中我们使⽤ include 函数要比 template 更好,可以更好地处理 YAML ⽂件的输出格式。

5、tpl 函数

将 模板中引用 模板变量的 内容输出。

values.yaml

favorite:
  game: LOL
  drink: coffee
like:
  - football
  - basketball
  - volleyball
  - doubleball
global:
  service: web
image:
  repository: jicki/myapp
  tag: 'v2'
hostsPort:
  http: 80
  https: 443
containerPort:
  http: 80
  https: 443
http: "{{ .Values.containerPort.http }}"
https: "{{ .Values.containerPort.https }}"
notTpl: |
        http: {{ .Values.http }}
        https: {{ .Values.https }}
tpl: |
        http: {{ tpl .Values.http . }}
        https: {{ tpl .Values.https . }}

运行 template

root@kubernetes:/opt/helm/myapp# helm template . --show-only templates/tpl.yaml
---
# Source: myapp/templates/tpl.yaml
notTpl: |
        http: {{ .Values.containerPort.http }}
        https: {{ .Values.containerPort.https }}
tpl: |
        http: 80
        https: 443
0

评论区