文章目录

概述架构Helm客户端安装Helm常用命令

Helm包管理Chart内置对象Chart包结构解析Chart命名模板

Helm语法基础语法高级函数逻辑运算流程控制文件操作字符串操作数学运算类型转换

实例解读 _helpers.tpl

文章基于企业经验和Helm官方文档编写,内容全面,可收藏作为Helm开发手册。

概述

引言:大家都知道,在k8s中,每个对象都是一种资源,每种资源都有其特定的资源描述语法格式,存储在资源描述文件中,比如:deployment.yaml、service.yaml、pod.yaml等。k8s通过其原生命令kubectl apply -f resource_desc.yaml对资源进行创建,通过修改资源描述的方式对这些资源进行维护。但是,这种方式比较低效且易出错,在软件安装和升级迭代时,无法对这些资源进行统一管理。若在安装、升级和回滚时,有几十上百份资源描述文件,只能一个个的执行,无法满足上线要求。

Helm是kubernetes(k8s)的包管理器,拥有自己的Chart模板和仓库,可以将几十上百份的k8s资源描述文件整合到一个Chart包中,通过helm install /path/to/chart_package_dir/命令安装Chart包中的所有资源,并创建一个服务版本Release对这些资源进行统一管理。

相比于k8s原生方式,helm方式更加便捷和高效,可以非常快速的创建资源对象,并且在后期迭代维护中,也可以非常方便的对服务版本Release进行升级和回滚。

Helm核心对象

Chart helm的资源对象。是一系列k8s资源描述文件的集合,拥有固定的目录结构。可以将chart想象成apt、yum中的软件安装包。Release 是chart的运行实例,代表一个正在运行的应用。 当chart被安装到k8s集群时,就会生成一个Release,初始Release Version为1。当对应用进行升级时,Release Version会自增1。Repository 用于发布和存储Chart的存储库。

架构

Helm是Client/Server架构,包含Helm客户端和Tiller服务端两个组件,Tiller服务端运行在k8s集群中,Helm客户端安装在宿主机上。 用户在helm客户端输入指令,helm客户端将命令转为gRPC请求,Tiller侦听gRPC请求并将其转换为k8s api请求,k8s server根据Tiller请求创建并管理资源对象。

Helm客户端安装

Helm客户端下载地址:https://github.com/helm/helm/releases 下载后,解压移动到/usr/bin/目录即可。

wget https://get.helm.sh/helm-vv3.2.1-linux-amd64.tar.gz

tar zxvf helm-v3.2.1-linux-amd64.tar.gz

mv linux-amd64/helm /usr/bin/

Helm常用命令

格式:helm command [-n ]

命令语法描述createhelm create mychart创建一个的chart,其目录名称为mychart。installhelm install myservice ./mychart/根据./mychart/包创建一个名为myservice的Release。Release版本为1 。在命令后添加选项--debug --dry-run可以测试安装,不会真安装。uninstallhelm uninstall myservice卸载myservice。myservice的Release记录都会被删除。所有k8s资源都会被删除。upgradehelm upgrade myservice ./mychart/升级myservice的Release版本。升级后的Release版本加1。rollback1. helm rollback myservice 2. helm rollback myservice 1回滚myservice的Release版本。1.不加Release版本,则回滚后的Release版本减1。2.加上回滚后的Release版本,将回滚到指定Release版本。statushelm status myservice查看myservice的Release信息listhelm list列出Releasehistoryhelm history myservice查看myservice 的Release历史记录,默认返回最大的256个历史版本。show1. helm show chart ./mychart/2. helm show all ./mychart/查看chart详细信息。子命令:chart、all、readme、values。 chart:查看./mychart/Chart.yaml的信息。 values:查看./mychart/values.yaml的信息。 all:查看chart和values的信息。packagehelm package ./mychart/将chart目录文件打包存档到mychart-0.1.0.tgzrepo1. helm repo list2. helm repo add stable http://mirror.azure.cn/kubernetes/charts3. helm repo update4. helm repo remove stable管理远程chart仓库。子命令:list、add、remove、update、index。searchhelm search repo stable查看配置的存储库。versionhelm version查看Helm客户端版本。

