入门helm chart语法

Helm是Kubernetes的包管理工具,类似Linux系统的yum,apt-get,macOs的homebrew。使用Helm template可以方便我们部署和管理自己的应用。本篇将基于Helm3.12.0,通过几个例子快速入门Helm 语法。

一、 helm chart 结构

学习helm语法之前先了解一下helmchart结构,helm通过chart描述一个应用,安装了helm以后就可以通过命令下面这个命令创建一个chart了。

helm create mychart

这个基本的chart的结构是这样的:

bash 复制代码
mychart
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml
  • templates/ 目录下的.yaml文件是模板文件。当Helm需要生成chart的时,会渲染该目录下的模板文件,将渲染结果发送给kubernetes。
  • values.yaml 模板的配置文件,用来向模板传递数据。用户可以在helm install 或者 helm upgrade可以指定新的值来覆盖默认值。
  • Chart.yaml 文件保存chart的基本描述信息,这些描述信息也可以在模板中被引用。
  • charts/目录 可以 包含其他的chart(称之为 子chart)。
  • _helpers.tpl用于保存一些可以在该chart中复用的模板。
  • NOTES.txt install的描述信息

二、 内置对象

内置对象中最常用的就是Values和Files,通过它们读取配置信息和访问外部文件。

Values

values 对象的值有四个来源

  • 根目录的values.yaml 文件
  • chart目录中的values.yaml 文件
  • 使用 helm install 或者 helm upgrade 的 -f 或者 --values 参数传入的自定义的 yaml 文件
  • 通过 --set 参数传入的值

Files

在chart中提供访问所有的非特殊文件的对象。你不能使用它访问Template对象,只能访问其他文件

  • Files.Get 通过文件名获取文件的方法。 (.Files.Get config.ini)
  • Files.GetBytes 用字节数组代替字符串获取文件内容的方法。 对图片之类的文件很有用
  • Files.Glob 用给定的shell glob模式匹配文件名返回文件列表的方法
  • Files.Lines 逐行读取文件内容的方法。迭代文件中每一行时很有用
  • Files.AsSecrets 使用Base 64编码字符串返回文件体的方法
  • Files.AsConfig 使用YAML格式返回文件体的方法
yaml 复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "demo.fullname" . }}
data:
{{ (.Files.Glob "files/confd/**").AsConfig |indent 2 }}

内置的值都是以大写字母开始。 这是符合Go的命名惯例。当你创建自己的名称时,可以按照团队约定自由设置。 就像很多你在 Artifact Hub 中看到的chart,其团队选择使用首字母小写将本地名称与内置对象区分开

see: glob package - github.com/gobwas/glob - Go Packages

Capabilities

提供关于Kubernetes集群支持功能的信息

Template

包含当前被执行的当前模板信息

Chart

Chart.yaml文件内容。 Chart.yaml里的所有数据在这里都可以可访问的。比如 {{ .Chart.Name }}-{{ .Chart.Version }} 会打印出 mychart-0.1.0

Release

Release对象描述了版本发布本身。

三、values.yaml

模板的配置文件,用来向模板传递数据。用户可以在helm install 或者 helm upgrade可以指定新的值来覆盖默认值。

values.yaml

yaml 复制代码
favoriteDrink: coffee

templates/configmap.yaml

yaml 复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favoriteDrink }}
yaml 复制代码
$ helm install geared-marsupi ./mychart --dry-run --debug
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: geared-marsupi-configmap
data:
  myvalue: "Hello World"
  drink: coffee

四、 常用函数

管道符 "|"

模板语言其中一个强大功能是 管道 概念。借鉴UNIX中的概念,下面两行是等效的表示读取food数据,并且加上双引号

yaml 复制代码
{{ .Values.favorite.food | quote }} {{ quote .Values.favorite.food }}

default 函数

default是模板中频繁使用的一个函数,这个函数允许你在模板中指定一个默认值,当给定值没有取值是返回这个默认值。

语法: default DEFAULT_VALUE GIVEN_VALUE

这个例子中读取food值,如果food是

{{ $food := default "apple" .Values.favorite.food }}

