Helm就是一个kubernetes的对象文件管理工具,有的介绍说Helm类似于python的Pip,是包管理工具。我们可以从使用的角度看看Helm的功能,进而明白它是什么工具。
一般我们在部署kubernetes的时候,会定义Deployment、Service、ConfigMap等对象,使用kubectl apply -f
的命令,但是,如果你想重新发布,修改,甚至支持多租户(多个环境),修改起来很麻烦。虽然可以使用kubectl edit
等命令,但是,我们更加倾向于可以一次性更新我们的服务,并且,最好支持我们做版本管理功能。
所以,Helm就诞生了,帮助我们管理kubenetes的yaml对象文件,借助go的template语法,将kubernetes对象模板化,并允许自己定义填充模板的值,做到一套模板多个发布,并支持版本管理。使用Helm命令行工具,就可以直接管理kubernetes服务——Helm install / uninstall
直接管理整个服务(包含deployment、service、configMap、pvc等等对象)。
本篇文章主要从Helm模板文件的语法讲解,介绍常用的语法与一般的使用环境。
这里贴一下Helm文档的链接:
https://helm.sh/docs/chart_template_guide/getting_started/
下划线开头的就是子模版,格式:{{- define “模板名字” -}} 模板内容 {{- end -}}
{{- define "nginx.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
# 若 .Values.nameOverride 为空,则默认值为 .Chart.Name
模板引用
{{ include “模板名字” 作用域 }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "nginx.fullname" . }}
可以在_help.tpl中编写子模板,完成镜像image字段的拼接。
```yaml
#_helo.tpl中定义规则
{{- define "get-image" -}}
{{- $registryName := .image.registry -}}
{{- $repositoryName := .image.repository -}}
{{- $tag := .image.tag | toString -}}
{{- if .global}}
{{- if .global.imageRegistry }}
{{- $registryName := .global.imageRegistry -}}
{{- end -}}
{{- end -}}
{{- if $registryName }}
{{- printf "%s/%s:%s" $registryName $repositoryName $tag -}}
{{- else -}}
{{- printf "%s"%s" $repositoryName $tag -}}
{{- end -}}
{{- end -}}
# get image nginx
{{- define "my-nginx.image" -}}
{{ include "get-image" (dict "image" .Values.myNginx "global" .Values.global)}}
{{- end -}}
```
使用时,将registry、repository、tag在values.yaml的定义完成,然后在template文件中使用。
```yaml
# my-nginx deployment.yaml
# ···
image: {{ template "my-nginx.image" .}}
# ···
```
预定义对象可以直接在模板中使用。
Release: 代表Release对象,属性包含:Release.Name、Release.Namespace、Release.Revision等
Values: 表示 values.yaml 文件数据
Chart: 表示 Chart.yaml 数据
Files: 用于访问 chart 中非标准文件
Capabilities: 用于获取 k8s 集群的一些信息
- Capabilities.KubeVersion.Major:K8s的主版本
Template: 表示当前被执行的模板
- Name:表示模板名,如:mychart/templates/mytemplate.yaml
- BasePath:表示路径,如:mychart/templates
# Release
其代表一次应用发布,下面是Release对象包含的属性字段:
Release.Name - release的名字,一般通过Chart.yaml定义,或者通过helm命令在安装应用的时候指定。
Release.Time - release安装时间
Release.Namespace - k8s名字空间
Release.Revision - release版本号,是一个递增值,每次更新都会加一
Release.IsUpgrade - true代表,当前release是一次更新.
Release.IsInstall - true代表,当前release是一次安装
Release.Service - The service that is rendering the present template. On Helm, this is always Helm.
# Values对象
values 对象的值有四个来源:
1. chart 包中的 values.yaml 文件
2. 父 chart 包的 values.yaml 文件
3. 使用 helm install 或者 helm upgrade 的 -f 或者 --values 参数传入的自定义的 yaml 文件
4. 通过 --set 参数传入的值
. 表示全局作用域,可以引用全局对象,并且,可以嵌套链式调用
# Values
# 这里引用了全局作用域下的Values对象中的key属性。
{{ .Values.key }}
Values代表的就是values.yaml定义的参数,通过.Values可以引用任意参数。
例子:
{{ .Values.replicaCount }}
# 引用嵌套对象例子,跟引用json嵌套对象类似
{{ .Values.image.repository }}
自定义模板变量
可以自定义变量然后在下面使用。
# 变量名以$开始命名, 赋值运算符是 := (冒号+等号)
{{- $relname := .Release.Name -}}
#引用自定义变量:
#不需要 . 引用
{{ $relname }}
wiht 关键字
with 关键字可以控制变量的作用域,主要就是用来修改 . 作用域的,默认 . 代表全局作用域,with 语句可以修改 . 的含义
# 例子:
# .Values.favorite 是一个 object 类型
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }} # 相当于.Values.favorite.drink
food: {{ .food | upper | quote }}
{{- end }}
应用场景
存在某些相关的模板变量上:
#例子:
#.Values.favorite是一个object类型
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }} #相当于.Values.favorite.drink
food: {{ .food | upper | quote }}
{{- end }}
range 关键字
range用于循环遍历数组类型
range主要用于循环遍历数组类型。
语法1:
# 遍历map类型,用于遍历键值对象
# 变量key代表对象的属性名,val代表属性值
{{- range key,val := 键值对象 }}
{{ $key }}: {{ $val | quote }}
{{- end}}
语法2:
{{- range 数组 }}
{{ . | title | quote }} # . (点),引用数组元素值。
{{- end }}
例子:
# values.yaml定义
# map类型
favorite:
drink: coffee
food: pizza
# 数组类型
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
# map类型遍历例子:
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end}}
# 数组类型遍历例子:
{{- range .Values.pizzaToppings}}
{{ . | quote }}
{{- end}}
include 函数
include是一个函数,一般输出结果可以传给其他函数
include 是一个函数,所以他的输出结果是可以传给其他函数的
# 例子1:
env:
{{- include "xiaomage" . }}
# 结果:
env:
- name: name
value: xiaomage
- name: age
value: secret
- name: favourite
value: "Cloud Native DevSecOps"
- name: wechat
value: majinghe11
# 例子2:
env:
{{- include "xiaomage" . | indent 8}}
# 结果:
env:
- name: name
value: xiaomage
- name: age
value: secret
- name: favourite
value: "Cloud Native DevSecOps"
- name: wechat
value: majinghe11
管道Piplines
管道的概念与liunx中管道命令类似,都是将一系列模板命令串联起来,并进行一系列转化。使用管道命令针对数据格式转换十分方便。
k8s: {{ quote .Values.course.k8s }} # 加双引号
k8s: {{ .Values.course.k8s | upper | quote }} # 大写字符串加双引号
k8s: {{ .Values.course.k8s | repeat 3 | quote }} # 加双引号和重复3次字符串
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | quote }}
food: {{ .Values.favorite.food | upper | quote }}
```
lookup 函数
lookup对象可以用于查找运行的集群中查找资源。查找 apiVersion, kind, namespace, name -> 资源或者资源列表。
# 对应关系
kubectl get pod mypod -n mynamespace ==》 lookup "v1" "Pod" "mynamespace" "mypod"
kubectl get pods -n mynamespace ==》 lookup "v1" "Pod" "mynamespace" ""
kubectl get pods --all-namespaces ==》 lookup "v1" "Pod" "" ""
kubectl get namespace mynamespace ==》 lookup "v1" "Namespace" "" "mynamespace"
kubectl get namespaces ==》 lookup "v1" "Namespace" "" ""
(lookup "v1" "Namespace" "" "mynamespace").metadata.annotations
{{ range $index, $service := (lookup "v1" "Service" "mynamespace" "").items }}
{{/* do something with each service */}}
{{ end }}
运算符函数
and, coalesce, default, empty, eq, fail, ge, gt, le, lt, ne, not, and or。
and .Arg1 .Arg2
eq .Arg1 .Arg2 # (Arg1 == Arg2)
ne .Arg1 .Arg2 # (Arg1 != Arg2)
le .Arg1 .Arg2 # (Arg1 <= Arg2)
lt .Arg1 .Arg2 # (Arg1 < Arg2)
gt .Arg1 .Arg2 # (Arg1 > Arg2)
ge .Arg1 .Arg2 # (Arg1 >= Arg2)
default "foo" .Bar
empty .Foo # true false
fail "Please accept the end user license agreement" # 无条件地返回带有指定文本的空 string 或者 error。
coalesce 0 1 2 # 获取一个列表并返回第一个非空值 # 用于扫描多个对象或者多个值
coalesce .name .parent.name "Matt"
#上述示例会优先检查 .name 是否为空。如果不是,就返回值。如果 是 空, 继续检查.parent.name。 最终,如果 .name 和 .parent.name 都是空,就会返回 Matt。
ternary "foo" "bar" true # 就像if判断一样, 如果第三个值返回的是true,则返回第一个值(foo),反之返回第二个值(bar)
true | ternary "foo" "bar"
# 上述示例会输出foo
字符串处理函数
Helm 包含了字符串函数:
abbrev, abbrevboth, camelcase, cat, contains, hasPrefix, hasSuffix, indent, initials, kebabcase, lower, nindent, nospace, plural, print, printf, println, quote, randAlpha, randAlphaNum, randAscii, randNumeric, repeat, replace, shuffle, snakecase, squote, substr, swapcase, title, trim, trimAll, trimPrefix, trimSuffix, trunc, untitle, upper, wrap, 和 wrapWith。
具体使用:
https://helm.sh/zh/docs/chart_template_guide/function_list/
if/else 针对流程控制的方法。
{{ if PIPELINE }}
# Do something
{{ else if OTHER PIPELINE }}
# Do something else
{{ else }}
# Default case
{{ end }}
# 判断条件,如果值为以下几种情况,管道的结果为 false:
1. 一个布尔类型的假
2. 一个数字零
3. 一个空的字符串
4. 一个 nil(空或null)
5. 一个空的集合(map, slice, tuple, dict, array)
除了上面的这些情况外,其他所有的条件都为真。
常用的模板语法就是这些,并且,在模板中做好各种判空操作,多层数据选择,是可以十分灵活定义kubernetes对象的。