# Helm Chart & template 函数
# Helm Chart
Chart 是 helm 管理应用的包, 一个Chart对应一个或一套应用. Chart 内部由YAML描述文件组成.
---
## Chart 目录结构
* `Chart.yaml` : chart 的描述文件, 包含版本信息, 名称 等.
* `Chart.lock` : chart 依赖的版本信息. ( apiVersion: v2 )
* `values.yaml` : 用于配置 `templates/` 目录下的模板文件使用的变量.
* `values.schema.json` : 用于校检 `values.yaml` 的完整性.
* `charts` : 依赖包的存储目录.
* `README` : 说明文件.
* `LICENSE` : 版权信息文件.
* `crd` : 存放 CRD 资源的文件的目录.
* `templates` : 模板文件存放目录.
* `NOTES.txt` : 模板须知/说明文件. `helm install ` 成功后会显示此文件内容到屏幕.
* `deployment.yaml` : kubernetes 资源文件. ( 所有类型的 kubernetes 资源文件都存放于 templates 目录下 )
* `_helpers.tpl` : 以 `_` 开头的文件, 可以被其他模板引用.
---
### Chart.yaml 文件
> Chart 的描述文件, 包含版本信息, Chart 名称,说明等.
* 这里仅说明 `apiVersion v2 版本`
```yaml
# Helm api 版本 (必填)
apiVersion: v2
# Chart 的名称 (必填)
name: myapp
# 此 Chart 的版本 (必填)
version: v1.0
# 约束此 Chart 支持的 kubernetes 版本, 如果不支持会失败 (可选)
kubeVersion: >= 1.18.0
# 此 Chart 说明信息 (可选)
description: "My App"
# Chart 的应用类型, 分别为 application (默认)和 library. (可选)
type: application
# Chart 关键词, 用于搜索时使用 (可选)
keywords
- app
- myapp
# Chart 的 home 的地址 (可选)
home: https://jicki.cn
# Chart 的源码地址 (可选)
sources:
- https://github.com/jicki
- https://jicki.cn
# Chart 的依赖信息, helm v2 是在 requirements.yaml 中. (可选)
dependencies:
# 依赖的 chart 名称
- name: nginx
# 依赖的版本
version: 1.2.3
# 依赖的 repo 地址
repository: https://kubernetes-charts.storage.googleapis.com
# 依赖的 条件 如 nginx 启动
condition: nginx.enabled
# 依赖的标签 tags
tags:
- myapp-web
- nginx-slb
enabled: true
# 传递值到 Chart 中.
import-values:
- child:
- parent:
# 依赖的 别名
alias: nginx-slb
# Chart 维护人员信息 (可选)
maintainers:
- name: 小炒肉
email: jicki@qq.com
url: https://jicki.cn
# icon 地址 (可选)
icon: "https://jicki.cn/images/favicon.ico"
# App 的版本 (可选)
appVersion: 1.19.2
# 标注是否为过期 (可选)
deprecated: false
# 注释 (可选)
annotations:
# 注释的例子
example:
```
---
## Helm 内置变量
* Helm 内置对象包含
* `Release` 相关的内置属性.
* `Chart` 属性 - `Chart.yaml` 文件中定义的内容.
* `Values` 属性 - `Values.yaml` 文件中定义的内容.
---
### Release 内置变量
* `Release` 内置变量
| 变量名称 | 变量说明 |
|--------------------|-------------------------------------------------------|
| Release.Name | release 名称 |
| Release.Namespace | release 所在命名空间 |
| Release.Service | release 发布的服务 |
| Release.IsUpgrade | 如果 release 操作状态为 更新 / 回滚 , 此变量值为 true |
| Release.IsInstall | 如果 release 操作状态为 安装 , 此变量值为 true |
| Release.Revision | release 版本序号, 初始为 1 , 执行 更新/ 回滚 版本 +1 |
---
## Helm 模板函数
* Helm 的模板语法使用Golang 语言的 template 模块.
* 参考: https://jicki.cn/golang-study-note-8/#template-%E8%AF%AD%E6%B3%95
---
注: 所有函数中 函数名称前面带: `must` 如: mustxxx 的函数,指定出错不会 panic , 而是会输出 错误.
---
### 比较函数
>
比较函数
| 函数 | 含义 |
| ---- | ------------------------- |
| eq | 如果 arg1 == arg2 返回 真 |
| ne | 如果 arg1 != arg2 返回 真 |
| lt | 如果 arg1 < arg2 返回 真 |
| le | 如果 arg1 <= arg2 返回 真 |
| gt | 如果 arg1 > arg2 返回 真 |
| ge | 如果 arg1 >= arg2 返回 真 |
---
### 特殊字符
> `-` 区别
---
* `{{ }}` 左右两边都没有 `-` 的情况
* 如果上下两边都有 元素, 会空一行. 效果如下:
```yaml
split: {{ "=============" }}
{{ if true }}
name: {{ "hello world" }}
{{ end }}
split: {{ "=============" }}
```
* 运行 template
```shell
root@kubernetes:/opt/helm/myapp# helm template . --show-only templates/name.yaml
---
# Source: myapp/templates/name.yaml
split: =============
name: hello world
split: =============
```
---
* `{{ }}` 左边包含 `-` 的情况
* 如果上下两边都有 元素, 直接输出不会有空行. 效果如下:
```yaml
split: {{ "=============" }}
{{- if true }}
name: {{ "hello world" }}
{{- end }}
split: {{ "=============" }}
```
* 运行 template
```shell
root@kubernetes:/opt/helm/myapp# helm template . --show-only templates/name.yaml
---
# Source: myapp/templates/name.yaml
split: =============
name: hello world
split: =============
```
---
* `{{ }}` 左右两边都包含 `-` 的情况
* 如果上下两边都有 元素, 会输出到上面一行后面. 效果如下:
* 注: 这种情况会有 `mapping values are not allowed in this context` 格式的错误, 特别注意 左右都包含 `-` 的情况.
```yaml
split: {{ "=============" }}
{{- if true -}}
name
{{- end -}}
```
* 运行 template
```shell
root@kubernetes:/opt/helm/myapp# helm template . --show-only templates/name.yaml
---
# Source: myapp/templates/name.yaml
split: =============name
```
---
> `|` 、 `|-` 、 `|+` 、 `>` 区别
* `|`
* 每一列转换到 json 后 无论多少个空行有且仅有一个 `\n` 符.
```yaml
A: |
aa
bb
cc
```
* 转换成 Json
```json
{
"A": "aa\nbb\ncc\n"
}
```
---
* `|-`
* 每一列转换到 json 后 除最后一行外 每个空行都有一个 `\n` 符.
```yaml
A: |-
aa
bb
cc
```
* 转换成 Json
```json
{
"A": "aa\n\nbb\ncc"
}
```
---
* `|+`
* 每一列转换到 json 后 每一个空行都有一个 `\n` 符.
```yaml
A: |+
aa
bb
cc
```
* 转换成 Json
```json
{
"A": "aa\nbb\n\ncc\n\n"
}
```
---
* `>`
* 每一列转换到 json 后 没有 `\n` 符.
```yaml
A: >
aa
bb
cc
```
* 转换成 Json
```json
{
"A": "aa bb cc"
}
```
---
### 流程控制
> 模板函数 之 流程控制
* `values.yaml` 文件内容如下
```yaml
favorite:
game: LOL
drink: coffee
like:
- football
- basketball
- volleyball
- doubleball
global:
service: web
image:
repository: jicki/myapp
tag: 'v2'
hostsPort:
http: 80
https: 443
containerPort:
http: 80
https: 443
```
---
> if / else 条件控制
* `if` / `else` 条件控制
* `templates/if.yaml` 文件, 模板语法使用 go语言 template 语法
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "hello world"
{{- if eq .Values.favorite.game "LOL" }}
msg: "Good Game"
{{- else }}
msg: "Null"
{{- end }}
```
* 查看 template
```shell
root@kubernetes:/opt/helm/myapp# helm template . --show-only templates/if.yaml
---
# Source: myapp/templates/if.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: RELEASE-NAME-configmap
data:
myvalue: "hello world"
msg: "Good Game"
```
---
> with 范围控制
* `with` 范围控制, 加载范围主体为当前'.' , 后续通过 `.game | .drink` 直接调用
* `templates/with.yaml` 文件内容
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "hello world"
{{- with .Values.favorite }}
# default 设置默认值. quote 是加上引号
game: {{ .game | default "King" | quote }}
# upper 将输出转换为 大写. quote 是加上引号
drink: {{ .drink | upper | quote }}
{{- end }}
```
* 查看 template
```shell
root@kubernetes:/opt/helm/myapp# helm template . --show-only templates/with.yaml
---
# Source: myapp/templates/with.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: RELEASE-NAME-configmap
data:
myvalue: "hello world"
game: "LOL"
drink: "COFFEE"
```
---
> range 循环控制
* `range` 循环控制
* `templates/range.yaml` 文件内容
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "hello world"
like: |-
# 遍历 数组
{{- range .Values.like }}
- {{ . }}
{{- end }}
# 遍历 map
{{- range $key, $val := .Values.favorite }}
{{ $key }} = {{ $val | quote }}
{{- end }}
```
* 查看 template
```shell
root@kubernetes:/opt/helm/myapp# helm template . --show-only templates/range.yaml
---
# Source: myapp/templates/range.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: RELEASE-NAME-configmap
data:
myvalue: "hello world"
like: |-
# 遍历 数组
- football
- basketball
- volleyball
- doubleball
# 遍历 map
drink = "coffee"
game = "LOL"
```
---
### 内置函数
> Go 语言函数
| 函数 | 含义 |
| ------- | ----------------------------------------------------- |
| and | 函数返回它的第一个 empty 参数或者最后一个参数 |
| or | 函数返回它的第一个非 empty 参数或者最后一个参数 |
| not | 函数返回它的单个参数的布尔值是否定 |
| len | 函数返回它的参数的整数类型长度 |
| index | 函数执行结果为第一个参数以剩下的参数为索引/键指向的值 |
| html | 函数返回其参数文本表示的 html 逸码等价表示 |
| js | 函数返回其参数文本表示的 JavaScrpit 逸码等价表示 |
| slice | 函数返回值为 slice 中的选定项 |
| print | 既 Go 语言中 fmt.Sprint |
| printf | 既 Go 语言中 fmt.Sprintf |
| println | 既 Go 语言中 fmt.Sprintln |
| urlquery| 函数返回其参数文本表示可嵌入URL查询的逸码等价表示 |
---
> and 函数
* `and` 函数
* `templates/and.yaml` 文件内容
```yaml
# 如果 5 大于 1 and 3 小于等于 10
{{- if and (gt 5 1 ) (le 3 10) }}
msg: true
{{- else }}
msg: false
{{- end }}
```
* 运行 template
```shell
root@kubernetes:/opt/helm/myapp# helm template . --show-only templates/and.yaml
---
# Source: myapp/templates/and.yaml
# 如果 5 大于 1 and 3 小于等于 10
msg: true
```
---
> or 函数
* `or` 函数
* `templates/or.yaml` 文件内容
```yaml
# 判断 1 大于 2 或 1 小于 2 返回为 true
{{- if or (gt 1 2 ) (le 1 2) }}
msg: true
{{- else }}
msg: false
{{- end }}
```
* 运行 template
```shell
root@kubernetes:/opt/helm/myapp# helm template . --show-only templates/or.yaml
---
# Source: myapp/templates/or.yaml
# 判断 1 大于 2 或 1 小于 2 返回为 true
msg: true
```
---
> not 函数
* `not` 函数
* `templates/not.yaml` 文件内容
```yaml
# 判断 如果 1 大于 2 返回 false 取非 为 true
{{- if not (gt 1 2 ) }}
msg: true
{{- end}}
```
* 运行 template
```shell
root@kubernetes:/opt/helm/myapp# helm template . --show-only templates/not.yaml
---
# Source: myapp/templates/not.yaml
# 判断 如果 1 大于 2 返回 false 取非 为 true
msg: true
```
---
> len 函数
* `len` 函数
* `templates/len.yaml` 文件内容
```yaml
service: {{ .Values.global.service }}
len: {{ len .Values.global.service }}
```
* 运行 template
```shell
root@kubernetes:/opt/helm/myapp# helm template . --show-only templates/len.yaml
---
# Source: myapp/templates/len.yaml
service: web
len: 3
```
---
> index 函数
* `index` 函数
* `templates/index.yaml` 文件内容
```yaml
# 定义一个变量 hostsPort
{{- $hostsPort := .Values.hostsPort -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "hello world"
# 遍历 containerPort 的 k,v 值
{{- range $name, $val := .Values.containerPort }}
# $name 变量取值为 $hostsPort 中 $name 变量的值
{{ $name }}: {{ index $hostsPort $name | default $val }}
{{- end }}
```
* 运行 template
```shell
root@kubernetes:/opt/helm/myapp# helm template . --show-only templates/index.yaml
---
# Source: myapp/templates/index.yaml
# 定义一个变量 hostsPort
apiVersion: v1
kind: ConfigMap
metadata:
name: RELEASE-NAME-configmap
data:
myvalue: "hello world"
http: 80
https: 443
```
---
> html 函数
* `html` 函数
* `templates/html.yaml` 文件内容
```yaml
html: |
{{ html "Title" }}
```
* 运行 template
```shell
root@kubernetes:/opt/helm/myapp# helm template . --show-only templates/html.yaml
---
# Source: myapp/templates/html.yaml
html: |
<html><head><title>Title</title></head></html>
```
---
> js 函数
* `js` 函数
* `templates/js.yaml` 文件内容
```yaml
js: {{ js "