indent

helm描述kubernetes资源文件用indent和nindent处理缩进,缩进错误chart就会解析失败。

  • indent 2 $lots_of_text 表示在当前模板位置向后缩进两位输出字符串,注意是当前模板的位置开始,即模板的位置也是有效的
  • nindent 2 $lots_of_text 表示在当前位置增加一个空行,从新行的开始位置缩进两位,输出字符串,注意此时模板的位置已经无效了

toYaml

改函数可以将列表,切片,数组,字典或对象转换成已缩进的yaml,但最常用的功能是该函数可以从任意源拷贝yaml块。

下面这个例子中我们用toYaml从values.yaml读取内容。

values.yaml

yaml 复制代码
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: nvidia-gpu
          operator: Exists

模版片段

yaml 复制代码
      {{- if .Values.affinity }}
      affinity:
        {{- toYaml .Values.affinity | nindent 8 }}
      {{- end }}

渲染结果:

yaml 复制代码
        affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: nvidia-gpu
                operator: Exists

除了上面介绍的几个函数,helm 还提供了很多函数,我们可以参考官方文档,在此就不介绍了。下面是官方文档中提供的函数的分类:

  • Cryptographic and Security 处理加密的函数
  • Date 时间数据处理函数
  • Dictionaries 字典函数
  • Encoding 编码解码函数
  • File Path Helm模板函数没有访问文件系统的权限,提供了遵循文件路径规范的函数。
  • Kubernetes and Chart Helm 包含了用于 Kubernetes的函数
  • Logic and Flow Control 逻辑函数
  • Lists 提供了一个简单的list类型,包含任意顺序的列表。类似于数组或切片,但列表是被设计用于不可变数据类型。
  • Math 除非另外指定,否则所有的math函数都是操作 int64 的值。
  • Network Helm提供了一个网络函数:getHostByName,它接收一个域名返回IP地址。
  • Reflection 反射工具函数,用于高级模板开发
  • Regular Expressions 正则表达式函数
  • Semantic Versions 语义版本函数,用于分析比较语义版本
  • String 字符串函数
  • Type Conversion 类型转换函数
  • URL URL解析组装函数
  • UUID helm 提供了一个uuidv4函数,用于生成UUID v4 通用唯一ID

五、流控制

if else

ifelse的结构是这样的,中间的else if和 else是可选的。

yaml 复制代码
{{ if PIPELINE }}
  # Do something
{{ else if OTHER PIPELINE }}
  # Do something else
{{ else }}
  # Default case
{{ end }}

chart语法中借鉴了golang语言的0值的概念。如果是以下值时,PIPELINE会被设置为 false,除此之外都是true:

  • 布尔false
  • 数字0
  • 空字符串
  • nil (空或null)
  • 空集合(map, slice, tuple, dict, array)

控制空格

我们先看一个例子,在下面的例子中我们看到渲染的结果有个空行,虽然合法,但看起来丑。

他是怎么形成的呢,原因是yaml认为空白是有意义的,而helm模版只移除了 {{ 和 }} 里面的内容,剩下下的空格完全保持原样。

yaml 复制代码
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 复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  name: telling-chimp-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"

  mug: "true"

那helm如何管理空格呢,模板声明的大括号语法可以通过特殊的字符修改,并通知模板引擎取消空格。

{{- (包括添加的横杠和空格)表示向左删除空白, 而 -}}表示右边的空格应该被去掉。 一定注意空格就是换行,对于上面的例子我们值需要在if前增加 - 就可以去掉前面的空格。就像这样:

yaml 复制代码
  {{- if eq .Values.favorite.drink "coffee" }}
  mug: "true"
  {{- end }}

with

with允许你为特定对象设定当前作用域(.)。

helm 中 .是对当前作用域的引用。因此 .Values就是告诉模板在当前作用域查找Values对象。

with的作用是修改作用域,在下面的例子中,我们通过with 修改配置映射中的.的作用域指向.Values.favorite,然后.就表示 .Values.favorite,而with后面的块只有在 PIPELINE 的值不为空时才会执行。

所以有时候用with就可以省略if。

