在helm中除了此前的那些内置函数和定义的一些valumes的值替换,这些对象和控制语句,还有一些管道之外,仍然提供了变量。
大多数编程语言中,都有变量。如,在golang中以及groovy中都提到了全局变量和局部变量。 他们的作用域范围不同
- 全局变量
全局变量,顾名思义,所有都可以使用
- 局部变量
在某一块的代码内被使用,而代码块作用域外无法使用
有了这些的支撑,更好理解变量的出现以及使用的问题
变量
而变量在helm中的用的和大多数编程语言不一样,helm中的变量能够用来简化代码。这通常配合with已经range。
但是在helm中,定义一个变量的方式却非常有意思,似乎结合了shell和golang。
$mark := .Release.Name
示例1 变量
仍然存在一个局部和全局的意思,比如:with
{{ with .Values.mydata -}}
{{ if eq .status "isok" -}}
status: ok
{{- else if eq .names "marksugar" -}}
namestatus: "true"
{{ else -}}
defaultstaus: true
{{- end }}
{{- end }}
在如上代码块中是不能使用Release.Name
的,解决这个问题的办法就是将对象分配给with的作用域之外。
上面提到,定义一个变量的方式和shell,golang类似,随即定义一个Release.Name
{{ $linuxea := .Release.Name -}}
并将塔引入到with
必须将变量定于在with之外,在with中的if之外
{{ $linuxea := .Release.Name -}}
{{ with .Values.mydata -}}
releasename: {{ $linuxea }}
{{ if eq .status "isok" -}}
status: ok
{{- else if eq .names "marksugar" -}}
namestatus: "true"
{{ else -}}
defaultstaus: true
{{- end }}
{{- end }}
如下
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cmp
labels:
app: {{ .Release.Name }}-cmp
data:
name: {{ .Values.mydata.names | default "supper" }}
test: {{ .Values.mydata.data | upper | repeat 5 }}
{{ $linuxea := .Release.Name -}}
{{ with .Values.mydata -}}
releasename: {{ $linuxea }}
{{ if eq .status "isok" -}}
status: ok
{{- else if eq .names "marksugar" -}}
namestatus: "true"
{{ else -}}
defaultstaus: true
{{- end }}
{{- end }}
{{ indent 2 "test: ok" }}
mylist: |-
{{- range .Values.mylist }}
- {{ . | title | quote }}
{{- end }}
执行
PS H:k8s-1.20.2helm> helm template linuxea.com .liunuxea
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: linuxea.com-cmp
labels:
app: linuxea.com-cmp
data:
name: marksugar
test: HI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COM
releasename: linuxea.com
status: ok
test: ok
mylist: |-
- "Mark"
- "Edwin"
- "Sean"
示例2 range
在golang里面,range是可以将索引和值进行打印的了,而在helm中也可以这样使用。如下
mylist: |-
{{- range $index,$value := .Values.mylist }}
- {{ $index }}:{{ $value | title | quote }}
{{- end }}
values.yaml
mydata:
names: marksugar
data: hi mark, my www.linuxea.com
status: isok
mylist:
- mark
- edwin
- sean
如下
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cmp
labels:
app: {{ .Release.Name }}-cmp
data:
name: {{ .Values.mydata.names | default "supper" }}
test: {{ .Values.mydata.data | upper | repeat 5 }}
{{ $linuxea := .Release.Name -}}
{{ with .Values.mydata -}}
releasename: {{ $linuxea }}
{{ if eq .status "isok" -}}
status: ok
{{- else if eq .names "marksugar" -}}
namestatus: "true"
{{ else -}}
defaultstaus: true
{{- end }}
{{- end }}
{{ indent 2 "test: ok" }}
mylist: |-
{{- range .Values.mylist }}
- {{ . | title | quote }}
{{- end }}
{{- range $index,$value := .Values.mylist }}
- {{ $index }}:{{ $value | title | quote }}
{{- end }}
渲染
PS H:k8s-1.20.2helm> helm template linuxea.com .liunuxea
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: linuxea.com-cmp
labels:
app: linuxea.com-cmp
data:
name: marksugar
test: HI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COM
releasename: linuxea.com
status: ok
test: ok
mylist: |-
- "Mark"
- "Edwin"
- "Sean"
- 0:"Mark"
- 1:"Edwin"
- 2:"Sean"
- map
同样,可以渲染一个字典
{{- range $index,$value := .Values.mydata }}
- {{ $index }}:{{ $value | title | quote }}
{{- end }}
values.yaml
mydata:
names: marksugar
data: hi mark, my www.linuxea.com
status: isok
mylist:
- mark
- edwin
- sean
如下
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cmp
labels:
app: {{ .Release.Name }}-cmp
data:
name: {{ .Values.mydata.names | default "supper" }}
test: {{ .Values.mydata.data | upper | repeat 5 }}
{{ $linuxea := .Release.Name -}}
{{ with .Values.mydata -}}
releasename: {{ $linuxea }}
{{ if eq .status "isok" -}}
status: ok
{{- else if eq .names "marksugar" -}}
namestatus: "true"
{{ else -}}
defaultstaus: true
{{- end }}
{{- end }}
{{ indent 2 "test: ok" }}
mylist: |-
{{- range .Values.mylist }}
- {{ . | title | quote }}
{{- end }}
{{- range $index,$value := .Values.mylist }}
- {{ $index }}:{{ $value | title | quote }}
{{- end }}
{{- range $index,$value := .Values.mydata }}
- {{ $index }}:{{ $value | title | quote }}
{{- end }}
渲染
PS H:k8s-1.20.2helm> helm template linuxea.com .liunuxea
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: linuxea.com-cmp
labels:
app: linuxea.com-cmp
data:
name: marksugar
test: HI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COM
releasename: linuxea.com
status: ok
test: ok
mylist: |-
- "Mark"
- "Edwin"
- "Sean"
- 0:"Mark"
- 1:"Edwin"
- 2:"Sean"
- data:"Hi Mark, My Www.Linuxea.Com"
- names:"Marksugar"
- status:"Isok"
示例3 全局变量
变量通常而言不是全局的,都在作用域之内,在range和with中作用域也只是在{{ rage }}和{{end}}之间的。
为了解决这个问题,可以从顶部开始定义一个,或者使用$
来引用外部变量
$
表示最外层的上下文
- 顶部定义Release.Name
有两种方式。第一种,在顶部定义,如下
{{ $linuxea := .Release.Name -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cmp
labels:
app: {{ .Release.Name }}-cmp
data:
...
releasename: {{ $linuxea }}
...
$
引用Chart.Name
{{ $linuxea := .Release.Name -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cmp
labels:
app: {{ .Release.Name }}-cmp
data:
...
chartname: {{ $.Chart.Name }}
...
如下
{{ $linuxea := .Release.Name -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cmp
labels:
app: {{ .Release.Name }}-cmp
data:
name: {{ .Values.mydata.names | default "supper" }}
test: {{ .Values.mydata.data | upper | repeat 5 }}
{{ with .Values.mydata -}}
releasename: {{ $linuxea }}
chartname: {{ $.Chart.Name }}
{{ if eq .status "isok" -}}
status: ok
{{- else if eq .names "marksugar" -}}
namestatus: "true"
{{ else -}}
defaultstaus: true
{{- end }}
{{- end }}
渲染
PS H:k8s-1.20.2helm> helm template linuxea.com .liunuxea
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: linuxea.com-cmp
labels:
app: linuxea.com-cmp
data:
name: marksugar
test: HI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COM
releasename: linuxea.com
chartname: linuxea
status: ok
到现在为止,一直都是使用一个模板来进行操作的,如果要进行多个模板,就需要使用到命名模板。
命名模板
命名模板也称为子模板。在文件内部定义,通常有两种方式创建,而使用方式较多
一旦定义了命名模板,名称就是全局的,如果名称重复,最后被加载的模板会被使用。因此,命名需要注意不要冲突,而为了避免此事,大家开始约定,在定义的模板前添加chart名称,如
{{ define "mylinuxea.name" }}
通过这种特定的前缀避免相同名称带来的冲突问题
如果希望渲染的是一段,那么template将很适用,否则include可以更适合
嵌套
helm模板允许创建命名进行嵌入式的方式在其他位置进行访问。
命名约定:
- templates/ 目录下的文件被视为kubernetes资源清单
- 以
_
开头的文件不会被当作资源清单文件 - 以
_
下划线开头的文件可以被其他chart模板调用
partials
_
开头的文件是helm中的partials,默认的名称模板就在_helpers.tpl文件中,而我们自己定义的也可以在其中。这些文件就是partials文件。而在chart的包中也能找到这个文件
...
templates/
|
`-- tests
.......
`-- _helpers.tpl
....
_helpers.tpl中就定义了被其他chart调用
define and template
define关键字可以在模板文件中创建命名模板,而后使用template来引用
- 示例
{{ define "linuxea.name" }}
# describe
{{ end }}
定义一个标签
{{- define "linuxea.labels" }}
labels:
generator: helm
data: {{ now | htmlDate }}
{{ end }}
now为当前时间的函数,而htmlDate是格式化
而使用则是使用template引用
{{- template "linuxea.labels" }}
如下
{{ $linuxea := .Release.Name -}}
{{- define "linuxea.labels" }}
labels:
generator: helm
data: {{ now | htmlDate -}}
{{ end }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cmp
{{- template "linuxea.labels" }}
data:
name: {{ .Values.mydata.names | default "supper" }}
test: {{ .Values.mydata.data | upper | repeat 5 }}
{{ with .Values.mydata -}}
releasename: {{ $linuxea }}
chartname: {{ $.Chart.Name }}
{{ if eq .status "isok" -}}
status: ok
{{- else if eq .names "marksugar" -}}
namestatus: "true"
{{ else -}}
defaultstaus: true
{{- end }}
{{- end }}
渲染
PS H:k8s-1.20.2helm> helm template linuxea.com .liunuxea
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: linuxea.com-cmp
labels:
generator: helm
data: 2022-04-21
data:
name: marksugar
test: HI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COM
releasename: linuxea.com
chartname: linuxea
status: ok
- _helpers.tpl
那么按照刚说的,我们应该把她放在创建的_helpers.tpl
文件中
{{/ 注释 /}} 注释
{{/* 注释 */}}
{{- define "linuxea.labels" }}
labels:
generator: helm
data: {{ now | htmlDate -}}
{{ end }}
其他不需要修改,仍然是可以进行调用的
PS H:k8s-1.20.2helm> helm template linuxea.com .liunuxea
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: linuxea.com-cmp
labels:
generator: helm
data: 2022-04-21
data:
name: marksugar
test: HI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COM
releasename: linuxea.com
chartname: linuxea
status: ok
访问范围
那么此时,如果想要在_helpers.tpl中使用helm的内置函数对象,如:Release.Name
类似的对象,就需要在template中传递一个.
.
作为作用域,在_helpers.tpl中需要从template中传递过来,否则是无法正常被使用
_helpers.tpl
chartName: {{ .Release.Name }}
_helpers.tpl中的
.
是从template的尾部的.
传递的,也就是作用域中的传递
引用使用template的尾部加.
{{- template "linuxea.labels" . }}
如下
{{/* labels */}}
{{- define "linuxea.labels" }}
labels:
generator: helm
data: {{ now | htmlDate }}
chartName: {{ .Release.Name }}
{{- end }}
引用
{{ $linuxea := .Release.Name -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cmp
{{- template "linuxea.labels" . }}
data:
name: {{ .Values.mydata.names | default "supper" }}
test: {{ .Values.mydata.data | upper | repeat 5 }}
{{ with .Values.mydata -}}
releasename: {{ $linuxea }}
chartname: {{ $.Chart.Name }}
{{ if eq .status "isok" -}}
status: ok
{{- else if eq .names "marksugar" -}}
namestatus: "true"
{{ else -}}
defaultstaus: true
{{- end }}
{{- end }}
渲染
PS H:k8s-1.20.2helm> helm.exe template test .liunuxea
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-cmp
labels:
generator: helm
data: 2022-04-23
chartName: test
data:
name: marksugar
test: HI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COM
releasename: test
chartname: linuxea
status: ok
include
template作为一个函数用来渲染结果,是无法将模板调用给其他函数使用的,而要完成这样的操作就需要include,include可以将模板内容导入到当前的管道,传递给其他函数
template只是将结果渲染,原封不动的渲染过来,而include可以做一些操作,比如,添加空格。而这在yaml格式中尤为重要
定义一个mark.labels,如下
{{- define "mark.labels" }}
app: linuxea.com
version: v0.1
{{- end }}
引用
metadata:
name: {{ .Release.Name }}-cmp
labels:
{{- include "mark.labels" . | indent 4 }}
include 后,indent 4 空出4个空格
如下
{{ $linuxea := .Release.Name -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cmp
labels:
{{- include "mark.labels" . | indent 4 }}
data:
name: {{ .Values.mydata.names | default "supper" }}
test: {{ .Values.mydata.data | upper | repeat 5 }}
{{ with .Values.mydata -}}
releasename: {{ $linuxea }}
chartname: {{ $.Chart.Name }}
{{ if eq .status "isok" -}}
status: ok
{{- else if eq .names "marksugar" -}}
namestatus: "true"
{{ else -}}
defaultstaus: true
{{- end }}
{{- end }}
渲染如下
PS H:k8s-1.20.2helm> helm.exe template test .liunuxea
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-cmp
labels:
app: linuxea.com
version: v0.1
data:
name: marksugar
test: HI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COMHI MARK, MY WWW.LINUXEA.COM
releasename: test
chartname: linuxea
status: ok
.Files
.Files可以更好的导入文件中的内容,上面的几种都是来使得模板使用变得容易,而.Files是注入内容,但是并不是通过模板渲染获得。但是.files在使用的时候需要注意一下3点:
1,helm chart被限制必须不能大于1M,而.files的文件也会被打包,这意味着不能什么都加进去
helm chart最终是以secret形式存放,而secret是存放在etcd中,etcd本身的限制
2,出于安全考虑.Files不能访问template/和.helmgnore的排除文件
3,chart不会与uninx系统信息挂钩,.files的文件权限不影响使用
注意:
文件内容必须是yaml格式或者json格式
文件必须在template目录之上,和values.yaml同级别
在templates目录之上创建三个文件
否则会抛出: Error: INSTALLATION FAILED: unable to build kubernetes objects from release manifest: error validating "": error validating data: [apiVersion not set, kind not set]
错误
所以目录结构必须正确
Test.json
test2.json
test3.json
如下
PS H:k8s-1.20.2helm> dir .liunuxea
目录: H:k8s-1.20.2helmliunuxea
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2022-04-26 0:28 templates
-a---- 2022-04-26 0:21 0 .helmignore
-a---- 2022-04-26 0:24 102 Chart.yaml
-a---- 2022-04-26 0:22 10 Test.json
-a---- 2022-04-26 0:38 11 test2.json
-a---- 2022-04-26 0:38 12 test3.json
-a---- 2022-04-26 0:12 120 values.yaml
而后使用range来遍历
如下
apiVersion: v1
kind: Secret
metadata:
name: mysecret
namespace: default
type: Opaque
data:
{{- $files := .Files }}
{{- range tuple "Test.json" "test2.json" "test3.json"}}
{{ . }}: |-
{{ $files.Get . }}
{{- end }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
data:
{{- $files := .Files }}
{{- range tuple "Test.json" "test2.json" "test3.json"}}
{{ . }}: |-
{{ $files.Get . }}
{{- end }}
$files赋值的值是.Files对象的引用,tuple函数来循环文件列表,而后打印每个文件夹的
{{ . }}: 文件名 |- 换行,并且去掉行尾空格 {{ $files.Get . }} 打印文件内容
渲染
PS H:k8s-1.20.2helm> helm.exe install test --dry-run .liunuxea
NAME: test
LAST DEPLOYED: Tue Apr 26 00:39:14 2022
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
namespace: default
type: Opaque
data:
Test.json: |-
names: 123
test2.json: |-
names: 1234
test3.json: |-
names: 12345
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: special-config
data:
Test.json: |-
names: 123
test2.json: |-
names: 1234
test3.json: |-
names: 12345
configmap和secrets
pod中的configmap和secrets如果把文件内容同时加入到configmap和secrets中,在helm中有另外一个方法
https://helm.sh/docs/chart_template_guide/accessing_files/#configmap-and-secrets-utility-functions
- asconfig
- assecrets
如果不想用这两个还可使用base64编码
在templates目录之上创建三个文件
否则会抛出:
Error: INSTALLATION FAILED: unable to build kubernetes objects from release manifest: error validating "": error validating data: [apiVersion not set, kind not set]
错误所以目录结构必须正确
{{ $linuxea := .Release.Name -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cmp
labels:
{{- include "mark.labels" . | indent 4 }}
data:
token: |-
{{ .Files.Get "test3.json" | b64enc }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ .Release.Name }}-linuxea
type: Opaque
data:
my.cnf: |-
{{ .Files.Get "test2.json" | b64enc }}
调试
PS H:k8s-1.20.2helm> helm.exe install test --dry-run .liunuxea
NAME: test
LAST DEPLOYED: Tue Apr 26 00:42:37 2022
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: Secret
metadata:
name: test-linuxea
type: Opaque
data:
my.cnf: |-
bmFtZXM6IDEyMzQ=
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-cmp
labels:
app: linuxea.com
version: v0.1
data:
token: |-
bmFtZXM6IDEyMzQ1
NOTES.txt 文件
NOTES.txt被用来打印一些信息的,比如在安装完成或者升级完成后,而使用模板可以自定义这些信息。
而要使用这些,必须创建一个NOTES.txt的文件在templates目录下,纯文本内容。但是可以像模板一样进行处理并且和模板一样进行使用。
在template模板下创建一个NOTES.txt,内容随便,如下:
==================================
hello
thank you install {{ .Chart.Name }}
describe:
$ helm status {{ .Release.Name }}
$ helm get {{ .Release.Name }}
因为是安装后或者升级才能看到的,所以需要安装调试下才能看到
PS H:k8s-1.20.2helm> helm.exe install test --dry-run .liunuxea
NAME: test
LAST DEPLOYED: Tue Apr 26 23:02:27 2022
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
HOOKS:
MANIFEST:
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: Secret
metadata:
name: test-linuxea
type: Opaque
data:
my.cnf: |-
bmFtZXM6IDEyMzQ=
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-cmp
labels:
app: linuxea.com
version: v0.1
data:
token: |-
bmFtZXM6IDEyMzQ1
NOTES:
==================================
hello
thank you install linuxea
describe:
$ helm status test
$ helm get test
subcharts和全局值
charts是可以有一些依赖项的,这种依赖的方式是subcharts,也可以称为子chart
子chart注意信息:
- subcharts是独立的,不能依赖父chart
- 子chart无法访问父级的值
- 父级可以覆盖子chart的值
- helm中可以定义全局值,在父,子的chart都可以被访问
子chart
因此,我们在当前的liunxea的charts目录下下创建一个mychart
helm create mychart
rm mychart/templates/*
而后在templates下添加一个values.yaml,内容如下
mark: "hello mark"
在template下创建一个configmap.yaml,如下
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-mychart
data:
mychart: {{ .Values.mark }}
在当前子chart中渲染
两个chart是独立的,因此可以进行渲染
PS H:k8s-1.20.2helmliunuxeamychart> helm.exe template test ./
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-mychart
data:
mychart: hello mark
如果此时要在主chart,也就是liunxea中覆盖子chart,就需要在主chart中添加同样的参数
mychart:
mark: "is master chart"
而后直接渲染即可
顶层的主chart覆盖了子chart的值,但是这种覆盖方式在模板引擎传递values值的时候就会配置作用域,当覆盖的时候,liunxea中的values的mychart值就会传递到mychart, 对于mychart模板中的
.Vaules
仅仅用域该子chart的值
PS H:k8s-1.20.2helmliunuxea> helm.exe template test .
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: Secret
metadata:
name: test-linuxea
type: Opaque
data:
my.cnf: |-
bmFtZXM6IDEyMzQ=
---
# Source: linuxea/charts/mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-mychart
data:
mychart: is master chart
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-cmp
labels:
app: linuxea.com
version: v0.1
data:
token: |-
bmFtZXM6IDEyMzQ1
全局值
全局值是可以从任何 chart 或子 chart 中都可以访问的值,全局值需要显示的声明,不能将现有的非全局对象当作全局对象使用。
Values 数据类型具有一个名为 Values.global
的保留部分,可以在其中设置全局值,我们在 values.yaml
文件中添加一个全局值:
global:
name: marksugar
分别在文件中引用
name2: {{ .Values.global.name }}
渲染
PS H:k8s-1.20.2helm> helm template test .liunuxea
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: Secret
metadata:
name: test-linuxea
name2: marksugar
type: Opaque
data:
my.cnf: |-
bmFtZXM6IDEyMzQ=
---
# Source: linuxea/charts/mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-mychart
data:
mychart: is master chart
name: marksugar
---
# Source: linuxea/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-cmp
labels:
app: linuxea.com
version: v0.1
data:
token: |-
bmFtZXM6IDEyMzQ1
共享模板
父级 chart 和子 chart 可以共享模板,任何 chart 中已定义的块都可以用于其他 chart。比如,我们可以定义一个简单的模板,如下所示:
{{- define "labels" }}from: mychart{{ end }}
前面我们提到过可以使用在模板中使用 include
和 template
,但是使用 include
的一个优点是可以动态引入模板的内容:
{{ include $mytemplate }}
hook
helm提供一个钩子,可以在某个时间点进行干预,比如:
- 在加载charts之前执行一个job备份数据库,安装完成后执行第二个job还原
- 删除之前运行一个Job来关闭一些服务
Hooks 的工作方式类似于普通的模板,但是他们具有特殊的注解,这些注解使 Helm 可以用不同的方式来使用他们。
hooks
在 Helm 中定义了如下一些可供我们使用的 Hooks:
- 预安装
pre-install
:在模板渲染后,kubernetes 创建任何资源之前执行 - 安装后
post-install
:在所有 kubernetes 资源安装到集群后执行 - 预删除
pre-delete
:在从 kubernetes 删除任何资源之前执行删除请求 - 删除后
post-delete
:删除所有 release 的资源后执行 - 升级前
pre-upgrade
:在模板渲染后,但在任何资源升级之前执行 - 升级后
post-upgrade
:在所有资源升级后执行 - 预回滚
pre-rollback
:在模板渲染后,在任何资源回滚之前执行 - 回滚后
post-rollback
:在修改所有资源后执行回滚请求 - 测试
test
:在调用 Helmtest
子命令的时候执行
生命周期
Hooks 允许开发人员在 release 的生命周期中的一些关键节点执行一些钩子函数,我们正常安装一个 chart 包的时候的生命周期如下所示:
- 用户运行
helm install foo
- Helm 库文件调用安装 API
- 经过一些验证,Helm 库渲染
foo
模板 - Helm 库将产生的资源加载到 kubernetes 中去
- Helm 库将 release 对象和其他数据返回给客户端
- Helm 客户端退出
如果开发人员在 install
的生命周期中定义了两个 hook:pre-install
和post-install
,那么我们安装一个 chart 包的生命周期就会多一些步骤了:
- 用户运行helm install foo
- Helm 库文件调用安装 API
- 在 crds/ 目录下面的 CRDs 被安装
- 经过一些验证,Helm 库渲染 foo 模板
- Helm 库将 hook 资源加载到 kubernetes 中,准备执行pre-install hooks
- Helm 库会根据权重对 hooks 进行排序(默认分配权重0,权重相同的 hook 按升序排序)
- Helm 库然后加载最低权重的 hook
- Helm 库会等待,直到 hook 准备就绪
- Helm 库将产生的资源加载到 kubernetes 中,注意如果添加了 --wait 参数,Helm 库会等待所有资源都准备好,在这之前不会运行 post-install hook
- Helm 库执行 post-install hook(加载 hook 资源)
- Helm 库等待,直到 hook 准备就绪
- Helm 库将 release 对象和其他数据返回给客户端
- Helm 客户端退出
等待 hook 准备就绪,这是一个阻塞的操作,如果 hook 中声明的是一个 Job 资源,Helm 将等待 Job 成功完成,如果失败,则发布失败,在这个期间,Helm 客户端是处于暂停状态的。
对于所有其他类型,只要 kubernetes 将资源标记为加载(添加或更新),资源就被视为就绪状态,当一个 hook 声明了很多资源是,这些资源是被串行执行的。
另外需要注意的是 hook 创建的资源不会作为 release 的一部分进行跟踪和管理,一旦 Helm 验证了 hook 已经达到了就绪状态,它就不会去管它了。
所以,如果我们在 hook 中创建了资源,那么不能依赖 helm uninstall
去删除资源,因为 hook 创建的资源已经不受控制了,要销毁这些资源,你需要将 helm.sh/hook-delete-policy
这个 annotation 添加到 hook 模板文件中,或者设置 Job 资源的生存(TTL)字段。
编写hook
Hooks 就是 Kubernetes 资源清单文件,在元数据部分带有一些特殊的注解,因为他们是模板文件,所以你可以使用普通模板所有的功能,包括读取 .Values
、.Release
和 .Template
。
例如,在 templates/post-install-job.yaml
文件中声明一个 post-install 的 hook:
这个hook以job的形式在安装完成后触发,执行成功就删掉
apiVersion: batch/v1
kind: Job
metadata:
....
annotations:
# 因为添加了这个 hook,所以我们这个资源被定义为了 hook
# 如果没有这行,则当前这个 Job 会被当成 release 的一部分内容。
"helm.sh/hook": post-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": hook-succeeded
- 详细
这个模板成为 hook 的原因就是添加这个注解:
annotations:
"helm.sh/hook": post-install
一种资源也可以实现多个 hooks:
annotations:
"helm.sh/hook": post-install,post-upgrade
类似的,实现给定 hook 的资源数量也没有限制,比如可以将 secret 和一个 configmap 都声明为 pre-install
hook。
当子 chart 声明 hooks 的时候,也会对其进行调用,顶层的 chart 无法禁用子 chart 所声明的 hooks。可以为 hooks 定义权重,这将有助于确定 hooks 的执行顺序:
annotations:
"helm.sh/hook-weight": "5"
hook 权重可以是正数也可以是负数,但是必须用字符串表示,当 Helm 开始执行特定种类的 hooks 的时候,它将以升序的方式对这些 hooks 进行排序。
渲染
Chart.yaml
apiVersion: v1
name: linuxea
description: A Helm chart for Kubernetes
type: application
version: 0.1.2
appVersion: "1.16.0"
job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ .Release.Name }}"
labels:
app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
app.kubernetes.io/instance: {{ .Release.Name | quote }}
app.kubernetes.io/version: {{ .Chart.AppVersion }}
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
annotations:
# 因为添加了这个 hook,所以我们这个资源被定义为了 hook
# 如果没有这行,则当前这个 Job 会被当成 release 的一部分内容。
"helm.sh/hook": post-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": hook-succeeded
spec:
template:
metadata:
name: "{{ .Release.Name }}"
labels:
app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
app.kubernetes.io/instance: {{ .Release.Name | quote }}
helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
spec:
restartPolicy: Never
containers:
- name: post-install-job
image: "alpine:3.3"
command: ["/bin/sleep","{{ default "10" .Values.sleepyTime }}"]
configmap.yaml
{{ $linuxea := .Release.Name -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-cmp
labels:
{{- include "mark.labels" . | indent 4 }}
data:
token: |-
{{ .Files.Get "test3.json" | b64enc }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ .Release.Name }}-linuxea
type: Opaque
data:
my.cnf: |-
{{ .Files.Get "test2.json" | b64enc }}
values.yaml
mydata:
names: marksugar
data: hi mark, my www.linuxea.com
status: isok
mylist:
- mark
- edwin
- sean
mychart:
mark: "is master chart"
global:
name: marksugar
开始安装
PS H:k8s-1.20.2helm> helm install mark .liunuxea
此时打开另外一个终端观察
PS C:WINDOWSsystem32> kubectl.exe get pod -w
NAME READY STATUS RESTARTS AGE
dpment-linuxea-6bdfbd7b77-fr4pn 1/1 Running 16 40d
dpment-linuxea-a-5b98f7fb86-9ff2f 1/1 Running 24 52d
mark-hlrpf 0/1 ContainerCreating 0 14s
nfs-client-provisioner-597f7dd4b-h2nsg 1/1 Running 86 277d
testv1-9c974bd5d-gl52m 1/1 Running 16 40d
testv2-5767685995-mjd6c 1/1 Running 23 52d
traefik-6866c896d5-dqlv6 1/1 Running 16 40d
whoami-7d666f84d8-8wmk4 1/1 Running 22 50d
whoami-7d666f84d8-vlgb9 1/1 Running 16 40d
whoamitcp-744cc4b47-24prx 1/1 Running 16 40d
whoamitcp-744cc4b47-xrgqp 1/1 Running 16 40d
whoamiudp-58f6cf7b8-b6njt 1/1 Running 16 40d
whoamiudp-58f6cf7b8-jnq6c 1/1 Running 22 50d
mark-hlrpf 1/1 Running 0 21s
mark-hlrpf 0/1 Completed 0 31s
mark-hlrpf 0/1 Terminating 0 32s
mark-hlrpf 0/1 Terminating 0 32s
可以看到执行完成后就被删除了这个job
当这里执行完成,渲染也结束
PS H:k8s-1.20.2helm> helm install mark .liunuxea
NAME: mark
LAST DEPLOYED: Sun May 15 22:45:38 2022
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
==================================
hello
thank you install linuxea
describe:
$ helm status mark
$ helm get mark
通过ls查看
PS H:k8s-1.20.2helm> helm ls
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
mark default 1 2022-05-15 22:45:38.6000054 +0800 CST deployed linuxea-0.1.2 1.16.0
查看configmap
PS H:k8s-1.20.2helm> kubectl.exe get configmap
NAME DATA AGE
istio-ca-root-cert 1 55d
kube-root-ca.crt 1 339d
mark-cmp 1 5m50s
mark-mychart 2 5m50s
describe查看内容
PS H:k8s-1.20.2helm> kubectl.exe describe configmap mark-mychart
Name: mark-mychart
Namespace: default
Labels: app.kubernetes.io/managed-by=Helm
Annotations: meta.helm.sh/release-name: mark
meta.helm.sh/release-namespace: default
Data
====
mychart:
----
is master chart
name:
----
marksugar
Events: <none>
PS H:k8s-1.20.2helm> kubectl.exe describe configmap mark-cmp
Name: mark-cmp
Namespace: default
Labels: app=linuxea.com
app.kubernetes.io/managed-by=Helm
version=v0.1
Annotations: meta.helm.sh/release-name: mark
meta.helm.sh/release-namespace: default
Data
====
token:
----
bmFtZXM6IDEyMzQ1
Events: <none>
- hook删除策略
还可以定义确定何时删除相应 hook 资源的策略,hook 删除策略可以使用下面的注解进行定义:
annotations:
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
我们也可以选择一个或多个已定义的注解:
before-hook-creation
:运行一个新的 hook 之前删除前面的资源(默认)hook-succeeded
:hook 成功执行后删除资源hook-failed
:hook 如果执行失败则删除资源
如果未指定任何 hook 删除策略注解,则默认情况下会使用 before-hook-creation
策略。