Helm 從入門到專家
作者:liugp
出處:https://u.kubeinfo.cn/28oCWV
一、概述
我們可以將 Helm 看作 Kubernetes 下的 apt-get/yum。Helm 是 kubernetes 的包管理器,helm 倉庫裏面只有配置清單文件, 而沒有鏡像, 鏡像還是由鏡像倉庫來提供, 比如 hub.docker.com、私有倉庫。
官方文檔:
https://v3.helm.sh/zh/docs/
二、Helm 架構
三、Helm 安裝
下載地址:
https://github.com/helm/helm/releases
# 下載包
$ wget https://get.helm.sh/helm-v3.9.4-linux-amd64.tar.gz
# 解壓壓縮包
$ tar -xf helm-v3.9.4-linux-amd64.tar.gz
# 製作軟連接
$ ln -s /opt/helm/linux-amd64/helm /usr/local/bin/helm
# 驗證
$ helm version
$ helm help
四、Helm 組件及相關術語
-
Helm
——Helm 是一個命令行下的客戶端工具。主要用於 Kubernetes 應用程序 Chart 的創建、打包、發佈以及創建和管理本地和遠程的 Chart 倉庫。 -
Chart
——Chart 代表着 Helm 包。它包含在 Kubernetes 集羣內部運行應用程序,工具或服務所需的所有資源定義。你可以把它看作是 Homebrew formula,Apt dpkg,或 Yum RPM 在 Kubernetes 中的等價物。 -
Release
——Release 是運行在 Kubernetes 集羣中的 chart 的實例。一個 chart 通常可以在同一個集羣中安裝多次。每一次安裝都會創建一個新的 release。 -
Repoistory
——Repository(倉庫) 是用來存放和共享 charts 的地方。它就像 Perl 的 CPAN 檔案庫網絡 或是 Fedora 的 軟件包倉庫,只不過它是供 Kubernetes 包所使用的。
五、Helm Chart 詳解
1)Chart 目錄結構
# 通過helm create命令創建一個新的chart包
helm create nginx
tree nginx
nginx/
├── charts #依賴其他包的charts文件
├── Chart.yaml # 該chart的描述文件,包括ico地址,版本信息等
├── templates # #存放k8s模板文件目錄
│ ├── deployment.yaml # 創建k8s資源的yaml 模板
│ ├── _helpers.tpl # 下劃線開頭的文件,可以被其他模板引用
│ ├── hpa.yaml # 彈性擴縮容,配置服務資源CPU 內存
│ ├── ingress.yaml # ingress 配合service域名訪問的配置
│ ├── NOTES.txt # 說明文件,helm install之後展示給用戶看的內容
│ ├── serviceaccount.yaml # 服務賬號配置
│ ├── service.yaml # kubernetes Serivce yaml 模板
│ └── tests # 測試模塊
│ └── test-connection.yaml
└── values.yaml # 給模板文件使用的變量
可能有寫包還會有以下幾個目錄:
wordpress/
...
LICENSE # 可選: 包含chart許可證的純文本文件
README.md # 可選: 可讀的README文件
values.schema.json # 可選: 一個使用JSON結構的values.yaml文件
charts/ # 包含chart依賴的其他chart
crds/ # 自定義資源的定義
...
2)Chart.yaml 文件
apiVersion: chart API 版本 (必需)
name: chart名稱 (必需)
version: chart 版本,語義化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: 按名稱輸入的批註列表 (可選).
-
從 v3.3.2,不再允許額外的字段。推薦的方法是在
annotations
中添加自定義元數據。 -
每個 chart 都必須有個版本號(
version
)。版本必須遵循 語義化版本 2 標準。不像經典 Helm, Helm v2 以及後續版本會使用版本號作爲發佈標記。倉庫中的包通過名稱加版本號標識。
比如 nginx chart 的版本字段 version: 1.2.3 按照名稱被設置爲:
nginx-1.2.3.tgz
【溫馨提示】
appVersion
字段與version
字段並不相關。這是指定應用版本的一種方式。比如,這個 drupal chart 可能有一個 appVersion: "8.2.1",表示包含在 chart(默認)的 Drupal 的版本是 8.2.1。
3)Chart 依賴管理(dependencies)
當前 chart 依賴的其他 chart 會在 dependencies 字段定義爲一個列表。
dependencies:
- name: apache
version: 1.2.3
repository: https://example.com/charts
- name: mysql
version: 3.2.1
repository: https://another.example.com/charts
-
name 字段是你需要的 chart 的名稱
-
version 字段是你需要的 chart 的版本
-
repository 字段是 chart 倉庫的完整 URL。注意你必須使用 helm repo add 在本地添加倉庫
-
你可以使用倉庫的名稱代替 URL
示例演示:
helm repo add bitnami https://charts.bitnami.com/bitnami
helm pull bitnami/wordpress
tar -xf wordpress
cat wordpress/Chart.yaml
一旦你定義好了依賴,運行 helm dependency update
就會使用你的依賴文件下載所有你指定的 chart 到你的 charts / 目錄。
helm dependency update ./wordpress
當 helm dependency update 拉取 chart 時,會在 charts / 目錄中形成一個 chart 包。因此對於上面的示例,會在 chart 目錄中期望看到以下文件:
wordpress/charts/
├── common
├── common-2.0.1.tgz
├── mariadb
├── mariadb-11.2.2.tgz
├── memcached
└── memcached-6.2.3.tgz
依賴中的 tag 和條件字段
除了上面的其他字段外,每個需求項可以包含可選字段
tags
和condition
。所有的 chart 會默認加載。如果存在 tags 或者 condition 字段,它們將被評估並用於控制它們應用的 chart 的加載。
-
Condition
——條件字段 field 包含一個或多個 YAML 路徑(用逗號分隔)。如果這個路徑在上層 values 中已存在並解析爲布爾值,chart 會基於布爾值啓用或禁用 chart。只會使用列表中找到的第一個有效路徑,如果路徑爲未找到則條件無效。 -
Tags
——tag
字段是與 chart 關聯的 YAML 格式的標籤列表。在頂層 value 中,通過指定 tag 和布爾值,可以啓用或禁用所有的帶 tag 的 chart。
# parentchart/Chart.yaml
dependencies:
- name: subchart1
repository: http://localhost:10191
version: 0.1.0
condition: subchart1.enabled, global.subchart1.enabled
tags:
- front-end
- subchart1
- name: subchart2
repository: http://localhost:10191
version: 0.1.0
condition: subchart2.enabled,global.subchart2.enabled
tags:
- back-end
- subchart2
# parentchart/values.yaml
subchart1:
enabled: true
tags:
front-end: false
back-end: true
-
在上面的例子中,所有帶 front-end tag 的 chart 都會被禁用,但只要上層的 value 中
subchart1.enabled
路徑被設置爲'true'
,該條件會覆蓋 front-end 標籤且 subchart1 會被啓用。 -
一旦 subchart2 使用了 back-end 標籤並被設置爲了 true,subchart2 就會被啓用。也要注意儘管 subchart2 指定了一個條件字段, 但是上層 value 沒有相應的路徑和 value,因此這個條件不會生效。
--set
參數可以用來設置標籤和條件值。
helm install --set tags.front-end=true --set subchart2.enabled=false
標籤和條件的解析:
-
條件 (當設置在 value 中時)總是會覆蓋標籤 第一個 chart 條件路徑存在時會忽略後面的路徑。
-
標籤被定義爲 '如果任意的 chart 標籤是 true,chart 就可以啓用'。
-
標籤和條件值必須被設置在頂層 value 中。
-
value 中的 tags: 鍵必須是頂層鍵。
4)通過依賴導入子 Value
-
在某些情況下,允許子 chart 的值作爲公共默認傳遞到父 chart 中是值得的。使用
exports
格式的額外好處是它可是將來的工具可以自檢用戶可設置的值。 -
被導入的包含值的 key 可以在父 chart 的 dependencies 中的
import-values
字段以 YAML 列表形式指定。列表中的每一項是從子 chart 中 exports 字段導入的 key。 -
導入 exports key 中未包含的值,使用 子 - 父格式。兩種格式的示例如下所述。
使用導出格式:
如果子 chart 的 values.yaml 文件中在根節點包含了 exports 字段,它的內容可以通過指定的可以被直接導入到父 chart 的 value 中, 如下所示:
# parent's Chart.yaml file
dependencies:
- name: subchart
repository: http://localhost:10191
version: 0.1.0
import-values:
- data
# child's values.yaml file
exports:
data:
myint: 99
只要我們再導入列表中指定了鍵 data,Helm 就會在子 chart 的 exports 字段查找 data 鍵並導入它的內容。
最終的父級 value 會包含我們的導出字段:
# parent's values
myint: 99
【注意】父級鍵 data 沒有包含在父級最終的 value 中,如果想指定這個父級鍵,要使用
'子-父' 格式
。
下面示例中的import-values
指示 Helm 去拿到能再 child: 路徑中找到的任何值,並拷貝到 parent: 的指定路徑。
# parent's Chart.yaml file
dependencies:
- name: subchart1
repository: http://localhost:10191
version: 0.1.0
...
import-values:
- child: default.data
parent: myimports
上面的例子中,在 subchart1 裏面找到的 default.data 的值會被導入到父 chart 的 myimports 鍵中,細節如下:
# parent's values.yaml file
myimports:
myint: 0
mybool: false
mystring: "helm rocks!"
# subchart1's values.yaml file
default:
data:
myint: 999
mybool: true
父 chart 的結果值將會是這樣:
# parent's final values
myimports:
myint: 999
mybool: true
mystring: "helm rocks!"
六、Templates and Values
1)Templates and Values 簡介
-
Helm Chart 模板是按照 Go 模板語言書寫, 增加了 50 個左右的附加模板函數 來自 Sprig 庫 和一些其他 指定的函數。
-
所有模板文件存儲在 chart 的
templates/
文件夾。當 Helm 渲染 chart 時,它會通過模板引擎遍歷目錄中的每個文件。
模板的 Value 通過兩種方式提供:
-
Chart 開發者可以在 chart 中提供一個命名爲
values.yaml
的文件。這個文件包含了默認值。 -
Chart 用戶可以提供一個包含了 value 的 YAML 文件。可以在命令行使用 helm install 命令時通過
-f
指定 value 文件。
模板示例
apiVersion: v1
kind: ReplicationController
metadata:
name: deis-database
namespace: deis
labels:
app.kubernetes.io/managed-by: deis
spec:
replicas: 1
selector:
app.kubernetes.io/name: deis-database
template:
metadata:
labels:
app.kubernetes.io/name: deis-database
spec:
serviceAccount: deis-database
containers:
- name: deis-database
image: {{ .Values.imageRegistry }}/postgres:{{ .Values.dockerTag }}
imagePullPolicy: {{ .Values.pullPolicy }}
ports:
- containerPort: 5432
env:
- name: DATABASE_STORAGE
value: {{ default "minio" .Values.storage }}
上面的例子,鬆散地基於
https://github.com/deis/charts
是一個 Kubernetes 副本控制器的模板。可以使用下面四種模板值(一般被定義在 values.yaml 文件):
-
imageRegistry: Docker 鏡像的源註冊表
-
dockerTag: Docker 鏡像的 tag
-
pullPolicy: Kubernetes 的拉取策略
-
storage: 後臺存儲,默認設置爲 "minio"
2)預定義的 Values
Values 通過模板中. Values 對象可訪問的 values.yaml 文件(或者通過 --set 參數) 提供, 但可以模板中訪問其他預定義的數據片段。
以下值是預定義的,對每個模板都有效,並且可以被覆蓋。和所有值一樣,名稱 區分大小寫。
-
Release.Name
: 版本名稱 (非 chart 的) -
Release.Namespace
: 發佈的 chart 版本的命名空間 -
Release.Service
: 組織版本的服務 -
Release.IsUpgrade
: 如果當前操作是升級或回滾,設置爲 true -
Release.IsInstall
: 如果當前操作是安裝,設置爲 true -
Chart
:Chart.yaml
的內容。因此,chart 的版本可以從 Chart.Version 獲得, 並且維護者在 Chart.Maintainers 裏。 -
Files
: chart 中的包含了非特殊文件的類圖對象。這將不允許您訪問模板, 但是可以訪問現有的其他文件(除非被. helmignore 排除在外)。使用 {{index .Files "file.name"}} 可以訪問文件或者使用 {{.Files.Get name }} 功能。您也可以使用 {{ .Files.GetBytes }} 作爲[]byte 訪問文件內容。 -
Capabilities
: 包含了 Kubernetes 版本信息的類圖對象。({{.Capabilities.KubeVersion}}) 和支持的 Kubernetes API 版本 ({{ .Capabilities.APIVersions.Has "batch/v1" }})
考慮到前面部分的模板,values.yaml
文件提供的必要值如下:
imageRegistry: "quay.io/deis"
dockerTag: "latest"
pullPolicy: "Always"
storage: "s3"
values 文件被定義爲 YAML 格式。chart 會包含一個默認的 values.yaml 文件。Helm 安裝命令允許用戶使用附加的 YAML values 覆蓋這個 values:
helm install --generate-name --values=myvals.yaml wordpress
3)範圍,依賴和值
Values 文件可以聲明頂級 chart 的值,以及charts/
目錄中包含的其他任意 chart。或者換個說法,values 文件可以爲 chart 及其任何依賴項提供值。比如,上面示範的 WordPress chart 同時有 mysql 和 apache 作爲依賴。values 文件可以爲以下所有這些組件提供依賴:
title: "My WordPress Site" # Sent to the WordPress template
mysql:
max_connections: 100 # Sent to MySQL
password: "secret"
apache:
port: 8080 # Passed to Apache
更高階的 chart 可以訪問下面定義的所有變量。因此 WordPress chart 可以用. Values.mysql.password 訪問 MySQL 密碼。但是低階的 chart 不能訪問父級 chart,所以 MySQL 無法訪問 title 屬性。同樣也無法訪問 apache.port。
4)全局 Values
從 2.0.0-Alpha.2 開始,Helm 支持特殊的 "global" 值。設想一下前面的示例中的修改版本:
title: "My WordPress Site" # Sent to the WordPress template
global:
app: MyWordPress
mysql:
max_connections: 100 # Sent to MySQL
password: "secret"
apache:
port: 8080 # Passed to Apache
面添加了 global 部分和一個值 app: MyWordPress。這個值以
.Values.global.app
在 所有 chart 中有效。
比如,mysql 模板可以以{{.Values.global.app}}
訪問 app,同樣 apache chart 也可以訪問。實際上,上面的 values 文件會重新生成爲這樣:
title: "My WordPress Site" # Sent to the WordPress template
global:
app: MyWordPress
mysql:
global:
app: MyWordPress
max_connections: 100 # Sent to MySQL
password: "secret"
apache:
global:
app: MyWordPress
port: 8080 # Passed to Apache
七、Helm 資源安裝順序
-
Namespace
-
NetworkPolicy
-
ResourceQuota
-
LimitRange
-
PodSecurityPolicy
-
PodDisruptionBudget
-
ServiceAccount
-
Secret
-
SecretList
-
ConfigMap
-
StorageClass
-
PersistentVolume
-
PersistentVolumeClaim
-
CustomResourceDefinition
-
ClusterRole
-
ClusterRoleList
-
ClusterRoleBinding
-
ClusterRoleBindingList
-
Role
-
RoleList
-
RoleBinding
-
RoleBindingList
-
Service
-
DaemonSet
-
Pod
-
ReplicationController
-
ReplicaSet
-
Deployment
-
HorizontalPodAutoscaler
-
StatefulSet
-
Job
-
CronJob
-
Ingress
-
APIService
八、Helm 安裝 Chart 包的三種方式
Helm 自帶一個強大的搜索命令,可以用來從兩種來源中進行搜索:
-
helm search hub
從 Artifact Hubhttps://artifacthub.io/
中查找並列出 helm charts。Artifact Hub 中存放了大量不同的倉庫。 -
helm search repo
從你添加(使用helm repo add
)到本地 helm 客戶端中的倉庫中進行查找。該命令基於本地數據進行搜索,無需連接互聯網。
# 添加bitnami倉庫源
helm repo add bitnami https://charts.bitnami.com/bitnami
# 從bitnami源查找所有chart包,不指定具體源的話,會查找本地添加的所有源地址的所有chart包
helm search repo bitnami
1)values 傳參
安裝過程中有兩種方式傳遞配置數據:
-
--values (或 -f)
:使用 YAML 文件覆蓋配置。可以指定多次,優先使用最右邊的文件。 -
--set
:通過命令行的方式對指定項進行覆蓋。
如果同時使用兩種方式,則 --set 中的值會被合併到 --values 中,但是 --set
中的值優先級更高。在 --set 中覆蓋的內容會被被保存在 ConfigMap 中。可以通過 helm get values <release-name>
來查看指定 release 中 --set 設置的值。也可以通過運行 helm upgrade 並指定 --reset-values 字段來清除 --set 中設置的值。示例如下:
echo '{mariadb.auth.database: user0db, mariadb.auth.username: user0}' > values.yaml
helm install -f values.yaml bitnami/wordpress --generate-name
2)【第一種方式】直接在線 安裝不需要先下載包到本地
helm install mysql bitnami/mysql
helm list
3)【第二種方式】離線安裝 直接通過安裝包安裝
# 先刪除
helm uninstall mysql
# 拉包到本地
helm pull bitnami/mysql
# 不解壓直接安裝
helm install mysql ./mysql-9.3.1.tgz
helm list
4)【第三種方式】離線安裝 解壓包再安裝
# 拉包到本地
helm pull bitnami/mysql
# 解壓安裝
tar -xf mysql-9.3.1.tgz
# 開始安裝
helm install mysql ./mysql \
--namespace=mysql \
--create-namespace \
--set image.registry=myharbor.com \
--set image.repository=bigdata/mysql \
--set image.tag=8.0.30 \
--set primary.service.type=NodePort \
--set service.nodePorts.mysql=30306
# 查看在運行的Release
helm list
# 卸載
helm uninstall mysql -n mysql
九、Helm 基礎語法
1)變量
模板(templates/
)中的變量都放在{{}}
中,比如:{{ .Values.images }}
表示 Values 對象
下的 images 字段。Values 來源於values.yaml
文件或者-f
指定的 yaml 文件,或者--set
設置的變量。
【溫馨提示】使用
-
刪除空格和換行符,要想刪除那行其他的空格和換行符可以用{{-
或者-}}
,** 一個是刪除左邊的空格
和換行符
**,**一個是刪除右邊的空格
和換行符
**。
2)內置對象
-
Release
:Release 對象描述了版本發佈本身。包含了以下對象: -
Release.Name
:release 名稱; -
Release.Namespace
:版本中包含的命名空間 (如果 manifest 沒有覆蓋的話); -
Release.IsUpgrade
:如果當前操作是升級或回滾的話,該值將被設置爲 true -
Release.IsInstall
:如果當前操作是安裝的話,該值將被設置爲 true -
Release.Revision
:此次修訂的版本號。安裝時是 1,每次升級或回滾都會自增; -
Release.Service
:該 service 用來渲染當前模板。Helm 裏始終 Helm。 -
Values
:Values 對象是從values.yaml
文件和用戶提供的文件傳進模板的。默認爲空 -
Chart
:Chart.yaml
文件內容。Chart.yaml 裏的所有數據在這裏都可以可訪問的。比如 {{.Chart.Name}}-{{ .Chart.Version }} 會打印出 mychart-0.1.0。 -
Template
:包含當前被執行的當前模板信息 -
Template.Name
: 當前模板的命名空間文件路徑 (e.g. mychart/templates/mytemplate.yaml); -
Template.BasePath
: 當前 chart 模板目錄的路徑 (e.g. mychart/templates)。
3)常用的內置函數
1、quote and squote
該函數將值轉換成字符串用雙引號 (quote
) 或者 ** 單引號 (squote
)** 括起來。示例如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | quote }}
food: {{ .Values.favorite.food | upper | quote }}
倒置命令是模板中的常見做法。可以經常看到
.val | quote
而不是quote .val
。實際上兩種操作都是可以的。
2、default
這個函數允許你在模板中指定一個默認值,以防這個值被忽略。
# 如果.Values.favorite.drink是非空值,則使用它,否則會返回tea。
drink: {{ .Values.favorite.drink | default "tea" | quote }}
# 還可以這樣寫,如果.Bar是非空值,則使用它,否則會返回foo。
default "foo" .Bar
"空" 定義取決於以下類型:
整型: 0
字符串: ""
列表: []
字典: {}
布爾: false
以及所有的nil (或 null)
3、print
返回各部分組合的字符串,非字符串類型會被轉換成字符串。
print "Matt has " .Dogs " dogs"
【溫馨提示】當相鄰兩個參數不是字符串時會在它們之間添加一個空格。
4、println
和 print 效果一樣,但會在末尾新添加一行。
5、printf
返回參數按順序傳遞的格式化字符串。
printf "%s has %d dogs." .Name .NumberDogs
{{- printf "%d" (.Values.externalCache.port | int ) -}}
{{- printf "%s" .Values.existingSecret -}}
{{- printf "%v" .context.Values.redis.enabled -}}
# %s 字符串佔位符,未解析的二進制字符串或切片
# %d 數字佔位符,十進制
# %v 默認格式的值,當打印字典時,加號參數(%+v)可以添加字段名稱
更多佔位符的使用,可以參考官方文檔:
https://helm.sh/zh/docs/chart_template_guide/function_list/
6、trim
trim 行數移除字符串兩邊的空格:
trim " hello "
7、trimAll
從字符串中移除給定的字符:
trimAll "$" "$5.00"
上述結果爲:5.00 (作爲一個字符串)。
8、lower
將整個字符串轉換成小寫:
lower "HELLO"
上述結果爲:hello
9、upper
將整個字符串轉換成大寫:
upper "hello"
上述結果爲:HELLO
10、title
首字母轉換成大寫:
title "hello world"
上述結果爲:Hello World
11、substr
獲取字符串的子串,有三個參數:
-
start (int)
-
end (int)
-
string (string)
substr 0 5 "hello world"
上述結果爲:hello
12、abbrev
用省略號截斷字符串 (...)
abbrev 5 "hello world"
# 第一個參數:最大長度
# 第二個參數:字符串
上述結果爲:he..., 因爲將省略號算進了長度中。
13、contains
測試字符串是否包含在另一個字符串中:
contains "cat" "catch"
14、cat
cat 函數將多個字符串合併成一個,用空格分隔:
cat "hello" "beautiful" "world"
上述結果爲:hello beautiful world
15、indent
indent 以指定長度縮進給定字符串所在行,在對齊多行字符串時很有用:
indent 4 $lots_of_text
上述結果會將每行縮進 4 個空格。
16、nindent
nindent 函數和 indent 函數一樣,但可以在字符串開頭添加新行。
nindent 4 $lots_of_text
上述結果會在字符串所在行縮進 4 個字符,並且在開頭新添加一行。
17、replace
執行簡單的字符串替換。
# 下面兩行等價
replace " " "-" "I Am Henry VIII"
"I Am Henry VIII" | replace " " "-"
# 參數1:待替換字符串
# 參數2:要替換字符串
# 參數3:源字符串
上述結果爲:I-Am-Henry-VIII
18、date
date 函數格式化日期,日期格式化爲 YEAR-MONTH-DAY:
now | date "2006-01-02"
想了解更多內置函數,可以參考官方文檔:
https://helm.sh/zh/docs/chart_template_guide/function_list/
4)類型轉換函數
Helm 提供了以下類型轉換函數:
-
atoi
: 字符串轉換成整型。 -
float64
: 轉換成 float64。 -
int
: 按系統整型寬度轉換成 int。 -
int64
: 轉換成 int64。 -
toDecimal
: 將 unix 八進制轉換成 int64。 -
toString
: 轉換成字符串。 -
toStrings
: 將列表、切片或數組轉換成字符串列表。 -
toJson (mustToJson)
: 將列表、切片、數組、字典或對象轉換成 JSON。 -
toPrettyJson (mustToPrettyJson)
: 將列表、切片、數組、字典或對象轉換成格式化 JSON。 -
toRawJson (mustToRawJson)
: 將列表、切片、數組、字典或對象轉換成 HTML 字符未轉義的 JSON。
5)正則表達式(Regular Expressions)
Helm 包含以下正則表達式函數
-
regexFind(mustRegexFind)
-
regexFindAll(mustRegexFindAll)
-
regexMatch (mustRegexMatch)
-
regexReplaceAll (mustRegexReplaceAll)
-
regexReplaceAllLiteral(mustRegexReplaceAllLiteral)
-
regexSplit (mustRegexSplit)
6)編碼和解碼函數
Helm 有以下編碼和解碼函數:
-
b64enc/b64dec: 編碼或解碼 Base64
-
b32enc/b32dec: 編碼或解碼 Base32
7)Dictionaries and Dict Functions
Helm 提供了一個 key/value 存儲類型稱爲 dict("dictionary" 的簡稱,Python 中也有)。dict 是無序類型。字典的 key 必須是字符串。但值可以是任意類型,甚至是另一個 dict 或 list。
1、創建字典(dict)
下面是創建三個鍵值對的字典:
$myDict := dict "name1" "value1" "name2" "value2" "name3" "value 3"
2、獲取值(get)
給定一個映射和一個鍵,從映射中獲取值。
get $myDict "name1"
上述結果爲:"value1"
注意如果沒有找到,會簡單返回 ""。不會生成 error。
3、添加鍵值對(set)
使用 set 給字典添加一個鍵值對。
$_ := set $myDict "name4" "value4"
注意 set 返回字典 (Go 模板函數的一個要求),因此你可能需要像上面那樣使用使用
$_
賦值來獲取值。
4、刪除(unset)
給定一個映射和 key,從映射中刪除這個 key。
$_ := unset $myDict "name4"
和 set 一樣,需要返回字典。
5、判斷 key(hasKey)
hasKey 函數會在給定字典中包含了給定 key 時返回 true。
hasKey $myDict "name1"
如果 key 沒找到,會返回 false。
6、pluck
pluck 函數給定一個鍵和多個映射,並獲得所有匹配項的列表:
pluck "name1" $myDict $myOtherDict
上述會返回的 list 包含了每個找到的值 ([value1 otherValue1])。
7、合併 dict(merge, mustMerge)
將兩個或多個字典合併爲一個, 目標字典優先:
$newdict := merge $dest $source1 $source2
8、獲取所有 keys
keys 函數會返回一個或多個 dict 類型中所有的 key 的 list。由於字典是 無序的,key 不會有可預料的順序。可以使用 sortAlpha 存儲。
keys $myDict | sortAlpha
當提供了多個詞典時,key 會被串聯起來。使用
uniq
函數和sortAlpha
獲取一個唯一有序的鍵列表。
keys $myDict $myOtherDict | uniq | sortAlpha
9、獲取所有 values
values 函數類似於 keys,返回一個新的 list 包含源字典中所有的 value(只支持一個字典)。
$vals := values $myDict
上述結果爲:list["value1", "value2", "value 3"]。
注意 values 不能保證結果的順序;如果你需要順序, 請使用
sortAlpha
。
8)Lists and List Functions
Helm 提供了一個簡單的 list 類型,包含任意順序的列表。類似於數組或切片,但列表是被設計用於不可變數據類型。
1、創建列表
$myList := list 1 2 3 4 5
上述會生成一個列表 [1 2 3 4 5]。
2、獲取列表第一項(first, mustFirst)
獲取列表中的第一項,使用 first。
first $myList
# 返回 1
first 有問題時會出錯,mustFirst 有問題時會向模板引擎返回錯誤。
3、獲取列表的尾部內容(rest, mustRest)
獲取列表的尾部內容 (除了第一項外的所有內容),使用 rest。
rest $myList
# 返回 [2 3 4 5]
rest 有問題時會出錯,mustRest 有問題時會向模板引擎返回錯誤。
4、獲取列表的最後一項(last, mustLast)
使用 last 獲取列表的最後一項:
last $myList
# 返回 5。這大致類似於反轉列表然後調用first。
5、獲取列表所有內容(initial, mustInitial)
通過返回所有元素 但 除了最後一個元素。
initial $myList
# 返回 [1 2 3 4]。
initial 有問題時會出錯,但是 mustInitial 有問題時會向模板引擎返回錯誤。
6、末尾添加元素(append, mustAppend)
在已有列表中追加一項,創建一個新的列表。
$new = append $myList 6
上述語句會設置 爲。myList 會保持不變。
append 有問題時會出錯,但 mustAppend 有問題時會向模板引擎返回錯誤。
7、前面添加元素(prepend, mustPrepend)
將元素添加到列表的前面,生成一個新的列表。
prepend $myList 0
上述語句會生成 [0 1 2 3 4 5]。$myList 會保持不變。
prepend 有問題時會出錯,但 mustPrepend 有問題時會向模板引擎返回錯誤。
8、多列表連接(concat)
將任意數量的列表串聯成一個。
concat $myList ( list 6 7 ) ( list 8 )
上述語句會生成 [1 2 3 4 5 6 7 8]。$myList 會保持不變。
9、反轉(reverse, mustReverse)
反轉給定的列表生成一個新列表。
reverse $myList
上述語句會生成一個列表:[5 4 3 2 1]。
reverse 有問題時會出錯,但 mustReverse 有問題時會向模板引擎返回錯誤。
10、去重(uniq, mustUniq)
生成一個移除重複項的列表。
list 1 1 1 2 | uniq
上述語句會生成 [1 2]
uniq 有問題時會出錯,但 mustUniq 有問題時會向模板引擎返回錯誤。
11、過濾(without, mustWithout)
without 函數從列表中過濾內容。
without $myList 3
# 上述語句會生成 [1 2 4 5]
一個過濾器可以過濾多個元素:
without $myList 1 3 5
# 這樣會得到: [2 4]
without 有問題時會出錯,但 mustWithout 有問題時會向模板引擎返回錯誤。
12、判斷元素是否存在(has, mustHas)
驗證列表是否有特定元素。
has 4 $myList
上述語句會返回 true, 但 has "hello" $myList 就會返回 false。
has 有問題時會出錯,但 mustHas 有問題時會向模板引擎返回錯誤。
13、刪除空項(compact, mustCompact)
接收一個列表並刪除空值項。
$list := list 1 "a" "foo" ""
$copy := compact $list
compact 會返回一個移除了空值 (比如, "") 的新列表。
compact 有問題時會出錯,但 mustCompact 有問題時會向模板引擎返回錯誤。
14、index
使用 index list [n] 獲取列表的第 n 個元素。使用 index list [n] [m] ... 獲取多位列表元素。
-
index $myList 0 返回 1,同 myList[0]
-
index $myList 0 1 同 myList[0][1]
15、獲取部分元素(slice, mustSlice)
從列表中獲取部分元素,使用 slice list [n] [m]。等同於 list[n:m].
-
slice $myList 返回 [1 2 3 4 5]。等同於 myList[:]。
-
slice $myList 3 返回 [4 5] 等同於 myList[3:]。
-
slice $myList 1 3 返回 [2 3] 等同於 myList[1:3]。
-
slice $myList 0 3 返回 [1 2 3] 等同於 myList[:3]。
slice 有問題時會出錯,但 mustSlice 有問題時會向模板引擎返回錯誤。
16、構建一個整數列表(until)
until 函數構建一個整數範圍。
until 5
上述語句會生成一個列表:[0, 1, 2, 3, 4]。
對循環語句很有用:range e := until 5。
17、seq
seq 5 => 1 2 3 4 5
seq -3 => 1 0 -1 -2 -3
seq 0 2 => 0 1 2
seq 2 -2 => 2 1 0 -1 -2
seq 0 2 10 => 0 2 4 6 8 10
seq 0 -2 -5 => 0 -2 -4
9)數學函數(Math Functions)
1、求和(add)
使用 add 求和。接受兩個或多個輸入。
add 1 2 3
2、自加 1(add1)
自增加 1,使用 add1。
3、相減(sub)
相減使用 sub。
4、除(div)
整除使用 div。
5、取模(mod)
取模使用 mod。
6、相乘(mul)
相乘使用 mul。接受兩個或多個輸入。
mul 1 2 3
7、獲取最大值(max)
返回一組整數中最大的整數。
max 1 2 3
# 返回 3
8、獲取最小值(min)
返回一組數中最小的數。
min 1 2 3
# 會返回 1。
9、獲取長度(len)
以整數返回參數的長度。
len .Arg
10)Network Functions
Helm 提供了幾個網絡函數:
-
getHostByName
接收一個域名返回 IP 地址。 -
getHostByName
"www.google.com" 會返回對應的 www.google.com 的地址。
10)條件語句
運算符:
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)
if/else 用法:
{{if 命令}}
…
{{else if 命令}}
…
{{else}}
…
{{end}}
如果是以下值時,管道會被設置爲 false:
布爾false
數字0
空字符串
nil (空或null)
空集合(map, slice, tuple, dict, array)
【示例】
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 }}
11)變更作用域 with
下一個控制結構是
with
操作。這個用來控制變量範圍。回想一下,.
是對 當前作用域 的引用。因此.Values
就是告訴模板在當前作用域查找 Values 對象。
with 的語法與 if 語句類似:
{{ with PIPELINE }}
# restricted scope
{{ end }}
作用域可以被改變。with 允許你爲特定對象設定當前作用域 (.
)。比如,我們已經在使用. Values.favorite。修改配置映射中的. 的作用域指向. 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 }}
這樣會報錯因爲Release.Name
不在.
限定的作用域內。但是如果對調最後兩行就是正常的, 因爲在 {{end}} 之後作用域被重置了。
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
release: {{ .Release.Name }}
或者,我們可以使用$
從父作用域中訪問 Release.Name 對象。當模板開始執行後$
會被映射到根作用域,且執行過程中不會更改。下面這種方式也可以正常工作:
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ $.Release.Name }}
{{- end }}
也可以在外邊定義變量,遵循$name變量
的格式且指定了一個特殊的賦值運算符::=
。我們可以使用針對 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 變量仍會執行版本名稱。
12)rang 循環語句
很多編程語言支持使用 for 循環,foreach 循環,或者類似的方法機制。在 Helm 的模板語言中,在一個集合中迭代的方式是使用range
操作符。
定義 values
favorite:
drink: coffee
food: pizza
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
現在我們有了一個 pizzaToppings 列表(模板中稱爲切片)。修改模板把這個列表打印到配置映射中:
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 }}
有時能在模板中快速創建列表然後迭代很有用,Helm 模板的 tuple 可以很容易實現該功能。在計算機科學中, 元組表示一個有固定大小的類似列表的集合,但可以是任意數據類型。這大致表達了tuple
的用法。
sizes: |-
{{- range tuple "small" "medium" "large" }}
- {{ . }}
{{- end }}
上述模板會生成以下內容:
sizes: |-
- small
- medium
- large
13)命名模板
此時需要越過模板,開始創建其他內容了。該部分我們會看到如何在一個文件中定義 命名模板,並在其他地方使用。命名模板 (有時稱作一個 部分 或一個 子模板) 僅僅是在文件內部定義的模板,並使用了一個名字。有兩種創建方式和幾種不同的使用方法。
-
三種聲明和管理模板的方法:
define
,template
,和block
,在這部分,我們將使用這三種操作並介紹一種特殊用途的include
方法,類似於 template 操作。 -
命名模板時要記住一個重要細節:模板名稱是全局的。如果您想聲明兩個相同名稱的模板,哪個最後加載就使用哪個。因爲在子 chart 中的模板和頂層模板一起編譯,命名時要注意 chart 特定名稱。
-
一個常見的命名慣例是用 chart 名稱作爲模板前綴:
{{ define "mychart.labels" }}
。使用特定 chart 名稱作爲前綴可以避免可能因爲 兩個不同 chart 使用了相同名稱的模板而引起的衝突。
在編寫模板細節之前,文件的命名慣例需要注意:
-
templates / 中的大多數文件被視爲包含 Kubernetes 清單
-
NOTES.txt 是個例外
-
命名以下劃線 (
_
) 開始的文件則假定 沒有 包含清單內容。這些文件不會渲染爲 Kubernetes 對象定義,但在其他 chart 模板中都可用。
這些文件用來存儲局部和輔助對象,實際上當我們第一次創建 mychart 時,會看到一個名爲
_helpers.tpl
的文件,這個文件是模板局部的默認位置。
1、用 define 和 template 聲明和使用模板
define 操作允許我們在模板文件中創建一個命名模板,語法如下:
{{- define "MY.NAME" }}
# body of template here
{{- end }}
比如我們可以定義一個模板封裝 Kubernetes 的標籤:
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
現在我們將模板嵌入到了已有的配置映射中,然後使用template
包含進來:
{{- 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 }}
當模板引擎讀取該文件時,它會存儲 mychart.labels 的引用直到 template "mychart.labels" 被調用。然後會按行渲染模板,因此結果類似這樣:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: running-panda-configmap
labels:
generator: helm
date: 2022-09-04
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
注意:define 不會有輸出,除非像本示例一樣用模板調用它。
按照慣例,Helm chart 將這些模板放置在局部文件中,一般是_helpers.tpl
。把這個方法移到那裏:
{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
2、設置模板範圍
在上面定義的模板中,我們沒有使用任何對象,僅僅使用了方法。修改定義好的模板讓其包含 chart 名稱和版本號:
{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
chart: {{ .Chart.Name }}
version: {{ .Chart.Version }}
{{- end }}
3、include 方法
假設定義了一個簡單模板如下:
{{- define "mychart.app" -}}
app_name: {{ .Chart.Name }}
app_version: "{{ .Chart.Version }}"
{{- end -}}
現在假設我想把這個插入到模板的 labels: 部分和 data: 部分:
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" . }}
如果渲染這個,會得到以下錯誤:
$ helm install --dry-run measly-whippet ./mychart
Error: unable to build kubernetes objects from release manifest: error validating "": error validating data: [ValidationError(ConfigMap): unknown field "app_name" in io.k8s.api.core.v1.ConfigMap, ValidationError(ConfigMap): unknown field "app_version" in io.k8s.api.core.v1.ConfigMap]
要查看渲染了什麼,可以用--disable-openapi-validation
參數重新執行:helm install --dry-run --disable-openapi-validation measly-whippet ./mychart
。輸入不是我們想要的:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: measly-whippet-configmap
labels:
app_name: mychart
app_version: "0.1.0"
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
app_name: mychart
app_version: "0.1.0"
注意兩處的 app_version 縮進都不對,爲啥?因爲被替換的模板中文本是左對齊的。由於
template
是一個行爲,不是方法,無法將template
調用的輸出傳給其他方法,數據只是簡單地按行插入。
爲了處理這個問題,Helm 提供了一個include
,可以將模板內容導入當前管道,然後傳遞給管道中的其他方法。下面這個示例,使用indent
正確地縮進了 mychart.app 模板:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
labels:
{{ include "mychart.app" . | indent 4 }}
data:
myvalue: "Hello World"
{{- range $key, $val := .Values.favorite }}
{{ $key }}: {{ $val | quote }}
{{- end }}
{{ include "mychart.app" . | indent 2 }}
現在生成的 YAML 每一部分都可以正確縮進了:
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: edgy-mole-configmap
labels:
app_name: mychart
app_version: "0.1.0"
data:
myvalue: "Hello World"
drink: "coffee"
food: "pizza"
app_name: mychart
app_version: "0.1.0"
include
相較於使用 template,在 helm 中使用 include 被認爲是更好的方式 只是爲了更好地處理 YAML 文檔的輸出格式。
14)NOTES.txt 文件
該部分會介紹爲 chart 用戶提供說明的 Helm 工具。在 helm install 或 helm upgrade 命令的最後,Helm 會打印出對用戶有用的信息。使用模板可以高度自定義這部分信息。
要在 chart 添加安裝說明,只需創建templates/NOTES.txt
文件即可。該文件是純文本,但會像模板一樣處理, 所有正常的模板函數和對象都是可用的。讓我們創建一個簡單的 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 }}
現在如果我們執行 helm install rude-cardinal ./mychart 會在底部看到:
RESOURCES:
==> v1/Secret
NAME TYPE DATA AGE
rude-cardinal-secret Opaque 1 0s
==> v1/ConfigMap
NAME DATA AGE
rude-cardinal-configmap 3 0s
NOTES:
Thank you for installing mychart.
Your release is named rude-cardinal.
To learn more about the release, try:
$ helm status rude-cardinal
$ helm get all rude-cardinal
使用 NOTES.txt 這種方式是給用戶提供關於如何使用新安裝的 chart 細節信息的好方法。儘管並不是必需的,強烈建議創建一個
NOTES.txt
文件。
15)模板調試
調試模板可能很棘手,因爲渲染後的模板發送給了 Kubernetes API server,可能會以格式化以外的原因拒絕 YAML 文件。以下命令有助於調試:
-
helm lint
是驗證 chart 是否遵循最佳實踐的首選工具 -
helm install --dry-run --debug
或helm template --debug
:我們已經看過這個技巧了, 這是讓服務器渲染模板的好方法,然後返回生成的清單文件。 -
helm get manifest
: 這是查看安裝在服務器上的模板的好方法。
當你的 YAML 文件解析失敗,但你想知道生成了什麼,檢索 YAML 一個簡單的方式是註釋掉模板中有問題的部分, 然後重新運行 helm install --dry-run --debug
:
apiVersion: v2
# some: problem section
# {{ .Values.foo | quote }}
以上內容會被渲染同時返回完整的註釋:
apiVersion: v2
# some: problem section
# "bar"
其實這裏主要是正對官方文檔進行整理,列出了常見的使用語法,想了解更多,可以參考官方文檔,官方文檔講解的很細緻,有疑問的小夥伴歡迎給我留言哦
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/aWXqRYlj4TEyGOG-X18lOg