Helm chart

时间:Nov. 20, 2020 分类:

目录:

Helm chart

参考

全文参考https://helm.sh/docs/chart_template_guide/整理

入门

Helm chart结构

mychart/
  Chart.yaml
  values.yaml
  charts/
  templates/
  ...

创建简单的Helm chart

$ helm create mychart
Creating mychart

mychart/templates/目录结构

  • NOTES.txt:帮助文本,运行时helm install时显示
  • _helpers.tpl:放置模板助手的地方,可重复使用

添加个configmap,mychart/templates/configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"

直接构建即可,full-coral是发行版的名称

$ helm install full-coral ./mychart
NAME: full-coral
LAST DEPLOYED: Tue Nov  1 17:36:01 2016
NAMESPACE: default
STATUS: DEPLOYED
REVISION: 1
TEST SUITE: None

检测已经发布的模板

$ helm get manifest full-coral

---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"

卸载使用helm uninstall full-coral

模板调动的helm chart

调整configmap

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"

Release是helm内置对象

$ helm install clunky-serval ./mychart

执行就会生成clunky-serval-configmap

测试可以指定--dry-run参数,打印渲染后的模板

内置对象

Release为对象描述,包含

  • Release.Name:发行名称
  • Release.Namespace:安装的namespace,如果chart中没有进行覆盖
  • Release.IsUpgrade:如是是升级和回滚,该值为true
  • Release.IsInstall:如是是安装,该值为true
  • Release.Revision:版本号,安装的时候为1,之后升级和回滚都会增加
  • Release.Service:模板服务,helm就一直为helm

还有

Values为values.yaml文件内容

Chart为Chart.yaml内容,参考the-chartyaml-file

Files为非特殊文件的访问,参考[accessing_files](https://helm.sh/docs/chart_template_guide/accessing_files/)

  • Files.Get:获取文件
  • Files.GetBytes:获取文件的字节数组
  • Files.Glob:
  • Files.Lines:逐行读取文件
  • Files.AsSecrets:文件内容做base64
  • Files.AsConfig:文件内容作为yaml

Capabilities为kubernetes支持能力

  • Capabilities.APIVersions
  • Capabilities.APIVersions.Has
  • Capabilities.KubeVersion
  • Capabilities.KubeVersion.Version
  • Capabilities.KubeVersion.Major
  • Capabilities.KubeVersion.Minor

Template为模板相关信息

  • Template.Name:模板文件路径(例如 mychart/templates/mytemplate.yaml)
  • Template.BasePath:模板文件路径(例如mychart/templates)

value

value的获取有很多方式

  • chart中的value文件
  • 父级的value文件
  • helm installhelm upgrade传入,例如helm install -f myvals.yaml ./mychart
  • 通过--set传入,例如helm install --set foo=bar ./mychart

优先级是从下到上的顺序,set的优先级最高

使用value

在value.yaml中写入favoriteDrink: coffee

configmap调整为

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favoriteDrink }}

测试一下

$ helm install geared-marsupi ./mychart --dry-run --debug
install.go:158: [debug] Original chart version: ""
install.go:175: [debug] CHART PATH: /home/bagratte/src/playground/mychart

NAME: geared-marsupi
LAST DEPLOYED: Wed Feb 19 23:21:13 2020
NAMESPACE: default
STATUS: pending-install
REVISION: 1
TEST SUITE: None
USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
favoriteDrink: coffee

HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: good-puppy-configmap
data:
  myvalue: "Hello World"
  drink: coffee

value文件调整为

favorite:
  drink: coffee
  food: pizza

configmap调整为

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink }}
  food: {{ .Values.favorite.food }}

在set的指定drink=slurm

删除默认值

默认的探针为

livenessProbe:
  httpGet:
    path: /user/login
    port: http
  initialDelaySeconds: 120

直接set添加是不行的,--set livenessProbe.exec.command=[cat,docroot/CHANGELOG.txt]会生成

livenessProbe:
  httpGet:
    path: /user/login
    port: http
  exec:
    command:
    - cat
    - docroot/CHANGELOG.txt
  initialDelaySeconds: 120

需要将livenessProbe.httpGet设置为null,helm install stable/drupal --set image=my-registry/drupal:0.1.0 --set livenessProbe.exec.command=[cat,docroot/CHANGELOG.txt] --set livenessProbe.httpGet=null

模板的方法和管道

模板使用

模板支持很多方法,基本都是go模板语言定义和sprig库提供的

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ quote .Values.favorite.drink }}
  food: {{ quote .Values.favorite.food }}

或则使用管道的方式

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | quote }}
  food: {{ .Values.favorite.food | quote }}

所以.val | quote等价于quote .val

支持多个管道

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | quote }}
  food: {{ .Values.favorite.food | upper | quote }}

模板设置默认字段

在模板内部设置默认值

drink: {{ .Values.favorite.drink | default "tea" | quote }}

查找集群内资源

有apiVersion,kind,namespace和name,语法为lookup apiVersion, kind, namespace, name -> resource or resource list

例如

# 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来获取

{{ range $index, $service := (lookup "v1" "Service" "mynamespace" "").items }}
    {{/* do something with each service */}}
{{ end }}

但是交互失败就会造成模板处理失败

helm install|update|delete|rollback --dry-run获取到的也为空

运算符

eq,ne,lt,gt,and,or都可以在管道中使用,支持括号

更多方法

