heml3 charts 语法函数相关

Chart 文件结构

一个 Chart 包由以下几个配置文件组成:
wordpress/
  Chart.yaml          # Yaml文件,用于描述 Chart 的基本信息,包括名称版本等
  LICENSE             # [可选] 文本格式的协议
  README.md           # [可选] 应用介绍、使用说明
  requirements.yaml   # [可选] 用于存放当前 Chart 依赖的其它 Chart 的说明文件
  values.yaml         # Chart 的默认值配置文件
  charts/             # [可选] 该目录中放置当前 Chart 依赖的其它 Chart
  templates/          # [可选] 部署文件模版目录,模版填入 values.yaml 中相应值,生成最终的 
kubernetes 配置文件
   ├── NOTES.txt        [可选] 使用指南
   ├── _helpers.tpl     下划线开头的文件,可以被其他模板引用
   ├── deployment.yaml  创建k8s资源deployment的yaml文件
   ├── ingress.yaml     创建k8s资源ingress的yaml文件
   └── service.yaml     创建k8s资源service的yaml文件
   ├── .....

Chart.yaml 文件

apiVersion: [必须] Chart API 版本,可用值 v1
name: [必须] Chart 名称
version: [必须] 版本,遵循 [SemVer 2 标准](https://semver.org/)
kubeVersion: [可选] 兼容的 Kubernetes 版本,遵循 [SemVer 2 标准](https://semver.org/)
description: [可选] 一句话的应用描述
keywords:
  - [可选] 应用关键字列表
home: [可选] 应用主页 URL
sources:
  - [可选] 当前应用下载地址列表
maintainers: [可选]
  - name: [必须] name 
    email: [可选] email
    url: [可选] url
engine: [可选] 模板引擎,默认值是 gotpl
icon: [可选] SVG 或者 PNG 格式的图片地址
appVersion: [可选] 应用版本
deprecated: [可选] boolean 类型,是否不建议使用
tillerVersion: [可选] Chart 需要的 Tiller 版本,遵循 [SemVer 2 标准](https://semver.org/),需要 ">2.0.0"

Requirements.yaml 文件和 Charts 目录

Chart支持两种方式表示依赖关系,可以写入 requirements.yaml 文件动态链接[推荐],也可以将依赖的 Chart 放入 charts 目录手动管理。

requirements.yaml 文件样例:

dependencies:
  - name: apache
    version: 1.2.3
    repository: http://example.com/charts
  - name: mysql
    version: 3.2.1
    repository: http://another.example.com/charts

    name:Chart 名称
    version:Chart 版本
    repository: Chart 仓库 URL 地址

有了 requirements.yaml 文件,可以运行 helm dependency update,依赖的 Chart 会被自动的下载到 charts 目录下。
Values.yaml 文件和 Templates 目录

values.yaml 文件中记录了模板中引用的默认值。 templates 目录中存放了 Kubernetes 部署文件的模版,遵循 Go template 语法

templates 中模板文件样例:

apiVersion: v1
kind: ReplicationController
metadata:
  name: deis-database
  namespace: deis
  labels:
    app.kubernetes.io/managed-by: deis
spec:
  replicas: 1
  selector:
    app.kubernetes.io/name: deis-database
  template:
    metadata:
      labels:
        app.kubernetes.io/name: deis-database
    spec:
      serviceAccount: deis-database
      containers:
        - name: deis-database
          image: {{.Values.imageRegistry}}/postgres:{{.Values.dockerTag}}
          imagePullPolicy: {{.Values.pullPolicy}}
          ports:
            - containerPort: 5432
          env:
            - name: DATABASE_STORAGE
              value: {{default "minio" .Values.storage}}

上述样例是一个 Kubernetes 中 replication controller 的模板文件定义,其中引用了以下几个值(一般定义在 values.yaml 中)

    imageRegistry:Docker 映像仓库
    dockerTag: Docker 映像标签
    pullPolicy: 下载映像策略
    storage: 存储后端,默认值是 "minio"

values.yaml 文件样例:

imageRegistry: "quay.io/deis"
dockerTag: "latest"
pullPolicy: "Always"
storage: "s3"

 开始

1 简单示例

1.1 生成案例结构 mycahrt

$ helm create mychart
Creating mychart

1.2 helm 客户端会自动的为我们创建些文件:

mychart
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── ingress.yaml
│   └── service.yaml
└── values.yaml

2 第一个模板

2.1 删除所有文件,我们自己手动,有助于深入理解

 rm -rf mychart/templates/*.*

删除掉 Helm 生成的模板文件,我们自己来实现一个模板。

我们的第一个模板是创建一个 ConfigMap。创建一个 mychart/templates/configmap.yaml文件,并写入如下内容:

apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"

注意:Template 目录下的文件没有严格的命名规范。但我们推荐用 .yaml 的后缀表示 YAML 文件,用 .tpl 表示帮助文件。

现在我们来部署它:

$ helm install wubo ./mychart
NAME: full-coral
LAST DEPLOYED: Tue Nov  09 17:36:01 2020
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME                DATA      AGE
mychart-configmap   1         1m

我们可以来查看下部署信息

$ helm get manifest wubo
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"

helm get manifest 这条命令可以通过 release 名来打印其相关信息。release的名字此时就是wubo

现在,删除掉刚刚发布的 release:helm delete wubo

3 赋值示例

3.1内置对象

  • Release:用来描述 release 本身
    • Release.Name
    • Release.Time
    • Release.Namespace
    • Release.Service:值总是 Tiller 注:在 Helm 2 中,Tiller 是作为一个 Deployment 部署在 kube-system 命名空间中,很多情况下,我们会为 Tiller 准备一个 ServiceAccount ,这个 ServiceAccount 通常拥有集群的所有权限。 用户可以使用本地 Helm 命令,自由地连接到 Tiller 中并通过 Tiller 创建、修改、删除任意命名空间下的任意资源。 在 Helm 3 中,Tiller 被移除了。新的 Helm 客户端会像 kubectl 命令一样,读取本地的 kubeconfig 文件,使用我们在 kubeconfig 中预先定义好的权限来进行一系列操作。
    • Release.Revision:release 版本号。从 1 开始,每次执行 helm upgrade ,数加 1
    • Release.IsUpgrade:本次操作是否为升级
    • Release.IsInstall:本次操作是否为安装
  • Values:
  • Chart:Chart.yaml里的内容
  • Files:
    • File.Get 通过名字获取文件(.Files.Get config.ini
    • File.getBytes 以字节流的方式获取,在获取类型图片时比较有用
  • Capabilities:
  • Template:

3.2 Values Files

前面讲了内置对像 Values,它的值有四个来源:

  • values.yaml 文件
  • 如果这是个子 chart,其父 chart 的 Values.yaml 文件
  • 在 helm install 或 helm upgrade 时,通过 -f 指定的文件
  • 通过 --set 指定的参数( 例:helm install --set foo=bar ./mychart )

优先级从上到下依次增加,即 --set 最高。

现在让我们来编辑 mychart/values.yaml,删除默认值,只写一个参数:

cat values.yaml

favoriteDrink:coffee

在模板中使用刚刚写的参数:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favoriteDrink}}

注意最后一行,我们通过访问 Values 属性的方式 {{ .Values.favoriteDrink}} 来获取 favoriteDrink 值。

来看下渲染的结果:

$ helm install wubo --dry-run --debug ./mychart
SERVER: "localhost:44134"
CHART PATH: /Users/mattbutcher/Code/Go/src/k8s.io/helm/_scratch/mychart
NAME: wubo
TARGET NAMESPACE:   default
CHART:  mychart 0.1.0
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: geared-marsupi-configmap
data:
  myvalue: "Hello World"
  drink: coffee

还可以通过 --set 覆盖掉这个值:

helm install wubo --dry-run --debug --set favoriteDrink=slurm ./mychart
SERVER: "localhost:44134"
CHART PATH: /Users/mattbutcher/Code/Go/src/k8s.io/helm/_scratch/mychart
NAME:   wubo
TARGET NAMESPACE:   default
CHART:  mychart 0.1.0
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: solid-vulture-configmap
data:
  myvalue: "Hello World"
  drink: slurm

由于 --set 的优先级高于 values.yaml,所有我们的模板最终输出为 drink: slurm

Values 文件还可以包含结构内容。

favorite:
  drink: coffee
  food: pizza

现在我们需要修改下模板:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink }}
  food: {{ .Values.favorite.food }}

 看下效果2中方式

1 此种方式可以拿到Release相关的内置属性值

root@localhost:~/go/test1/mychart # helm install wubo  -f values.yaml --dry-run --debug .          
install.go:172: [debug] Original chart version: ""
install.go:189: [debug] CHART PATH: /root/go/test1/mychart

NAME: wubo
LAST DEPLOYED: Wed Sep 23 17:07:52 2020
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
favorite:
  drink: coffee
  food: pizza

COMPUTED VALUES:
favorite:
  drink: coffee
  food: pizza

HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: wubo-configmap
data:
  myvalue: "Hello World"
  drink: coffee
  food: pizza

2 此种方式只是根据values和temp模板生成最终可供k8s的kubectl create -f 执行的一个yaml文件

root@localhost:~/go/test1/mychart # helm template . -s templates/configmap.yaml -f values.yaml 
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: RELEASE-NAME-configmap
data:
  myvalue: "Hello World"
  drink: coffee
  food: pizza

3.3. 删除默认Key

如果你想从默认值中删除一个key,你可以通过传 null 值,这样 Helm 在合并时就会删除这个 key。

举个例子, 名为 Drupal 的 chart 中配置的有存活检测。下面是它的默认设置:

livenessProbe:
  httpGet:
    path: /user/login
    port: http
  initialDelaySeconds: 120
如果你要使用 exec 替换 httpGet,可以通过 --set livenessProbe.exec.command=[cat,docroot/CHANGELOG.txt],Helm 会合并默认值和传进去的值,结果如下:
livenessProbe:
  httpGet:
    path: /user/login
    port: http
  exec:
    command:
    - cat
    - docroot/CHANGELOG.txt
  initialDelaySeconds: 120

这时,k8s 就会出错,因为你定义了两个 liveness handler。要解决这个问题,你可以通过给 livenessProbe.httpGet传个 null 值来删除它:

helm install stable/drupal --set image=my-registry/drupal:0.1.0 --set livenessProbe.exec.command=[cat,docroot/CHANGELOG.txt] --set livenessProbe.httpGet=null

4 模板函数和Pipelines(管道)

Helm包含许多模板函数,可以在模板中使用它们。常用函数:

https://helm.sh/docs/chart_template_guide/function_list/

https://helm.sh/docs/chart_template_guide/builtin_objects/

https://blog.csdn.net/miss1181248983/article/details/108285276

让我们从一个练习开始:当我们往 .Values 里注入一个字符串时,应当用引号将它们括起来,在模板中可以直接使用 quote 函数来实现:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ quote .Values.favorite.drink }}
  food: {{ quote .Values.favorite.food }}

模板函数的语法如下:functionName arg1 arg2...。在上面的小例子中, quote .Values.favorite.drink, 使用了 quote 函数并传递了一个参数。

4.1. Pipelines(管道)

通过管道可以在一行里干多件事,我们使用 pipeline 重写上面的例子:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | quote }}
  food: {{ .Values.favorite.food | quote }}

通过 pipeline(管道),我们可以链式的调用多个函数:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | quote }}
  food: {{ .Values.favorite.food | upper | quote }}

4.2 使用 Default 函数

这个函数允许你指定一个默认值:

drink: {{ .Values.favorite.drink | default "tea" | quote }}

4.3. OPERATORS ARE FUNCTIONS

操作符是按照函数的方式实现的,返回一个布尔值。使用 eq, ne, lt, gt, and, or, not时,要将它们放到句子的最前面,后面跟上对应的参数。多个操作符一起使用时,可以用小括号包起来。

{{/* include the body of this if statement when the variable .Values.fooString exists and is set to "foo" */}}
{{ if and .Values.fooString (eq .Values.fooString "foo") }}
    {{ ... }}
{{ end }}

意思就是Values.fooString不能为空且Values.fooString的值等于foo

{{/* do not include the body of this if statement because unset variables evaluate to false and .Values.setVariable was negated with the not function. */}}
{{ if or .Values.anUnsetVariable (not .Values.aSetVariable) }}
   {{ ... }}
{{ end }}

4.4控制流

Helm 的模板语言提供下面几种控制结构:

  • if / else
  • with
  • range 提供类型 for each 的循环

另外,还提供了几种方式来声明和使用命名模板:

  • define
  • template
  • block

这节只讨论 ifwith, 和 range。其它的会在之后的 “Named Templates” 那节介绍。

4.4.1 . IF / ELSE

基本结构如下

{{ if PIPELINE }}
  # Do something
{{ else if OTHER PIPELINE }}
  # Do something else
{{ else }}
  # Default case
{{ end }}

注意这里我们用 pipelines 面不是 values,是为了表明这个控制结构是可以运行完全的 pipeline 的,而不仅仅只能放个值。

下面情况其值会被认为是 false:

  1. bool 型的 false
  2. 数字 0
  3. 空字符串
  4. nil
  5. 空集合(map, slice, tuple, dict, array)

让我们来修改下 ConfigMap。当 drink 是 coffee时,增加一个设置:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
  {{ if and .Values.favorite.drink (eq .Values.favorite.drink "coffee") }}mug: true{{ end }}

注意mug: true前后不能有空格

注意, .Values.favorite.drink 最好是判断下是否为空,否则当它和 coffee作比较时会报错。最后的输出就变成: 

root@localhost:~/go/test1/mychart # helm template . -s templates/configmap.yaml -f values.yaml
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: RELEASE-NAME-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  mug: tru

root@localhost:~/go/test1/mychart # helm install wubo  -f values.yaml --dry-run --debug .                                                                                                                                         1 ↵
install.go:172: [debug] Original chart version: ""
install.go:189: [debug] CHART PATH: /root/go/test1/mychart

NAME: wubo
LAST DEPLOYED: Wed Sep 23 17:18:12 2020
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
favorite:
  drink: coffee
  food: pizza

COMPUTED VALUES:
favorite:
  drink: coffee
  food: pizza

HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: wubo-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  mug: true

4.4.2. 空白管理

空白的使用在模板中是受限制的。下面把之前的代码格式修改下,使它更易阅读:

kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
  {{if eq .Values.favorite.drink "coffee"}}
    mug: true
  {{end}}

它看起来不错,但当真正运行时,会报错:

$ helm install --dry-run --debug ./mychart
SERVER: "localhost:44134"
CHART PATH: /Users/mattbutcher/Code/Go/src/k8s.io/helm/_scratch/mychart
Error: YAML parse error on mychart/templates/configmap.yaml: error converting YAML to JSON: yaml: line 9: did not find expected key

这就是因为空格导致的:

这是翻译之后的最终数据 发现最后一样有问题 多2个空格
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: eyewitness-elk-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
    mug: true

mug的嵌套位置不正确。让我们简单的修改下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
  {{if eq .Values.favorite.drink "coffee"}}
  mug: true
  {{end}}

再次运行,发现生成的 YAML 格式正确了,但是有点丑: 

root@localhost:~/go/test1/mychart # helm install wubo  -f values.yaml --dry-run --debug .                                                                                                                                        20 ↵
install.go:172: [debug] Original chart version: ""
install.go:189: [debug] CHART PATH: /root/go/test1/mychart

NAME: wubo
LAST DEPLOYED: Wed Sep 23 17:20:22 2020
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
favorite:
  drink: coffee
  food: pizza

COMPUTED VALUES:
favorite:
  drink: coffee
  food: pizza

HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: wubo-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  
  mug: true

root@localhost:~/go/test1/mychart # helm template . -s templates/configmap.yaml -f values.yaml
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: RELEASE-NAME-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  
  mug: true

注意,YAML 中有行是空的。

{{ - 表示去掉左边或前的空格 }}

{{  表示去掉右边或后的空格  -}}

{{ - 表示去掉左边或前和右边或后的空格  -}}

好好理解一下 案例如下

root@localhost:~/go/test1/mychart # cat templates/configmap.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  namespace: {{ .Release.Namespace }}
  time: {{ .Release.Time }}
data:
  myvalue: "Hello World"
  {{ with .Values.favorite }}
  {{ if and $.Values.favorite.drink (eq $.Values.favorite.drink "coffee") }}
  mug: true
  {{ end }}
  name: wubo
  {{ end }}
  age: 12
  {{ if and .Values.favorite.drink (eq .Values.favorite.drink "coffee") }}
  mug: true
  {{ end }}
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}