核心命令介绍 1.helm create mychart 通常用来初始化一个Chart模板,然后将此模板复制到IDE工具中进行开发编辑。

# 创建一个mychart应用。

master-node:/test # helm create mychart

Creating mychart

master-node:/test # ls -l

total 4

drwxr-xr-x 4 root root 4096 Mar 27 15:05 mychart

2.helm install myservice ./mychart/

master-node:/test # helm install myservice ./mychart/

NAME: myservice

LAST DEPLOYED: Wed Mar 27 15:14:22 2024

NAMESPACE: default

STATUS: deployed

REVISION: 1

NOTES: Something you need to focus on.

master-node:/test # helm list

NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION

myservice default 1 2024-03-27 15:14:22.2151966 +0800 CST deployed mychart-0.1.0 1.16.0

3.helm upgrade myservice ./mychart/ 随着Chart应用不断更新迭代,helm会存档每个版本的Release快照,最大256个Release快照。

master-node:/test # helm upgrade myservice mychart/

Release "myservice" has been upgraded. Happy Helming!

NAME: myservice

LAST DEPLOYED: Wed Mar 27 15:19:35 2024

NAMESPACE: default

STATUS: deployed

REVISION: 2

NOTES: modified record: 1.add tag; 2.upgrade docker image; 3.upgrade app version to 1.16.1

master-node:/test # helm list

NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION

myservice default 2 2024-03-27 15:19:35.754778519 +0800 CST deployed mychart-0.1.0 1.16.0

master-node:/test # helm history myservice

REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION

1 Wed Mar 27 15:14:22 2024 superseded mychart-0.1.0 1.16.0 Install complete

2 Wed Mar 27 15:19:35 2024 deployed mychart-0.1.0 1.16.1 Upgrade complete

4.helm rollback myservice 当Chart应用需要回滚时,helm会调取之前存档的Release快照。

master-node:/test # helm rollback myservice 1

Rollback was a success! Happy Helming!

master-node:/test # helm history myservice

REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION

1 Wed Mar 27 15:14:22 2024 superseded mychart-0.1.0 1.16.0 Install complete

2 Wed Mar 27 15:19:35 2024 superseded mychart-0.1.0 1.16.1 Upgrade complete

3 Wed Mar 27 15:49:05 2024 deployed mychart-0.1.0 1.16.0 Rollback to 1

Helm包管理

Chart内置对象

Helm的内置对象,可以在整个模板文件中引用。

.:表示当前作用域。默认情况下,当前作用域就是全局作用域,用于引用全局变量,如:.Release.Name。{{}}:模板变量嵌套格式,如{{ .Release.Name }}。Release 1 Release.Name:Release名称。 2 Release.Namespace:Release所在的命名空间。 3 Release.IsUpgrade:如果当前操作是upgrade或者rollback,此值设置为true。 4 Release.IsInstall:如果当前操作是install,此值设置为true。 5 Release.Revision:当前Release的修订版本。安装时,该值为 1,并且随着每次升级和回滚而递增。 Release.Service:此值始终为Helm。Values values.yaml文件和用户提供的文件的内容。即用户在values.yaml自定义的对象。默认Values为空。Chart Chart.yaml文件的内容。Chart.yaml中的任何数据都可以访问。例如{{ .Chart.Name }}-{{ .Chart.Version }},引用值为mychart-0.1.0。 Chart字段参见:https://helm.sh/docs/topics/charts/#the-chartyaml-fileSubcharts 访问子Chart对象。例如.Subcharts.mySubChart.myValue访问mySubChart(子Chart)中的myValue。Files 访问Chart中的普通文件。无法访问templates/下的文件和.helmignore排除的文件。 常用函数如下: 1 Files.Get:读取文件内容。如:.Files.Get config.ini,获取config.ini文件内容。 2 Files.GetBytes:读取文件内容(bytes)。常用于读取二进制文件,如:图片。 3 Files.Glob:根据shell glob pattern表达式获取所有的文件,返回值:文件列表。 4 Files.Lines:逐行读取文件。用于迭代文件中的每一行。 5 Files.AsSecrets:读取文件内容,以Base64格式返回文件内容。 6 Files.AsConfig:读取文件内容并映射为YAML格式,返回文件内容。Capabilities 提供k8s集群的基本信息。 1 Capabilities.KubeVersion.Major:k8s的major版本。 2 Capabilities.KubeVersion.Minor:k8s的minor版本。 3 Capabilities.HelmVersion:helm客户端版本。同helm version。 4 Capabilities.HelmVersion.GoVersion:Go编译器版本。Template 模板信息。 1 Template.Name:模板的命名空间路径。如:mychart/templates/mytemplate.yaml。 2 Template.BasePath:模板目录的命名空间路径。如:mychart/templates。

