1. Helm 概念
Helm 中几个个非常重要的概念:
Repository
Chart
Release
Value
Template
Namespace
1.1 Repository
存放安装包的仓库,可以使用 helm env
查看
[root@kube-master ~]# helm env
HELM_BIN="helm"
HELM_BURST_LIMIT="100"
HELM_CACHE_HOME="/root/.cache/helm"
HELM_CONFIG_HOME="/root/.config/helm"
HELM_DATA_HOME="/root/.local/share/helm"
HELM_DEBUG="false"
HELM_KUBEAPISERVER=""
HELM_KUBEASGROUPS=""
HELM_KUBEASUSER=""
HELM_KUBECAFILE=""
HELM_KUBECONTEXT=""
HELM_KUBEINSECURE_SKIP_TLS_VERIFY="false"
HELM_KUBETLS_SERVER_NAME=""
HELM_KUBETOKEN=""
HELM_MAX_HISTORY="10"
HELM_NAMESPACE="default"
HELM_PLUGINS="/root/.local/share/helm/plugins"
HELM_QPS="0.00"
HELM_REGISTRY_CONFIG="/root/.config/helm/registry/config.json"
HELM_REPOSITORY_CACHE="/root/.cache/helm/repository"
HELM_REPOSITORY_CONFIG="/root/.config/helm/repositories.yaml"
[root@kube-master ~]# helm env
HELM_BIN="helm"
HELM_BURST_LIMIT="100"
HELM_CACHE_HOME="/root/.cache/helm"
HELM_CONFIG_HOME="/root/.config/helm"
HELM_DATA_HOME="/root/.local/share/helm"
HELM_DEBUG="false"
HELM_KUBEAPISERVER=""
HELM_KUBEASGROUPS=""
HELM_KUBEASUSER=""
HELM_KUBECAFILE=""
HELM_KUBECONTEXT=""
HELM_KUBEINSECURE_SKIP_TLS_VERIFY="false"
HELM_KUBETLS_SERVER_NAME=""
HELM_KUBETOKEN=""
HELM_MAX_HISTORY="10"
HELM_NAMESPACE="default"
HELM_PLUGINS="/root/.local/share/helm/plugins"
HELM_QPS="0.00"
HELM_REGISTRY_CONFIG="/root/.config/helm/registry/config.json"
HELM_REPOSITORY_CACHE="/root/.cache/helm/repository"
HELM_REPOSITORY_CONFIG="/root/.config/helm/repositories.yaml"
1.2 Chart
Helm 的应用包,采用tgz格式。类似于 Yum 的 RPM 包,其包含了一组定义 Kubernetes 资源相关的 YAML 文件,也称为应用 Chart
1.3 Release
Release
就是安装到 Kubernetes 中的 Chart 实例,每个 Chart 可以在集群中安装多次,每安装一次,就会产生一个 Release
1.4 Value
Helm Chart的参数,用于配置Kubernetes对象
1.5 Template
使用Go模板语言生成Kubernetes对象的定义文件
1.6 Namespace
Kubernetes中用于隔离资源的逻辑分区
1.4 部署流程
- 开发者首先创建并编辑chart的配置;
- 接着打包并发布至Helm的仓库(Repository);
- 当管理员使用helm命令安装时,相关的依赖会从仓库下载;
- 接着helm会根据下载的配置部署资源至k8s;
2. Helm语法
2.0 与2相比变化点
1.HelmCLI个别名字更名
helm delete 更名为 helm uninstall
helm inspect 更名为 helm show
helm fetch 更名为 helm pull
helm delete 更名为 helm uninstall
helm inspect 更名为 helm show
helm fetch 更名为 helm pull
2.移除了用于本地临时搭建Chart Repository的helm serve命令
3.自动创建名称空间
在不存在的命名空间中创建发行版时,Helm2创建了命名空间。Helm3遵循其他Kubernetes对象的行为,如果命名空间不存在则返回错误.
4.不再需要requirements.yaml,依赖关系是直接在chart.yaml中定义.
2.1 模版注释
Chart.yaml
apiVersion: chart API 版本 (必需) #必须有
name: chart名称 (必需) # 必须有
version: 语义化2 版本(必需) # 必须有
kubeVersion: 兼容Kubernetes版本的语义化版本(可选)
description: 一句话对这个项目的描述(可选)
type: chart类型 (可选)
keywords:
- 关于项目的一组关键字(可选)
home: 项目home页面的URL (可选)
sources:
- 项目源码的URL列表(可选)
dependencies: # chart 必要条件列表 (可选)
- name: chart名称 (nginx)
version: chart版本 ("1.2.3")
repository: (可选)仓库URL ("https://example.com/charts") 或别名 ("@repo-name")
condition: (可选) 解析为布尔值的yaml路径,用于启用/禁用chart (e.g. subchart1.enabled )
tags: # (可选)
- 用于一次启用/禁用 一组chart的tag
import-values: # (可选)
- ImportValue 保存源值到导入父键的映射。每项可以是字符串或者一对子/父列表项
alias: (可选) chart中使用的别名。当你要多次添加相同的chart时会很有用
maintainers: # (可选) # 可能用到
- name: 维护者名字 (每个维护者都需要)
email: 维护者邮箱 (每个维护者可选)
url: 维护者URL (每个维护者可选)
icon: 用做icon的SVG或PNG图片URL (可选)
appVersion: 包含的应用版本(可选)。不需要是语义化,建议使用引号
deprecated: 不被推荐的chart (可选,布尔值)
annotations:
example: 按名称输入的批注列表 (可选).
apiVersion: chart API 版本 (必需) #必须有
name: chart名称 (必需) # 必须有
version: 语义化2 版本(必需) # 必须有
kubeVersion: 兼容Kubernetes版本的语义化版本(可选)
description: 一句话对这个项目的描述(可选)
type: chart类型 (可选)
keywords:
- 关于项目的一组关键字(可选)
home: 项目home页面的URL (可选)
sources:
- 项目源码的URL列表(可选)
dependencies: # chart 必要条件列表 (可选)
- name: chart名称 (nginx)
version: chart版本 ("1.2.3")
repository: (可选)仓库URL ("https://example.com/charts") 或别名 ("@repo-name")
condition: (可选) 解析为布尔值的yaml路径,用于启用/禁用chart (e.g. subchart1.enabled )
tags: # (可选)
- 用于一次启用/禁用 一组chart的tag
import-values: # (可选)
- ImportValue 保存源值到导入父键的映射。每项可以是字符串或者一对子/父列表项
alias: (可选) chart中使用的别名。当你要多次添加相同的chart时会很有用
maintainers: # (可选) # 可能用到
- name: 维护者名字 (每个维护者都需要)
email: 维护者邮箱 (每个维护者可选)
url: 维护者URL (每个维护者可选)
icon: 用做icon的SVG或PNG图片URL (可选)
appVersion: 包含的应用版本(可选)。不需要是语义化,建议使用引号
deprecated: 不被推荐的chart (可选,布尔值)
annotations:
example: 按名称输入的批注列表 (可选).
values.yaml
templates
templates/ 目录下的文件被视为使用 Go 模板语言的动态 YAML 模板,并带有一些附加功能。
YAML 模板可防止配置重复,并允许您在开发、暂存和生产环境中安装相同的图表。
2.2 内置对象
Release 对象
Values 对象
Chart 对象
Capabilities 对象
Template 对象
内置 | 作用 |
---|---|
Release.Name | release名称 |
Release.Namespace | release命名空间 |
Release.Revision | release版本号。起始是1,每次升级或回滚都会自增1 |
Release.Service | release 服务的名称 |
2.3 内置函数
upper
将整个字符串转换为大写:
upper "hello"
upper "hello"
lower
将整个字符串转换为小写:
lower "HELLO"
lower "HELLO"
title
转换为标题大小写:
title "hello world"
title "hello world"
returns Hello World
2.4 流程控制
2.4.0 运算符
运算符 | 作用 |
---|---|
eq | 等于(equal to) |
ne | 不等于(not equal to) |
lt | 小于(less than) |
le | 小于等于(less than or equal to) |
gt | 大于(greater than) |
ge | 大于等于(greater than or equal to) |
2.4.1 if/else 条件块
- 语法
如果值为如下情况,则if条件评估为 false
一个布尔型的假
一个数字零
一个空的字符串
一个 nil(空或 null)
一个空的集合(map,slice,tuple,dict,array)
一个布尔型的假
一个数字零
一个空的字符串
一个 nil(空或 null)
一个空的集合(map,slice,tuple,dict,array)
例子:
上面配置是基于同一个pod 部署两个容器,一个是应用一个是nginx 的配置的通用模板。 也就是说默认是关闭nginx 配置的,如果启用可以通过--set nginx.enabled=true 方式。
💡 说明
当模板引擎运行时,它会删除 中的内容,但保留其余空白,如下方式删除空行
花括号里面的中横行“-” 的用途是清除helm 渲染后的yml 文件里面的空行,由于像if 判断这些语句不是k8s里面yml 文件里的配置信息,所以渲染后的yml 文件中if 等语句的位置会产生空行,所以加上“-”就会清除空行
谨慎使用:如: -}} ,这将会把如上的结果生成在同一行,因为它消除了两边的换行符.
2.4.2 with 指定范围
- 定义
with作用域,用来控制变量范围。回想一下,.
是对 当前作用域 的引用。因此 .Values
就是告诉模板在当前作用域查找Values
对象。
with
语句块内不能再 .Release.Name
对象,否则报错
- 语法
{{ with PIPELINE }}
# restricted scope
{{ end }}
{{ with PIPELINE }}
# restricted scope
{{ end }}
- 案例
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}}
注意,现在我们可以引用 .drink 和 .food 无需对其进行限定。这是因为该 with 声明设置 . 为指向 .Values.favorite。在 {{end}} 后 . 复位其先前的范围。
但是请注意!在受限范围内,此时将无法从父范围访问其他对象。例如,下面会报错:
{{- with .Values.favorite}}
drink: {{.drink | default "tea" | quote}}
food: {{.food | upper | quote}}
release: {{.Release.Name}} #此处报错
{{- end}}
解决方式:
{{- $releaseName := .Release.Name -}} #在with区域外定义要引入的值,在里面再通过变量引入
{{- with .Values.favorite}}
drink: {{.drink | default "tea" | quote}}
food: {{.food | upper | quote}}
release: {{ $releaseName }} #通过定义的变量引入
{{- end}}
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}}
注意,现在我们可以引用 .drink 和 .food 无需对其进行限定。这是因为该 with 声明设置 . 为指向 .Values.favorite。在 {{end}} 后 . 复位其先前的范围。
但是请注意!在受限范围内,此时将无法从父范围访问其他对象。例如,下面会报错:
{{- with .Values.favorite}}
drink: {{.drink | default "tea" | quote}}
food: {{.food | upper | quote}}
release: {{.Release.Name}} #此处报错
{{- end}}
解决方式:
{{- $releaseName := .Release.Name -}} #在with区域外定义要引入的值,在里面再通过变量引入
{{- with .Values.favorite}}
drink: {{.drink | default "tea" | quote}}
food: {{.food | upper | quote}}
release: {{ $releaseName }} #通过定义的变量引入
{{- end}}
2.4.3 range 循环块
- 定义
Helm 的模板语言中,遍历集合的方式是使用 range 操作(类似for)
- 语法
{{ range PIPELINE }}
# restricted scope
{{ end }}
{{ range PIPELINE }}
# restricted scope
{{ end }}
- 案例
cat values.yaml
favorite:
drink: coffee
food: pizza
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
将这个列表打印到我们的 ConfigMap 中:
cat templates/configmap.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}}
{{- end}}
toppings: |- #因为此处要引入的是多行字符串,所以通过"|-"方式
{{- range .Values.pizzaToppings}}
- {{. | title | quote}} #"." 就是循环的对象中的单个元素,由此可见range也具有with 一样的功能,可以限定范围。
{{- end}}
循环自建的元祖
有时能快速在模板中创建一个列表,然后遍历该列表是很有用的。Helm 模板有一个功能可以使这个变得简单:tuple。
sizes: |-
{{- range tuple "small" "medium" "large"}}
- {{.}}
{{- end}}
{{/*输出如下*/}}
sizes: |-
- small
- medium
- large
用于类似列表的对象以同时捕获索引和值:
toppings: |-
{{- range $index, $topping := .Values.pizzaToppings}}
{{$index}}: {{ $topping }}
{{- end}}
注意,range 首先是变量,然后是赋值运算符,然后是列表。这将分配整数索引(从零开始)给 $index,值给 $topping。运行它将产生:
对于同时具有键和值的数据结构,我们可以使用 range 来获得两者
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite}}
{{$key}}: {{ $val | quote }}
{{- end}}
#favorite 定义在 values.yaml中,如上文所示。
cat values.yaml
favorite:
drink: coffee
food: pizza
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
将这个列表打印到我们的 ConfigMap 中:
cat templates/configmap.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}}
{{- end}}
toppings: |- #因为此处要引入的是多行字符串,所以通过"|-"方式
{{- range .Values.pizzaToppings}}
- {{. | title | quote}} #"." 就是循环的对象中的单个元素,由此可见range也具有with 一样的功能,可以限定范围。
{{- end}}
循环自建的元祖
有时能快速在模板中创建一个列表,然后遍历该列表是很有用的。Helm 模板有一个功能可以使这个变得简单:tuple。
sizes: |-
{{- range tuple "small" "medium" "large"}}
- {{.}}
{{- end}}
{{/*输出如下*/}}
sizes: |-
- small
- medium
- large
用于类似列表的对象以同时捕获索引和值:
toppings: |-
{{- range $index, $topping := .Values.pizzaToppings}}
{{$index}}: {{ $topping }}
{{- end}}
注意,range 首先是变量,然后是赋值运算符,然后是列表。这将分配整数索引(从零开始)给 $index,值给 $topping。运行它将产生:
对于同时具有键和值的数据结构,我们可以使用 range 来获得两者
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Release.Name}}-configmap
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite}}
{{$key}}: {{ $val | quote }}
{{- end}}
#favorite 定义在 values.yaml中,如上文所示。
2.4.4 变量
- 定义
Helm模板中,变量是对另一个对象的命名引用。遵循$name
变量的格式且指定了一个特殊的赋值运算符::=
变量通常不是 “全局” 的。它们的范围是它们所在的块
- 案例
这段代码会失败
{{- with .Values.favorite}}
drink: {{.drink | default "tea" | quote}}
food: {{.food | upper | quote}}
release: {{.Release.Name}}
{{- end}}
Release.Name 不在该 with 块中限制的范围内。解决范围问题的一种方法是将对象分配给可以在不考虑当前范围的情况下访问的变量。
{{- with .Values.favorite}}
drink: {{.drink | default "tea" | quote}}
food: {{.food | upper | quote}}
release: {{.Release.Name}}
{{- end}}
Release.Name 不在该 with 块中限制的范围内。解决范围问题的一种方法是将对象分配给可以在不考虑当前范围的情况下访问的变量。
使用变量重写上面的 Release.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 变量仍然指向发布名称。因为变量不受with 范围限制。
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 变量仍然指向发布名称。因为变量不受with 范围限制。
2.4.5 命名模板
❌ 注意
在命名模板时要注意一个重要的细节:模板名称是全局的。如果声明两个具有相同名称的模板,则最后加载一个模板是起作用的模板。
define定义命名模板
可以在/templates/*.yaml 文件中定义命名模板也可以在/templates/_helpers.tpl 定义
template/include 使用命名模板
include与template 区别
include 是可以替代template 的更高级的用法,可以增加缩进
功能。
例如创建一个configmap 它的lable 和 data 下面的数据缩进是不同的,lable 缩进在metadata 下面,所以lable 下面的数据是相比于顶格是缩进四个空格。data 本身就是顶格写的,它下面的数据缩进两个空格即可
define 定义的命名模板内容如果同时引入到lable 和 data 下面,那么相同的内容但是缩进不同,如果直接用template 引入那么就会原模原样引入不缩进而是顶格引入到yaml 中
这样不符合configmap 的定义语法可能不报错但是不会生效这两部分内容,
即使在模本文件中缩进引用{{- template "mychart.labels" . }},依然不生效,
所以在引入过程中需要增加空格所以include 可以替代template 增加空格,语法为:{{- include "mychart.labels" .| indent 4 }} 数字4表示缩进几个空格
这样不符合configmap 的定义语法可能不报错但是不会生效这两部分内容,
即使在模本文件中缩进引用{{- template "mychart.labels" . }},依然不生效,
所以在引入过程中需要增加空格所以include 可以替代template 增加空格,语法为:{{- include "mychart.labels" .| indent 4 }} 数字4表示缩进几个空格
- 案例
cat _helpers.tpl
{{/* 生成基本的资源配置 */}}
{{- define "resources" }}
{{- with .Values.resources}}
limits:
cpu: {{ .limits.cpu }}
memory: {{ .limits.memory }}
requests:
cpu: {{ .requests.cpu }}
memory: {{ .requests.memory }}
{{- end }}
{{- end }}
cat templates/deployment.yaml
...
- name: {{ .Release.Name }}-nginx
image: {{ .Values.image.repository }}/nginx-qa:{{ .Values.image.tagn }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 80
protocol: TCP
resources:
{{- include "resources" .| indent 10 }} #在此处通过命名模板名字引用
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d
...
cat _helpers.tpl
{{/* 生成基本的资源配置 */}}
{{- define "resources" }}
{{- with .Values.resources}}
limits:
cpu: {{ .limits.cpu }}
memory: {{ .limits.memory }}
requests:
cpu: {{ .requests.cpu }}
memory: {{ .requests.memory }}
{{- end }}
{{- end }}
cat templates/deployment.yaml
...
- name: {{ .Release.Name }}-nginx
image: {{ .Values.image.repository }}/nginx-qa:{{ .Values.image.tagn }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: 80
protocol: TCP
resources:
{{- include "resources" .| indent 10 }} #在此处通过命名模板名字引用
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d
...
2.4.6 模板中"-"
示例一
...
name: {{- Values.name -}} #话括号里面的横线左边的会删除括号左边的空格,右边的会删除右边的空格,在此处一般不加这俩“-”
...
示例二
...
{{-if Values.nginx.enable }} #此处作用就是删除if 和 end 逻辑语句所占的空行,因为这些流程控制语句不会渲染成实际的yaml 配置,默认保留空行再yaml 文件中,所以需要用“-”删除
...
{{- end }}
...
示例一
...
name: {{- Values.name -}} #话括号里面的横线左边的会删除括号左边的空格,右边的会删除右边的空格,在此处一般不加这俩“-”
...
示例二
...
{{-if Values.nginx.enable }} #此处作用就是删除if 和 end 逻辑语句所占的空行,因为这些流程控制语句不会渲染成实际的yaml 配置,默认保留空行再yaml 文件中,所以需要用“-”删除
...
{{- end }}
...
2.4.7 调试
Helm也提供了--dry-run --debug
调试参数,帮助验证模板正确性。在执行helm install时候带上这两个参数就可以把对应的values值和渲染的资源清单打印出来,而不会真正的去部署一个release
helm install web --dry-run /root/mychart
helm install web --dry-run /root/mychart
2.5 set格式和限制
--set
选项使用0或多个 name/value 对
1、最简单的name/value对
--set name=value
等价于
name: value
--set name=value
等价于
name: value
2、多个name/value对
--set a=b,c=d
等价于
a: b
c: d
--set a=b,c=d
等价于
a: b
c: d
3、更复杂的表达式
--set outer.inner=value
等价于
outer:
inner: value
--set outer.inner=value
等价于
outer:
inner: value
4、列表的表达
--set name={a, b, c}
等价于
name:
- a
- b
- c
--set name={a, b, c}
等价于
name:
- a
- b
- c
5、name/key可以设置为null或者空数组
--set name=[],a=null
由
name:
- a
- b
- c
a: b
变为了
name: []
a: null
--set name=[],a=null
由
name:
- a
- b
- c
a: b
变为了
name: []
a: null
6、使用数组下标的语法来访问列表中的元素
从 2.5.0 版本开始支持
--set servers[0].port=80
等价于
servers:
- port: 80
--set servers[0].port=80
等价于
servers:
- port: 80
7、多个值得数组下标语法
--set servers[0].port=80,servers[0].host=example
等价于
servers:
- port: 80
host: example
--set servers[0].port=80,servers[0].host=example
等价于
servers:
- port: 80
host: example
8、特殊字符转义
--set name=value1\,value2
等价于
name: "value1,value2"
--set name=value1\,value2
等价于
name: "value1,value2"
9、转义.
--set nodeSelector."kubernetes\.io/role"=master
等价于
nodeSelector:
kubernetes.io/role: master
--set nodeSelector."kubernetes\.io/role"=master
等价于
nodeSelector:
kubernetes.io/role: master