执行效果 

root@localhost:~/go/test1/mychart # helm template . -s templates/configmap.yaml -f values.yaml                                                                                                                                   20 ↵
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: RELEASE-NAME-configmap
  namespace: default
  time: 
data:
  myvalue: "Hello World"
  
  
  mug: true
  
  name: wubo
  
  age: 12
  
  mug: true
  
  drink: "coffee"
  food: "PIZZA"

改成

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  namespace: {{ .Release.Namespace }}
  time: {{ .Release.Time }}
data:
  myvalue: "Hello World"
  {{- with .Values.favorite }}
  {{- if and $.Values.favorite.drink (eq $.Values.favorite.drink "coffee") }}
  mug: true
  {{- end }}
  name: wubo
  {{- end }}
  age: 12
  {{- if and .Values.favorite.drink (eq .Values.favorite.drink "coffee") }}
  mug: true
  {{- end }}
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }

效果 

root@localhost:~/go/test1/mychart # helm template . -s templates/configmap.yaml -f values.yaml                                                                                                                                   20 ↵
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: RELEASE-NAME-configmap
  namespace: default
  time: 
data:
  myvalue: "Hello World"
  mug: true
  name: wubo
  age: 12
  mug: true
  drink: "coffee"
  food: "PIZZA"

分析内容如下: 