Chart包结构解析

本节只介绍目录结构及其作用,k8s资源定义参见我的另一篇文章《k8s企业级应用(架构原理+资源编排)》。

1. Chart完整目录结构: 我们在实际应用中,一般用不了这么完整的目录结构,都是根据需求删除多余的文件。

# 目录名称mychart就是Chart应用的名称。

mychart/

Chart.yaml # 必选项:包含Chart的描述信息,如:name,version,apiVersion,appVersion。

values.yaml # 必选项:定义公共变量,一般定义需要用户填写的开放配置项,在templates/下资源描述文件中引用。

values.schema.json # 可选项: 拓展Values的元信息,如字段类型、字段描述、字段间依赖。

templates/ # 必选项:Chart模板目录。用来定义k8s资源对象。文件名称没有限制,比如my_pvc.yaml、my_secret.yaml等。

charts/ # 可选项: 依赖的其他Chart,称之为“子Chart”。

crds/ # 可选项: 自定义资源。

LICENSE # 可选项: chart的许可证LICENSE信息。

README.md # 可选项: 说明文件,说明Chart应用的基本信息。

.helmignore # 可选项: 排除不需要加载的文件,类似于.gitignore。

mychart/templates/ # 此模板下使用helm语法引用values.yaml中定义的参数,在运行时渲染成有效的k8s资源描述文档。helm语法后面章节会介绍。

deployment.yaml # 必选项:定义k8s Deployment资源模板,引用values.yaml中的变量渲染出有效的Deployment模板。

_helpers.tpl # 必选项: 模板助手, 表示这是个模板结构。用于定义模板信息,存储模板帮助程序。

hpa.yaml # 可选项: 一般无需更改。

ingress.yaml # 可选项: ingress资源定义,按需添加。

NOTES.txt # 可选项: 帮助文本。helm install和helm upgrade时会显示到终端。

serviceaccount.yaml # 可选项: 一般无需更改。

service.yaml # 必选项:定义k8s service。

# 可选的文件或者目录,我们在IDE侧开发时都可以删除。其他没介绍的都是平常用不到的。

2. Chart简单目录结构: 使用helm create mychart命令创建的模板比较简洁。

mychart/

Chart.yaml # 必选项:命令自动创建

values.yaml # 必选项:命令自动创建

templates/ # 必选项:命令自动创建

charts/ # 可选项: 命令自动创建

.helmignore # 可选项: 命令自动创建

mychart/templates/ # 同上,命令自动创建

3. Chart维护清单与特殊文件:

在Chart模板中,下划线_开头的这些文件不会被加入Chart维护清单中,不能用来定义k8s资源对象,但是可以在Chart模板中被引用。 templates/_helpers.tpl文件,是template的默认位置,表示一个模板结构,类似于python的__init__.py、java的pom.xml。

另一个特殊的文件templates/NOTES.txt也不会被加入维护清单。除此之外的文件,一般都会被加入Chart维护清单中。

Chart命名模板

