## 1. 定義 chart
Helm 的 github 上面有一個比較[完整的文檔](https://github.com/helm/charts),一個 chart 包就是一個文件夾的集合,文件夾名稱就是 chart 包的名稱,比如創建一個 `mychart` 的 chart 包:
```bash
$ helm create mychart
Creating mychart
$ tree mychart/
mychart/
├── charts
├── Chart.yaml
├── templates
│ ├── deployment.yaml
│ ├── _helpers.tpl
│ ├── ingress.yaml
│ ├── NOTES.txt
│ └── service.yaml
└── values.yaml
2 directories, 7 files
```
templates 目錄下面的文件:
- `NOTES.txt`:chart 的 “幫助文本”。這會在用戶運行 `helm install` 時顯示給用戶。
- `deployment.yaml`:創建 `Kubernetes deployment` 的基本 `manifest`
- `service.yaml`:為 `deployment` 創建 `service` 的基本 `manifest`
- `ingress.yaml`: 創建 `ingress` 對象的資源清單文件
- `_helpers.tpl`:放置模板助手的地方,可以在整個 chart 中重復使用
然后我們把 templates 目錄下面所有文件全部刪除掉,這里我們自己來創建模板文件:
```bash
$ rm -rf mychart/templates/*.*
```
## 2. 創建模板
這里我們來創建一個非常簡單的模板 ConfigMap,在 templates 目錄下面新建一個`configmap.yaml`文件:
```bash
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "Hello World"
```
實際上現在我們就有一個可安裝的 chart 包了,通過`helm install`命令來進行安裝:
```bash
$ helm install ./mychart/
NAME: ringed-lynx
LAST DEPLOYED: Fri Sep 7 22:59:22 2018
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/ConfigMap
NAME DATA AGE
mychart-configmap 1 0s
```
在上面的輸出中,我們可以看到我們的 `ConfigMap` 資源對象已經創建了。然后使用如下命令我們可以看到實際的模板被渲染過后的資源文件:
```bash
$ helm get manifest ringed-lynx
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-configmap
data:
myvalue: "Hello World"
```
現在我們看到上面的 `ConfigMap` 文件是不是正是我們前面在模板文件中設計的,現在我們刪除當前的`release`:
```bash
$ helm delete ringed-lynx
release "ringed-lynx" deleted
```
## 3. 添加一個簡單的模板
我們可以看到上面我們定義的 ConfigMap 的名字是固定的,但往往這并不是一種很好的做法,我們可以通過插入 release 的名稱來生成資源的名稱,比如這里 ConfigMap 的名稱我們希望是:`ringed-lynx-configmap`,這就需要用到 Chart 的模板定義方法了。
Helm Chart 模板使用的是[Go語言模板](https://pkg.go.dev/text/template)編寫而成,并添加了[Sprig庫](https://github.com/Masterminds/sprig)中的50多個附件模板函數以及一些其他特殊的函。
> 需要注意的是kubernetes資源對象的 `labels` 和 `name` 定義被限制 63個字符,所以需要注意名稱的定義。
現在我們來重新定義下上面的 `configmap.yaml` 文件:
```bash
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
```
我們將名稱替換成了`{{ .Release.Name }}-configmap`,其中包含在{{和}}之中的就是模板指令,`{{ .Release.Name }}` 將 `release` 的名稱注入到模板中來,這樣最終生成的 ConfigMap 名稱就是以 `release` 的名稱開頭的了。這里的 Release 模板對象屬于 Helm 內置的一種對象,還有其他很多內置的對象,稍后我們將接觸到。
現在我們來重新安裝我們的 Chart 包,注意觀察 `ConfigMap` 資源對象的名稱:
```bash
$ helm install ./mychart
helm install ./mychart/
NAME: quoting-zebra
LAST DEPLOYED: Fri Sep 7 23:20:12 2018
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/ConfigMap
NAME DATA AGE
quoting-zebra-configmap 1 0s
```
可以看到現在生成的名稱變成了`quoting-zebra-configmap`,證明已經生效了,當然我們也可以使用命令`helm get manifest quoting-zebra`查看最終生成的清單文件的樣子。
## 4. 調試
我們用模板來生成資源文件的清單,但是如果我們想要調試就非常不方便了,不可能我們每次都去部署一個`release`實例來校驗模板是否正確,所幸的時 Helm 為我們提供了`--dry-run --debug`這個可選參數,在執行`helm install`的時候帶上這兩個參數就可以把對應的 `values` 值和生成的最終的資源清單文件打印出來,而不會真正的去部署一個release實例,比如我們來調試上面創建的 chart 包:
```bash
$ helm install . --dry-run --debug ./mychart
[debug] Created tunnel using local port: '35286'
[debug] SERVER: "127.0.0.1:35286"
[debug] Original chart version: ""
[debug] CHART PATH: /root/course/kubeadm/helm/mychart
NAME: wrapping-bunny
REVISION: 1
RELEASED: Fri Sep 7 23:23:09 2018
CHART: mychart-0.1.0
USER-SUPPLIED VALUES:
{}
COMPUTED VALUES:
...
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: wrapping-bunny-configmap
data:
myvalue: "Hello World"
```
現在我們使用`--dry-run`就可以很容易地測試代碼了,不需要每次都去安裝一個 `release` 實例了,但是要注意的是這不能確保 Kubernetes 本身就一定會接受生成的模板,在調試完成后,還是需要去安裝一個實際的 release 實例來進行驗證的。
## 5. 內置對象
剛剛我們使用`{{.Release.Name}}`將 release 的名稱插入到模板中。這里的 Release 就是 Helm 的內置對象,下面是一些常用的內置對象,在需要的時候直接使用就可以:
`Release`:這個對象描述了 release 本身。它里面有幾個對象:
- `Release.Name`:release 名稱
- `Release.Time`:release 的時間
- `Release.Namespace`:release 的 `namespace`(如果清單未覆蓋)
- `Release.Service`:release 服務的名稱(始終是 Tiller)。
- `Release.Revision`:此 `release` 的修訂版本號,從1開始累加。
- `Release.IsUpgrade`:如果當前操作是升級或回滾,則將其設置為 `true`。
- `Release.IsInstall`:如果當前操作是安裝,則設置為 `true`。
`Values`:從`values.yaml`文件和用戶提供的文件傳入模板的值。默認情況下,Values 是空的。
`Chart`:`Chart.yaml`文件的內容。所有的 Chart 對象都將從該文件中獲取。
`Files`:這提供對 chart 中所有非特殊文件的訪問。雖然無法使用它來訪問模板,但可以使用它來訪問 chart 中的其他文件。請參閱 "訪問文件" 部分。
- `Files.Get` 是一個按名稱獲取文件的函數(`.Files.Get config.ini`)
- `Files.GetBytes` 是將文件內容作為字節數組而不是字符串獲取的函數。這對于像圖片這樣的東西很有用。
`Capabilities`:這提供了關于 Kubernetes 集群支持的功能的信息。
- `Capabilities.APIVersions` 是一組版本信息。
- `Capabilities.KubeVersion` 提供了查找 Kubernetes版本的方法。它具有以下值:`Major`,`Minor`,`GitVersion`,`GitCommit`,`GitTreeState`,`BuildDate`,`GoVersion`,`Compiler`,和`Platform`。
- `Capabilities.TillerVersion` 提供了查找 `Tiller`版本的方法。它具有以下值:`SemVer`,`GitCommit`,和 `GitTreeState`。
`Capabilities.APIVersions.Has $version`指示集群上是否有可用的版本(例如batch/v1)或資源(例如)。apps/v1/Deployment
`Capabilities.KubeVersion`并且`Capabilities.KubeVersion.Version`是 Kubernetes 版本。
`Capabilities.KubeVersion.Major`是 Kubernetes 的主要版本。
`Capabilities.KubeVersion.Minor`是 Kubernetes 次要版本。
`Capabilities.HelmVersion`是包含 Helm 版本詳細信息的對象,它是相同的輸出h`elm version`
`Capabilities.HelmVersion.Version`是 semver 格式的當前 Helm 版本。
`Capabilities.HelmVersion.GitCommit`是 Helm git sha1。
`Capabilities.HelmVersion.GitTreeState`是 Helm git 樹的狀態。
`Capabilities.HelmVersion.GoVersion`是使用的 Go 編譯器的版本。
`Template`:包含有關正在執行的當前模板的信息
- `Template.Name`: 當前模板的命名空間文件路徑(例如`mychart/templates/mytemplate.yaml`)
- `Template.BasePath`: 當前圖表的模板目錄的命名空間路徑(例如`mychart/templates`)
上面這些值可用于任何頂級模板,要注意內置值始終以大寫字母開頭。這也符合Go的命名約定。當你創建自己的名字時,你可以自由地使用適合你的團隊的慣例。
---
?<font color= #FF4500 size=4 style="font-family:Courier New">推薦閱讀:</font>
- [helm 官方](https://helm.sh/docs/howto/charts_tips_and_tricks/)
- [helm 手冊](https://www.bookstack.cn/read/helm-3.8.0-en/b5fa667da3c6d162.md)