yaml 复制代码
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 }}
  release: {{ $.Release.Name }}
  {{- end }}

在上面例子中.Release不在作用域范围内,所以增加了$,表示根作用域下的Release对象,否则会报错。

range

helm中只有一种循环 range,提供类似 for each的循环。range可以遍历list,tuple,数字

遍历values.yaml中的list:

yaml 复制代码
favorite:
  drink: coffee
  food: pizza
pizzaToppings:
  - mushrooms
  - cheese
  - peppers
  - onions
yaml 复制代码
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 }}
  toppings: |-
    {{- range $.Values.pizzaToppings }}
    - {{ . | title | quote }}
    {{- end }}    
  {{- end }}

遍历tuple

yaml 复制代码
sizes: |-
    {{- range tuple "small" "medium" "large" }}
    - {{ . }}
    {{- end }} 

遍历数字

这里用到了两个函数,until 和 untilStep

  • until 构建一个整数范围。until 5 返回一个列表: [0, 1, 2, 3, 4]
  • untilStep 类似until, untilStep 生成一个可计数的整型列表。但允许你定义开始,结束和步长
yaml 复制代码
kind: Service
apiVersion: v1
metadata:
  name: ngrinder-controller-service
  namespace: qa-tools
spec:
  selector:
    app.kubernetes.io/name: ngrinder-controller
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      name: controller
    {{- range $_,$p := until 5 }}
    - port: {{ $p }}
      targetPort: http
      protocol: TCP
      name: http
    {{- end }}
    {{- range $_,$e := untilStep 12000 12009 1 }}
    - protocol: TCP
      port: {{ $e }}
      targetPort: {{ $e }}
      name: p{{ $e }}
  {{- end }}

六、命名模板

在编写命名模板细节之前,先了解一下文件的命名惯例,templates/中的大多数yaml文件被视为包含Kubernetes清单,命名以下划线(_)开始的文件则假定 没有 包含清单内容。这些文件不会渲染为Kubernetes对象定义,但在其他chart模板中都可用。_help.tpl就是保存模版的默认位置。

define操作允许我们在模板文件中创建一个命名模板,在下面例子中在_help.tpl文件中用 define 定义了一个模版 mychart.labels,然后通过 template 引用。

yaml 复制代码
{{- define "mychart.labels" }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
{{- end }}
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 }}

在这个模版中我们无法用 . 访问任何内容,解决这个问题我们只需要在template调用末尾传入 . 然后就可以通过.Values或.Chart等对象引用数据。但一定要是顶层范围。

由于template是一个行为,不是方法,无法将 template输出内容传给其他方法,数据只是简单地按行插入。

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

yaml 复制代码
{{ include "mychart.app" . | indent 2 }}

最后

编写完 chart可以通过命令 helm template . --debug渲染,检查是否有问题。另外写好一个helm chart除了学习helm 语法,更重要的是对kubernetes资源的了解,只有了解了每个资源的功能和参数的作用,才有可能编写出合理的chart,否则调试过程也会非常困难。

相关推荐
ac-er888841 分钟前
如何在Flask中实现国际化和本地化
后端·python·flask
Adolf_199343 分钟前
Flask-WTF的使用
后端·python·flask
林太白4 小时前
❤Node09-用户信息token认证
数据库·后端·mysql·node.js
骆晨学长5 小时前
基于Springboot的助学金管理系统设计与实现
java·spring boot·后端
蒙娜丽宁5 小时前
深入理解Go语言中的接口定义与使用
开发语言·后端·golang·go
AskHarries5 小时前
java使用ByteBuffer进行多文件合并和拆分
java·后端
不染_是非6 小时前
Django学习实战篇六(适合略有基础的新手小白学习)(从0开发项目)
后端·python·学习·django
代码对我眨眼睛6 小时前
springboot从分层到解耦
spring boot·后端
The Straggling Crow6 小时前
go 战略
开发语言·后端·golang
ai安歌6 小时前
【JavaWeb】利用IDEA2024+tomcat10配置web6.0版本搭建JavaWeb开发项目
java·开发语言·后端·tomcat·web·intellij idea