Helm模板语言还有一个很强大的特性就是能够声明多个模板并将它们一起使用。 应当注意的是,模板名称是全局的,应保持全局唯一。如果声明了两个同名模板,最后一个加载的模板生效。所以,定义Chart模板时,一定要注意命名不能重复。

模板命名规范:

规定将chart名称作为模板名称的前缀,这样就可以避免两个不同的Chart拥有同名模板而引发冲突。 如:{{ define "mychart.labels" }}。

管理模板管理函数:

define:声明一个新的命名模板。template:插入命名模板。 template是一个动作,而不是一个函数。template无法将调用输出结果传递给其他函数,如indent;数据只是内联插入。include:导入命名模板。 include将模板的内容导入到当前管道中,然后将其传递给管道中的其他函数,如indent。template和include区别 include可以将模板内容传递给其他函数进行处理。而 template做不到, template只能原封不动的将模板内容内联插入到引用位置。

模板作用域

使用{{ define "mychart.labels" }}引用模板时,模板语句块中无法引用全局变量.Values .Chart等。 我们可以在模板引用时传递当前作用域 .,如:{{- template "mychart.labels" . }}。

{{/* Generate basic labels */}}

{{- define "mychart.labels" }}

labels:

generator: helm

date: {{ now | htmlDate }}

chart: {{ .Chart.Name }} # {{- template "mychart.labels" }}方式导入时,.Chart.Name对象引用会失败

version: {{ .Chart.Version }}

{{- end }}

---

apiVersion: v1

kind: ConfigMap

metadata:

name: {{ .Release.Name }}-configmap

{{- template "mychart.labels" . }} # 将当前作用域传递给模板,即可在模板中引用.Chart .Values等全局变量。

模板调试语法:

使用模板调试语法,可以随时检查我们定义的模板是否有问题。

验证Chart模板 helm lint ./mychart/。在本地测试渲染Chart模板 helm template --debug ./mychart/。本地渲染模板且不会安装 helm install --dry-run --disable-openapi-validation measly-whippet ./mychart。

案例展示:

声明一个新的命名模板。# 基本格式

---

{{/* 描述模板功能 */}}

{{- define "MY.NAME" }}

# body of template here

{{- end }}

# 定义一个模板来封装k8s标签块

---

{{/* Generate basic labels */}}

{{- define "mychart.labels" }}

labels:

generator: helm

date: {{ now | htmlDate }}

{{- end }}

引用templates/_helpers.tpl中定义的模板# Source: /mychart/templates/myConfigMap.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 }}

在k8s资源描述文件中定义模板并引用# Source: /mychart/templates/myConfigMap.yaml

---

# 定义标签模板,渲染后的结果为空,只有在被引用时才会输出内容。

{{- define "mychart.labels" }}

labels:

generator: helm

date: {{ now | htmlDate }}

{{- end }}

apiVersion: v1

kind: ConfigMap

metadata:

name: {{ .Release.Name }}-configmap

# 在此处引用定义的模板语句块

{{- template "mychart.labels" }}

# 渲染后的结果

---

apiVersion: v1

kind: ConfigMap

metadata:

name: running-panda-configmap

labels:

generator: helm

date: 2016-11-02

include使用apiVersion: v1

kind: ConfigMap

metadata:

name: {{ .Release.Name }}-configmap

labels:

{{ include "mychart.app" . | indent 4 }} # include将模板内容作为输入流,传递给indent函数。

data:

myvalue: "Hello World"

{{- range $key, $val := .Values.favorite }}

{{ $key }}: {{ $val | quote }}

{{- end }}

{{ include "mychart.app" . | indent 2 }}

Helm语法

Helm基于yaml语法拓展了自己的语法糖,这些语法糖基本都是从Go中拓展出来的,本节将介绍这些拓展的Helm语法糖。 Helm支持yaml的所有语法,关于yaml语法介绍,我在另一篇文章中有介绍:《Yaml语法(语法+数据结构+多语言对比案例)》。

基础语法