myvalue: "Hello World"
  {{- with .Values.favorite }}
  {{- if and $.Values.favorite.drink (eq $.Values.favorite.drink "coffee") }}
  mug: true
  {{- end }}
  name: wubo
  {{- end }}
  age: 12
  {{- if and .Values.favorite.drink (eq .Values.favorite.drink "coffee") }}
  mug: true
  {{- end }}
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
 

解释:

myvalue: "Hello World"和 mug: true之间会有2个空行,因为有两个流程操作{{ with }} 和 {{ if }}

mug: true和 name: wubo之间有一个空行,因为有一个操作{{ end }}

name: wubo和  age: 12之间也有一个操作同上

age: 12和mug: true之间也有一个同上

mug: true和drink: {{ .Values.favorite.drink | default "tea" | quote }}之间也有一个

drink: {{ .Values.favorite.drink | default "tea" | quote }}和 food: {{ .Values.favorite.food | upper | quote }}之间没有

然后就是怎么去除空行

  myvalue: "Hello World"
  {{- with .Values.favorite }}  "-" 写在前代表的是删除上面或左边的所有空行,但是右边或后面还有一个空行没有处理呢
  {{- if and $.Values.favorite.drink (eq $.Values.favorite.drink "coffee") }} 同理如上
  mug: true

