命名模板

    流控制部分, 我们介绍了三种声明和管理模板的方法:definetemplate,和block。在这部分,我们将使用这三种操作并介绍一种特殊用途的 include方法,类似于template操作。

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

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

    目前为止,我们已经使用了单个文件,且单个文件中包含了单个模板。但Helm的模板语言允许你创建命名的嵌入式模板, 这样就可以在其他位置按名称访问。

    在编写模板细节之前,文件的命名惯例需要注意:

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

    这些文件用来存储局部和辅助对象,实际上当我们第一次创建mychart时,会看到一个名为_helpers.tpl的文件,这个文件是模板局部的默认位置。

    define操作允许我们在模板文件中创建一个命名模板,语法如下:

    比如我们可以定义一个模板封装Kubernetes的标签:

    1. {{- define "mychart.labels" }}
    2. labels:
    3. generator: helm
    4. date: {{ now | htmlDate }}
    5. {{- end }}

    现在我们将模板嵌入到了已有的配置映射中,然后使用template包含进来:

    1. {{- define "mychart.labels" }}
    2. labels:
    3. generator: helm
    4. date: {{ now | htmlDate }}
    5. {{- end }}
    6. apiVersion: v1
    7. kind: ConfigMap
    8. metadata:
    9. name: {{ .Release.Name }}-configmap
    10. {{- template "mychart.labels" }}
    11. data:
    12. myvalue: "Hello World"
    13. {{- range $key, $val := .Values.favorite }}
    14. {{ $key }}: {{ $val | quote }}
    15. {{- end }}

    当模板引擎读取该文件时,它会存储mychart.labels的引用直到template "mychart.labels"被调用。 然后会按行渲染模板,因此结果类似这样:

    1. # Source: mychart/templates/configmap.yaml
    2. apiVersion: v1
    3. kind: ConfigMap
    4. metadata:
    5. name: running-panda-configmap
    6. labels:
    7. generator: helm
    8. date: 2016-11-02
    9. data:
    10. myvalue: "Hello World"
    11. drink: "coffee"
    12. food: "pizza"

    按照惯例,Helm chart将这些模板放置在局部文件中,一般是_helpers.tpl。把这个方法移到那里:

    1. {{/* Generate basic labels */}}
    2. {{- define "mychart.labels" }}
    3. labels:
    4. generator: helm
    5. date: {{ now | htmlDate }}
    6. {{- end }}

    按照惯例方法会有个简单的文档块({{/* ... */}})来描述要做的事。

    尽管这个定义是在_helpers.tpl中,但它仍能访问configmap.yaml

    1. kind: ConfigMap
    2. metadata:
    3. name: {{ .Release.Name }}-configmap
    4. {{- template "mychart.labels" }}
    5. data:
    6. myvalue: "Hello World"
    7. {{- range $key, $val := .Values.favorite }}
    8. {{ $key }}: {{ $val | quote }}
    9. {{- end }}

    如上所述,模板名称是全局的。因此,如果两个模板使用相同名字声明,会使用最后出现的那个。由于子chart中的模板和顶层模板一起编译, 最好用 chart特定名称 命名你的模板。常用的命名规则是用chart的名字作为模板的前缀: {{ define "mychart.labels" }}

    在上面定义的模板中,我们没有使用任何对象,仅仅使用了方法。修改定义好的模板让其包含chart名称和版本号:

    如果渲染这个,会得到以下错误:

    1. $ helm install --dry-run moldy-jaguar ./mychart
    2. Error: unable to build kubernetes objects from release manifest: error validating "": error validating data: [unknown object type "nil" in ConfigMap.metadata.labels.chart, unknown object type "nil" in ConfigMap.metadata.labels.version]

    要查看渲染了什么,可以用--disable-openapi-validation参数重新执行: helm install --dry-run --disable-openapi-validation moldy-jaguar ./mychart。 结果并不是我们想要的:

    1. # Source: mychart/templates/configmap.yaml
    2. apiVersion: v1
    3. kind: ConfigMap
    4. metadata:
    5. name: moldy-jaguar-configmap
    6. labels:
    7. generator: helm
    8. date: 2021-03-06
    9. chart:
    10. version:

    名字和版本号怎么了?没有出现在我们定义的模板中。当一个(使用define创建的)命名模板被渲染时,会接收被template调用传入的内容。 在我们的示例中,包含模板如下:

    1. {{- template "mychart.labels" }}

    没有内容传入,所以模板中无法用.访问任何内容。但这个很容易解决,只需要传递一个范围给模板:

    1. apiVersion: v1
    2. kind: ConfigMap
    3. metadata:
    4. name: {{ .Release.Name }}-configmap
    5. {{- template "mychart.labels" . }}

    注意这个在template调用末尾传入的.,我们可以简单传入.Values.Values.favorite或其他需要的范围。但一定要是顶层范围。

    1. # Source: mychart/templates/configmap.yaml
    2. apiVersion: v1
    3. kind: ConfigMap
    4. metadata:
    5. name: plinking-anaco-configmap
    6. labels:
    7. generator: helm
    8. date: 2021-03-06
    9. chart: mychart
    10. version: 0.1.0

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

    假设定义了一个简单模板如下:

    现在假设我想把这个插入到模板的labels:部分和data:部分:

    1. apiVersion: v1
    2. kind: ConfigMap
    3. name: {{ .Release.Name }}-configmap
    4. labels:
    5. {{ template "mychart.app" . }}
    6. data:
    7. myvalue: "Hello World"
    8. {{ $key }}: {{ $val | quote }}
    9. {{- end }}
    10. {{ template "mychart.app" . }}

    如果渲染这个,会得到以下错误:

    1. $ helm install --dry-run measly-whippet ./mychart
    2. Error: unable to build kubernetes objects from release manifest: error validating "": error validating data: [ValidationError(ConfigMap): unknown field "app_name" in io.k8s.api.core.v1.ConfigMap, ValidationError(ConfigMap): unknown field "app_version" in io.k8s.api.core.v1.ConfigMap]

    要查看渲染了什么,可以用--disable-openapi-validation参数重新执行: helm install --dry-run --disable-openapi-validation measly-whippet ./mychart。 输入不是我们想要的:

    1. # Source: mychart/templates/configmap.yaml
    2. apiVersion: v1
    3. kind: ConfigMap
    4. metadata:
    5. name: measly-whippet-configmap
    6. labels:
    7. app_name: mychart
    8. app_version: "0.1.0"
    9. data:
    10. myvalue: "Hello World"
    11. drink: "coffee"
    12. food: "pizza"
    13. app_name: mychart
    14. app_version: "0.1.0"

    注意两处的app_version缩进都不对,为啥?因为被替换的模板中文本是左对齐的。由于template是一个行为,不是方法,无法将 template调用的输出传给其他方法,数据只是简单地按行插入。

    为了处理这个问题,Helm提供了一个template的可选项,可以将模板内容导入当前管道,然后传递给管道中的其他方法。

    下面这个示例,使用indent正确地缩进了mychart.app模板:

    1. apiVersion: v1
    2. kind: ConfigMap
    3. metadata:
    4. name: {{ .Release.Name }}-configmap
    5. labels:
    6. {{ include "mychart.app" . | indent 4 }}
    7. data:
    8. myvalue: "Hello World"
    9. {{- range $key, $val := .Values.favorite }}
    10. {{ $key }}: {{ $val | quote }}
    11. {{- end }}
    12. {{ include "mychart.app" . | indent 2 }}

    现在生成的YAML每一部分都可以正确缩进了:

    1. # Source: mychart/templates/configmap.yaml
    2. apiVersion: v1
    3. kind: ConfigMap
    4. metadata:
    5. name: edgy-mole-configmap
    6. labels:
    7. app_name: mychart
    8. app_version: "0.1.0"
    9. data:
    10. myvalue: "Hello World"
    11. drink: "coffee"
    12. food: "pizza"
    13. app_name: mychart
    14. app_version: "0.1.0"