Helm客户端是Go语言编写的,Helm从Go语言中导出了很多同名方法供我们使用,这些方法在helm模板中使用时,需要将首字母转换为小写。比如:Go语言中的Base方法,在helm中为base。

1. 点.

表示当前作用域。一般情况下,当前作用域就是根作用域。 如:.Values就是告诉模板在当前作用域(根作用域)查找Values对象。

2. 对象引用到模板中

语法:{{ .Release.Name }}

3. 变量定义和赋值

变量名:以$为前缀,$relname。 赋值运算符::=

# 定义变量

{{- $relname := .Release.Name -}}

# 引用变量

{{ $relname }} # 不需要带 .

4. 管道符 |

同linux管道符用法,将|左侧的值作为标准输入流传给|右侧的指令。

5. 控制空白 - {{- -}}语法

Yaml认为空白是有意义的。进行模板渲染时,删除的分支语句会留下空白字符,以保持原样。 使用{{- -}}语法可以消除留下的空白。{{-表示去掉左边的空白字符,-}}表示去掉右边的空白字符,-与中间内容之间必须有空格。左右-可以同时使用,也可以单独使用。 可以通过helm template命令来渲染模板,查看模板渲染结果。这在自测中非常实用。

5.1:生成空白字符示例

# 原始模板

---

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: telling-chimp-configmap

data:

myvalue: "Hello World"

drink: "coffee"

food: "PIZZA"

mug: "true"

注意:渲染后的模板出现了空行。是因为模板引擎移除了{{ if eq .Values.favorite.drink "coffee" }},但是留下了空白字符以保持原样。

5.2:使用{{- -}}语法语法后

# 原始模板 -

---

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: telling-chimp-configmap

data:

myvalue: "Hello World"

drink: "coffee"

food: "PIZZA"

mug: "true"

5.3:错误使用-示例

food: {{ .Values.favorite.food | upper | quote }}

{{- if eq .Values.favorite.drink "coffee" -}}

mug: "true"

{{- end -}}

# 结果:food: "PIZZA"mug:"true"。因为两边的新行都被删除了。

高级函数

default:设置默认值。 require:判断参数取值。 coalesce:返回args中第一个非空值。 ternary:三元运算符。 fail:抛出错误error。

1. 设置默认值 default

# 设置默认值。如果.Bar为空,则赋值为"foo"。

default "foo" .Bar

{{- $relname := (default "foo" .Bar) -}}

2. 指定值 require

# .Bar值必须设置为 "A valid foo is required!",否则,抛出异常

required "A valid foo is required!" .Bar

3. 返回第一个非空值 coalesce

coalesce 0 1 2 # 返回 1

coalesce .name .parent.name "Matt" # 若.name .parent.name都为空,则返回 "Matt"。

4. 三元运算 ternary

# 格式1: ternary "first" "second" 布尔值

# 如果 布尔值 为 true, 则取第一个值。反之,取第二个值。

---

ternary "foo" "bar" true # "foo"

ternary "foo" "bar" false # "bar"

---

# 格式 2:使用管道符

true | ternary "foo" "bar" # "foo"

5. 异常处理 fail

# 返回空值并抛出异常信息

fail "Please accept the end user license agreement"

逻辑运算

高级比较方法:not、eq、ne、lt、gt、ge、le、and、or、empty。 基础比较符:=、!=、>、<、>=、<=。 空值类型:0、""、[]、{}、false、nil、null

---

not .Arg # 布尔否定

and .Arg1 .Arg2 .Arg3 # 返回.Arg1 and .Arg2 and .Arg3的布尔运算结果

or .Arg1 .Arg2 .Arg3 # .Arg1 or .Arg2 or .Arg3

eq .Arg1 .Arg2 # Arg1 == Arg2

ne .Arg1 .Arg2 # Arg1 != Arg2

# 以此类推,le: <=, gt: >, ge: >=

---

# 如果 .Foo 为空,返回 true。

empty .Foo

---

# 应用到 if 语句中