上面这个还可以这样写

  myvalue: "Hello World"
  {{- with .Values.favorite -}}  "-" 写在前和后代表的是删除上面或左边和后面或右边的空行,就是把前后所有的空行都删除了,注意是所有的空行,不是一个空行
  {{ if and $.Values.favorite.drink (eq $.Values.favorite.drink "coffee") }} 此时{{- if }} 也是可以的,因为他的前面或左边确实有空行。{{- with -}} 共同删除空行没毛病。但是{{ if -}} 后面加个”-" 就会报错了,因为后面就是 mug: true没有空行了。
  mug: true

4.5. 修改作用域

通过 . 可以引用当前的作用域。 .Values 告诉模板在当前作用域上查找 Values

可以通过 with 来调整作用域

{{ with PIPELINE }}
  # restricted scope
{{ end }}
with 允许你把当前作用域(.)指到一个特定的对象上。举个例子,将 . 指到 .Values.favorites上:
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  {{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
  {{- end }}

警告,在这个特定的作用域中,你不能够访问其父领域的对象。下面的例子,访问会出错:

{{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
  wubo: {{ .Values.favorit.food  }} 此处获取不到
  release: {{ .Release.Name }} 也获取不到
{{- end }}

此时有两中解决办法,定义变量和全局获取

1种解决办法.由于下方的with语句引入相对命令空间,无法通过.Release引入,提前定义relname变量
2种解决办法.者可以使用$符号,引入全局命名空间
{{- $relname := .Values.favorit.food }}
{{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
  wubo: {{ $relname }} 
  # 或者可以使用$符号,引入全局命名空间
  wubo: {{$.Values.favorit.food}}
  release: {{ $.Release.Name }}
{{- end }}

4.6. range 操作

Helm 可以通过 range 操作符来迭代集合。

在 values.yaml 中增加列表:


favorite:
  drink: coffee
  food: pizza
pizzaToppings:
  - mushrooms
  - cheese
  - peppers
  - onions

现在修改下 ConfigMap 的模板,来打印出上面的列表:

root@localhost:~/go/test1/mychart # helm template . -s templates/configmap.yaml -f values.yaml                                                                                                                                   20 ↵
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: RELEASE-NAME-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  toppings: |-
    - "Mushrooms"
    - "Cheese"
    - "Peppers"
    - "Onions"

和 with一样,range也可以设置作用域,所以在这里,. 表示的是 pizzaToppings这个作用域。我们能把 . 直接传递给管道使用 {{ . | title | quote }}

运行上面的模板,结果如下:

root@localhost:~/go/test1/mychart # helm template . -s templates/configmap.yaml -f values.yaml                                                                                                                                   20 ↵
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: RELEASE-NAME-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  toppings: |-
    - "Mushrooms"
    - "Cheese"
    - "Peppers"
    - "Onions"

toppings: |- 表示这是一个多行的字符串

4.7 变量

在模板里,变量较少被使用。但通过使用变量,可以使 with 和 range 得到更好的使用。

这是之前的一个例子,会报错:

 {{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
  release: {{ .Release.Name }}
  {{- end }}

在 Helm 模板里,一个变量是对一个对象的引用。格式是 $name。使用 := 进行赋值。我们可以通过变量重写上面的代码:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  {{- $relname := .Release.Name -}}
  {{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
  release: {{ $relname }}
  {{- end }}

在使用 with 之前,我们 $relname := .Release.Name。现在在 with 的作用域里,$relname 仍然指向 .Release.name

 

5 Named Templates

本节我们学习如何定义一个命名模板,并在别处使用它。

你要注意的是:模板的名字是全局性的。当你定义了两个相同名字的模板时,最后加载的那个将被使用。

推荐的做法是在定义模板名字时,加上 chart:{{define "mychart.labels"}}

5.1. 特殊文件

在开始具体写模板前,有些命令惯例值得提醒下:

  • template/中的大部分文件可以认为是 k8s 的资源
  • NOTES.txt文件除外
  • 有下划线的除外

5.2. 使用 define 和 template

define 允许我们在模板文件中创建一个命名模板:

{{ define "MY.NAME" }}
  # body of template here
{{ end }}

举个例子

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

现在我们把它嵌套到之前的 ConfigMap 上,然后通过 template来引入:

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 }}

最终,经过渲染,文件会变成:

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

习惯上 Helm 把这些模板放在一个特殊的文件里,通常是 _helpers.tpl。让我们来移到下它吧:

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

按惯例,define 函数应该有个简单的使用说明,用 {{/* ... */}}括起来。

虽然是在 _helpers.tpl 中定义的,但仍然可以在 configmap.yaml 中使用:

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 }}

再次提醒下,命名模板是全局性的。如果定义了两个相同名字的模板,则后面定义的那个生效。

5.3. 给模板设定作用域

5.4. include 函数

如下,我们定义了个模板:

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

现在,我们想把它同时入到 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 的缩进是不对的。i

通过使用 include 和nindent 来实现正确的缩进,template语句的升级版本include,template是语句无法在后面接管道符来对引入变量做定义,
include实现了此功能.

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

6 模板中访问文件

在之前的章节中我们学会了创建和访问命令模板,让我们可以方便的在一个模板中导入另一个模板。但是有些时我们要导入一个文件而不需要经过模板的渲染。

Helm 通过 .Files 对象提供了访问文件的功能。在开始例子之前,有些点需要我们注意:

  • 在 Helm 中可以增加额处文件,它们也会被发给 Tiller。但要注意,由于 k8s 存储大小的限制, Charts 的大小不能超过 1M。
  • 因为安全的原因,有些文件是不能被 .Files 访问到的
    • templates/ 中的文件不能被访问
    • 在 .helmignore 中的文件不能被访问

6. 1. Basic Example

我们直接在 mychar/ 下创建三个文件
config1.toml

message = Hello from config 1

config2.toml

message = Hello from config 2

config3.toml

message = Hello from config 3

我们知道它位的名字,所以我们可以使用 range 循环的将它的们内容注入到 ConfigMap 中

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  {{- $files := .Files }}
  {{- range tuple "config1.toml" "config2.toml" "config3.toml" }}
  {{ . }}: |-
    {{ $files.Get . }}
  {{- end }}

通过运行它,我们能够得到: 

# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: quieting-giraf-configmap
data:
  config1.toml: |-
    message = Hello from config 1

  config2.toml: |-
    message = This is config 2

  config3.toml: |-
    message = Goodbye from config 3

6.2. Path Helpers

6.3. Glob Patterns

6.4. Encoding

使用base-64加密

apiVersion: v1
kind: Secret
metadata:
  name: {{ .Release.Name }}-secret
type: Opaque
data:
  token: |-
    {{ .Files.Get "config1.toml" | b64enc }}
# Source: mychart/templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: lucky-turkey-secret
type: Opaque
data:
  token: |-
    bWVzc2FnZSA9IEhlbGxvIGZyb20gY29uZmlnIDEK

 ======================================================

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  labels:
    {{- include  "mychart.app" . | nindent 4 }}
data:
  myvalue: "Hello World"
  {{- range $key, $val := .Values.favorite }}
  {{ $key }}: {{ $val | quote }}
  {{- end }}
  {{- include "mychart.app" . | nindent 2 }}
  {{- $files := .Files }}
  {{- range tuple "config1.toml"  "config2.toml"  "config3.toml" }}
  {{ . }}: |-
    {{ $files.Get . | b64enc }}
  {{- end }}
root@localhost:~/go/test1/mychart # helm template . -s templates/configmap.yaml                                                                                                                                                  20 ↵
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: RELEASE-NAME-configmap
  labels:
    app_name: mychart
    app_version: "0.1.0+"
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "pizza"
  app_name: mychart
  app_version: "0.1.0+"
  config1.toml: |-
    bWVzc2FnZSA9IEhlbGxvIGZyb20gY29uZmlnIDEK
  config2.toml: |-
    bWVzc2FnZSA9IEhlbGxvIGZyb20gY29uZmlnIDIK
  config3.toml: |-
    bWVzc2FnZSA9IEhlbGxvIGZyb20gY29uZmlnIDMK

7. Lines

创建 NOTES.Txt 文件

这节,来介绍下如何给你的 chart 增加说明。在 helm install 或者 helm upgrade 的最后,会打印一些对用户有用的信息,而这些信息是可以高度定制化的。

创建 templates/NOTES.txt 文件。它是个普通文件,但是可以像模板那样来使用,能够在文件中使用模板函数和亦是。

现在来创建个简单的 NOTES.txt 文件:

Thank you for installing {{ .Chart.Name }}.

Your release is named {{ .Release.Name }}.

To learn more about the release, try wubo:

  $ helm status {{ .Release.Name }}
  $ helm get {{ .Release.Name }}
root@localhost:~/go/test1/mychart # helm install wubo1 --dry-run --debug .                                                                                                                                                       20 ↵
install.go:172: [debug] Original chart version: ""
install.go:189: [debug] CHART PATH: /root/go/test1/mychart

NAME: wubo1
LAST DEPLOYED: Thu Sep 24 11:35:34 2020
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
favorite:
  drink: coffee
  food: pizza
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions

HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: wubo1-configmap
  labels:
    app_name: mychart
    app_version: "0.1.0+"
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "pizza"
  app_name: mychart
  app_version: "0.1.0+"
  config1.toml: |-
    bWVzc2FnZSA9IEhlbGxvIGZyb20gY29uZmlnIDEK
  config2.toml: |-
    bWVzc2FnZSA9IEhlbGxvIGZyb20gY29uZmlnIDIK
  config3.toml: |-
    bWVzc2FnZSA9IEhlbGxvIGZyb20gY29uZmlnIDMK

NOTES:
Thank you for installing mychart.

Your release is named wubo1.

To learn more about the release, try wubo:

  $ helm status wubo1
  $ helm get wubo1

NOTES.txt 不是必须的,但强烈推荐你创建一个。

8 Subcharts and Global Values

之前我们一直在使用一个 chart,但 chart 之间是可以存在依赖关系的,称之为 subchart,它们可以有自己的值和模板。这节我们将会创建一个 subchart,来看看它是如何获取值的。

在开始前,有几个关于 subchart 的知识点需要大家知道:

  1. subchart 是可以独立部署的,故而它不能明确的依赖 parent chart。
  2. subchart 不能获取 parent chart 的值。
  3. parent chart 可以覆盖 subchart 的值。
  4. Helm 有一个 global values 的概念,可以被所有 chart 获取。

8 1. Creating A Subchart

$ cd mychart/charts
$ helm create mysubchart
Creating mysubchart
$ rm -rf mysubchart/templates/*.*

8.2. ADDING VALUES AND A TEMPLATE TO THE SUBCHART

Debugging Templates

几种 debug 的方式:

  • helm lint:检查你的 chart 是否有可以优化的地方
  • helm install --dry-run --debug:让 Tiller 渲染模板,并返回其生成的 yaml 文件
  • helm get manifest:查看 k8s 部署的是什么样的模板

附录:YAML 技巧

前面全部关注在模板的书写上,现在让我们来看看 YAML 的格式。

1. Scalars and Collections

两种类型的集合,map和队列

map:
  one: 1
  two: 2
  three: 3

sequence:
  - one
  - two
  - three

2. Yaml 中的类型

数字类型

count: 1
size: 2.34

如果它们被引号引起来,就变成了字符串

count: "1" # <-- string, not int
size: '2.34' # <-- string, not float

布尔类型也是如此:

isGood: true   # bool
answer: "true" # string

空值由 null 表示,而不是 nil

需要注意的是,port: "80" 是符合 YAML 语法的,当通过模板引擎传递给 k8s 时,如果 k8s 要求此字段是 int 类型,那么会报错。

可以通过 Yaml 的标记,对类型进行强制的转换:

coffee: "yes, please"
age: !!str 21
port: !!int "80"

上面的代码,!!str 告诉分析器,age 是的 String 类型, port 是个 int 类型。

3. Yaml 中的字符串

5. Yaml 是 Json 的超集

因为 Yaml 是 Json 的超集,所以任何符合 JSON 格式的文档都符合 YAML 的规范。

{
  "coffee": "yes, please",
  "coffees": [
    "Latte", "Cappuccino", "Espresso"
  ]
}

上面内容的另一种表示方式:

coffee: yes, please
coffees:
- Latte
- Cappuccino
- Espresso

两者还能混合书写:

coffee: "yes, please"
coffees: [ "Latte", "Cappuccino", "Espresso"]

上面三种方式表示的内容是一致的。

这表示 values.yaml 里可以包含 JSON 格式的数据。但 Helm 不允许文件后缀名为 .json

 

10 Yaml Anchor

附录: Go 语言数据类型和模板

因为 Helm 的模板编辑是基于 Go 语言的,而 Go 本身就是一种强类型的语言,所以模板中的变量是有类型的。

  • string
  • bool
  • int
  • float64
  • a byte slice
  • struct
  • a slice
  • a string-kyed map

获取变量类型最简单的方式是 printf "%t"。也可以使用 typeof 和 kindf函数来获取。

https://blog.csdn.net/qq_24095941/article/details/88126207#NamedTemplates

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值