入门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,否则调试过程也会非常困难。

相关推荐
颜酱17 分钟前
# 02 | 搭骨架:用 LangGraph 编排 12 步工作流(思路)
前端·人工智能·后端
颜酱18 分钟前
02 | 搭骨架:用 LangGraph 编排 12 步工作流
前端·人工智能·后端
嘉伟桑1 小时前
Python调用电价API返回JSON示例:分时电价、现货电价和字段解析
后端
武子康2 小时前
Shippy:确定性工具、会话级 Sandbox 与 Live-Data Eval(4 类收敛 + 7 步实现方案 + 6 类评测指标)
前端·人工智能·后端
我叫黑大帅2 小时前
我为什么单一消费者的场景下,要用 Redis List 当消息队列?
redis·后端·面试
AskHarries2 小时前
文件上传系统
后端
止语Lab3 小时前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活3 小时前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
程序员天天困3 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn3 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端