{{- if eq .Chart.Name "mychart" -}}

dosomething: true

{{- end}}

流程控制

1. 分支结构 if/else 空值类型:false、0、""、nil、空集合(map, slice, tuple, dict, array)

# 基础语法结构

---

{{ if PIPELINE }}

# Do something

{{ else if OTHER PIPELINE }}

# Do something else

{{ else }}

# Default case

{{ end }}

# demo

---

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

2. 控制作用域 with with修改当前作用域为PIPELINE域,且只有当PIPELINE不为空时,才会执行with语句块。

# 基础语法结构

{{ with PIPELINE }}

# restricted scope # 同if类似,PIPELINE不为空时才执行。

{{ end }}

我们通过.引用当前作用域对象。当前作用域被修改后就不能再通过.引用根作用域的对象了,否则会报错。比如,{{ .Release.Name }}会报错,原因是Release.Name不在.表示的作用域了。

{{- with .Values.favorite }} # 当前作用域 '.' 被设置为 .Values.favorite。

drink: {{ .drink | default "tea" | quote }} # .drink在根作用域的路径:.Values.favorite.drink。

food: {{ .food | upper | quote }}

release: {{ .Release.Name }} # 此处调用会报错,因为当前作用域'.'已经是.Values.favorite。

{{- end }}

release: {{ .Release.Name }} # with语句块结束后,会将当前作用域重置为父作用域'$'。

不过,我们可以通过当前作用域的父作用域$来访问根作用域对象。比如,{{ $.Release.Name }}。

{{- with .Values.favorite }}

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

food: {{ .food | upper | quote }}

release: {{ $.Release.Name }}

{{- end }}

3. 循环语句 range 类似其他语言的foreach循环

Demo1:把pizzaToppings列表打印到配置映射中

# 定义披萨的配料列表 pizzaToppings

---

favorite:

drink: coffee

food: pizza

pizzaToppings:

- mushrooms

- cheese

- peppers

- onions

# 原始模板

---

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 }} # 在with语句中,$表示根作用域。

- {{ . | title | quote }} # '.'表示迭代元素。

{{- end }}

{{- end }}

# 渲染后的结果

---

apiVersion: v1

kind: ConfigMap

metadata:

name: edgy-dragonfly-configmap

data:

myvalue: "Hello World"

drink: "coffee"

food: "PIZZA"

toppings: |-

- "Mushrooms"

- "Cheese"

- "Peppers"

- "Onions"

Demo2:使用tuple快速创建列表。 类似的,还有map和dict。

# 原始定义模板

---

sizes: |-

{{- range tuple "small" "medium" "large" }}

- {{ . }}

{{- end }}

# 渲染后结果

---

sizes: |-

- small

- medium

- large

文件操作

类似于linux的basename、dirname方法 1. 操作文件路径

# 返回最后一个元素路径

base "foo/bar/baz" # "baz"

# 返回目录

dir "foo/bar/baz" # foo/bar

# 返回文件拓展名

ext "foo.bar" # .bar

# 判断是否为绝对路径

isAbs "foo/bar/baz" # false

2. 读取文件内容

内置对象Files 无法访问templates/下的文件、.helmignore排除的文件。

示例1:文件常规读取

在mychart/目录下创建三个文件:config1.toml、config2.toml、config3.toml,然后依次在其中添加config1 = c1、config2 = c2、config3 = c3。

# Source: mychart/templates/myconfigmap.yaml

---

apiVersion: v1

kind: ConfigMap

metadata:

name: {{ .Release.Name }}-configmap

data:

{{- $files := .Files }}

{{- range tuple "config1.toml" "config2.toml" "config3.toml" }}

{{ . }}: |-

{{ $files.Get . }}

{{- end }}

...

# 模板渲染后的结果

---

apiVersion: v1

kind: ConfigMap

metadata:

name: quieting-giraf-configmap

data:

config1.toml: |-

config1 = c1

config2.toml: |-

config2 = c2

config3.toml: |-