更多方法参考官方文档function_list

流程控制

if/else

{{ if PIPELINE }}
  # Do something
{{ else if OTHER PIPELINE }}
  # Do something else
{{ else }}
  # Default case
{{ end }}

为false和go一样,零值

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 }}

格式对其

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 }}

{{- value}}为左侧不留白

也可以通过方法控制{{ indent 2 "mug:true" }}

with

控制变量作用域

{{ with PIPELINE }}
  # restricted scope
{{ end }}

示例,将.的作用域调整为.Values.favorite

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 }}

但是也会造成无法访问作用域之外了,需要使用$.

{{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
  release: {{ $.Release.Name }}
{{- end }}

range

value使用

favorite:
  drink: coffee
  food: pizza
pizzaToppings:
  - mushrooms
  - cheese
  - peppers
  - onions

configmap就可以写成

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 }}
    {{- end }}

也可以在模板中创建一个tuple

sizes: |-
    {{- range tuple "small" "medium" "large" }}
    - {{ . }}
    {{- end }}

产生的就是

sizes: |-
    - small
    - medium
    - large

变量

设置变量

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 }}

在循环中使用变量

toppings: |-
    {{- range $index, $topping := .Values.pizzaToppings }}
      {{ $index }}: {{ $topping }}
    {{- end }}

循环map

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  {{- range $key, $val := .Values.favorite }}
  {{ $key }}: {{ $val | quote }}
  {{- end }}

获取全局变量仍然是$

模板

声明模板

语法

{{ define "MY.NAME" }}
  # body of template here
{{ end }}

示例生成一个标签快

{{- define "mychart.labels" }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
{{- end }}

使用模板

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

模板文件

模板文件通常放在_helpers.tpl中

{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
{{- end }}

这样{{/* ... */}}可以描述作用

模板作用域

{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
    chart: {{ .Chart.Name }}
    version: {{ .Chart.Version }}
{{- end }}

如果在使用的时候不指定作用域,会取不到值,需要指定,例如示例的.

{{- template "mychart.labels" . }}

include

通过include控制模板的缩进,{{ include "mychart.app" . | indent 4 }}

例如模板

{{- define "mychart.app" -}}
app_name: {{ .Chart.Name }}
app_version: "{{ .Chart.Version }}"
{{- end -}}

使用

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  labels:
    {{ template "mychart.app" . }}
data:
  myvalue: "Hello World"
  {{- range $key, $val := .Values.favorite }}
  {{ $key }}: {{ $val | quote }}
  {{- end }}
{{ template "mychart.app" . }}

得到的就是

kind: ConfigMap
metadata:
  name: measly-whippet-configmap
  labels:
    app_name: mychart
app_version: "0.1.0+1478129847"
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "pizza"
  app_name: mychart
app_version: "0.1.0+1478129847"

访问文件

Get

config1.toml:

message = Hello from config 1

config2.toml:

message = This is config 2

config3.toml:

message = Goodbye from config 3

获取配置

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  {{- $files := .Files }}
  {{- range tuple "config1.toml" "config2.toml" "config3.toml" }}
  {{ . }}: |-
    {{ $files.Get . }}
  {{- end }}

Glob

获取组织

{{ range $path, $_ :=  .Files.Glob  "**.yaml" }}
      {{ $.Files.Get $path }}
{{ end }}

直接生成yaml配置

apiVersion: v1
kind: ConfigMap
metadata:
  name: conf
data:
{{ (.Files.Glob "foo/*").AsConfig | indent 2 }}
---
apiVersion: v1
kind: Secret
metadata:
  name: very-secret
type: Opaque
data:
{{ (.Files.Glob "bar/*").AsSecrets | indent 2 }}

base编码

apiVersion: v1
kind: Secret
metadata:
  name: {{ .Release.Name }}-secret
type: Opaque
data:
  token: |-
    {{ .Files.Get "config1.toml" | b64enc }}

获取到的结果

# Source: mychart/templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: lucky-turkey-secret
type: Opaque
data:
  token: |-
    bWVzc2FnZSA9IEhlbGxvIGZyb20gY29uZmlnIDEK

循环模板文件

data:
  some-file.txt: {{ range .Files.Lines "foo/bar.txt" }}
    {{ . }}{{ end }}

note文件

note文件是用于描述模板功能和可用对象的文件

templates/NOTES.txt

Thank you for installing {{ .Chart.Name }}.

Your release is named {{ .Release.Name }}.

To learn more about the release, try:

  $ helm status {{ .Release.Name }}
  $ helm get all {{ .Release.Name }}

.helmignore

指定不在chart的文件

# comment

# Match any file or path named .git
.git

# Match any text file
*.txt

# Match only directories named mydir
mydir/

# Match only text files in the top-level directory
/*.txt

# Match only the file foo.txt in the top-level directory
/foo.txt

# Match any file named ab.txt, ac.txt, or ad.txt
a[b-d].txt

# Match any file under subdir matching temp*
*/temp*

*/*/temp*
temp?

和git的区别

  • 不支持**语法
  • 不支持!

debug

查看模板使用

helm install --dry-run --debug
或
helm template --debug
  • helm lint检查是否满足语法
  • helm get manifest查看安装的方法

示例

apiVersion: v2
# some: problem section
# {{ .Values.foo | quote }}

进行helm install --dry-run --debug,获得的是

apiVersion: v2
# some: problem section
#  "bar"