config2 = c3

示例2:通过Glob表达式**/foo*.yaml匹配文件

---

{{ $currentScope := .}}

{{ range $path, $_ := .Files.Glob "**/foo*.yaml" }}

{{- with $currentScope}}

{{ .Files.Get $path }}

{{- end }}

{{ end }}

---

{{ range $path, $_ := .Files.Glob "**/foo*.yaml" }}

{{ $.Files.Get $path }}

{{ end }}

更多的文件读取方式:https://helm.sh/docs/chart_template_guide/accessing_files/

字符串操作

包含: 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, and wrapWith。

常用字符串方法介绍 1 打印 print println printf

# 非字符串类型会被转换成字符串,当相邻两个参数不是字符串时会在它们之间添加一个空格

# println: 和print效果一样,但会在末尾新添加一行

print "Matt has " .Dogs " dogs"

# 带格式打印 占位符:%s和%d

printf "%s has %d dogs." .Name .NumberDogs

2 删除空白字符

# 移除两边的空白字符

trim " hello " # "hello"

# 删除所有空白字符

nospace "hello w o r l d"

# 移除所有指定字符

trimAll "$" "$5.00" # "5.00"

3 截取字符串

# 移除前缀

trimPrefix "pre-" "pre-hello" # hello

# 移除后缀

trimSuffix "-suf" "hello-suf" # hello

# 截取字符串

trunc 5 "hello world" # hello 截取前五个字符串

trunc -5 "hello world" # world 截取后五个字符串

# 用...截取字符串,...算入字符串长度。

abbrev 5 "hello world" # he...

4 转大/小写

lower "HELLO" # hello

upper "hello" # HELLO

title "hello world" # "Hello World"

untitle "Hello World" # "hello world"

5 字符串切片 叠加

# 字符串切片

substr 0 5 "hello world" # hello

# 重复叠加字符串

repeat 3 "hello" # hellohellohello

6 替换字符串

# 将空格替换为 -

"I Am Henry VIII" | replace " " "-"

7 判断字符串包含关系

# 判断字符串是否包含 -- true/false

contains "cat" "catch" # true 第一个字符串是否在第二个字符串中

# 判断字符串前缀/后缀 -- true/false

hasPrefix "cat" "catch" # true 第一个字符串是否是第二个字符串的前缀

8 字符串处理

# 给字符串包裹双引号或者单引号

quote eat # "eat"

squote eat # 'eat'

# 添加缩进

indent 4 $lots_of_text # 将$lots_of_text文本的每行字符缩进 4 个空格

nindent 4 $lots_of_text # 在indent基础上,在$lots_of_text文本前面新增一行空行。

9 生成安全随机字符串 语法格式:functionName

# 四种生成随机数方法,生成的随机数类型不同。

randAlphaNum # 生成[0-9a-zA-Z]字母数字混合随机字符串

randAlpha # 生成[a-zA-Z]字母随机字符串

randNumeric # 生成[0-9]的数字随机字符串

randAscii # 所有可打印的ASCII随机字符串

# 举例

randAlphaNum 5 # 生成5位 字母与数字混合的随机字符串 如:"ad3d6"。

10 合并字符串

cat "hello" "beautiful" "world" # "hello beautiful world"

数学运算

整形: add, sub, mul, div, mod, max, min, len 浮点型: addf, subf, mul, divf, maxf, minf, floor, ceil, round,。 1 整形

# 相加

add 1 2 3 # 1+2+3

# 相减

sub 10 1 5 # 10-1-5

# 乘

mul 1 2 3

# 整除

div 10 2 4 # 10/2/4

# 取模

mod 10 3

# 取最大值

max 1 2 3

# 取最小值

min 1 2 3 # 1

# 参数长度

len .Arg

2 浮点型

# 返回小于等于输入值的最大浮点整数

floor 123.9999 # 123.0

# 返回大于等于输入值的最小浮点整数

ceil 123.001 # 124.0

# 返回一个四舍五入到给定小数位的数

round 123.555555 3 # 123.556

类型转换

查看值类型 typeOf:返回值的基础类型,typeOf $foo

1 toJson toYaml

# Convert a list, slice, or array to a list of strings.

list 1 2 3 | toStrings # "1" "2" "3"

# Convert list, slice, array, dict, or object to JSON

toJson .Item

# Convert list, slice, array, dict, or object to indented yaml, can be used to copy chunks of yaml from any source

toYaml .Item

2 fromJson

# Source jsons/person.json

{

"name": "Bob",

"age": 25,

"hobbies": [

"hiking",

"fishing",

"cooking"

]

}

{{- $person := .Files.Get "jsons/person.json" | fromJson }}

greeting: |

Hi, my name is {{ $person.name }} and I am {{ $person.age }} years old.

My hobbies are {{ range $person.hobbies }}{{ . }} {{ end }}.

3 fromYaml

# Source jsons/person.yaml

name: Bob

age: 25

hobbies:

- hiking

- fishing

- cooking

{{- $person := .Files.Get "yamls/person.yaml" | fromYaml }}

greeting: |

Hi, my name is {{ $person.name }} and I am {{ $person.age }} years old.

My hobbies are {{ range $person.hobbies }}{{ . }} {{ end }}.

实例解读 _helpers.tpl

_helpers.tpl文件时定义Chart模板的结构文件,文中定义的模板语句块可以被其他文件引用。引用方式在前面命名模板章节已经介绍过。

使用helm create mychart时自动生成的文件内容入下:

{{/*

Expand the name of the chart.

*/}}

{{- define "mychart.name" -}} # 此处定义了一个名为"mychart.name"的模板。

# 模板内容:若.Values.nameOverride为空,则取.Chart.Name的值,截取其前63个字符,然后裁剪掉后缀-。

{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}

{{- end }}

{{/*

Create a default fully qualified app name.

We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).

If release name contains chart name it will be used as a full name.

*/}}

{{- define "mychart.fullname" -}} # 此处定义了一个名为"mychart.fullname"的模板。

{{- if .Values.fullnameOverride }}

# 模板内容:将.Values.fullnameOverride的值截取其前63个字符,然后裁剪掉后缀-。

{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}

{{- else }}

# 模板内容:将(default .Chart.Name .Values.nameOverride)的内容赋值给变量$name。

{{- $name := default .Chart.Name .Values.nameOverride }}

{{- if contains $name .Release.Name }} # 判断$name是否包含在.Release.Name中。

{{- .Release.Name | trunc 63 | trimSuffix "-" }}

{{- else }}

# 格式化.Release.Name $name的内容,然后截取63个字符,去除后缀-

{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}

{{- end }}

{{- end }}

{{- end }}

{{/*

Create chart name and version as used by the chart label.

*/}}

{{- define "mychart.chart" -}}

# replace: 将+替换成-

{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}

{{- end }}

{{/*

Common labels

*/}}

{{- define "mychart.labels" -}}

helm.sh/chart: {{ include "mychart.chart" . }} # 引入"mychart.chart"模板内容

{{ include "mychart.selectorLabels" . }}

{{- if .Chart.AppVersion }}

app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}

{{- end }}

app.kubernetes.io/managed-by: {{ .Release.Service }}

{{- end }}

{{/*

Selector labels

*/}}

{{- define "mychart.selectorLabels" -}}

app.kubernetes.io/name: {{ include "mychart.name" . }}

app.kubernetes.io/instance: {{ .Release.Name }}

{{- end }}

{{/*

Create the name of the service account to use

*/}}

{{- define "mychart.serviceAccountName" -}}

{{- if .Values.serviceAccount.create }}

{{- default (include "mychart.fullname" .) .Values.serviceAccount.name }}

{{- else }}

{{- default "default" .Values.serviceAccount.name }}

{{- end }}

{{- end }}

k8s深度结合Helm的使用方法,参见我的另一篇文章《k8s结合helm企业级案例》。

精彩内容

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: