圖表開發秘訣和技巧

本指南包含 Helm 圖表開發人員在建置製作等級圖表時學到的部分秘訣和技巧。

認識您的範本函式

Helm 使用 Go 範本 替您的資源檔建立範本。雖然 Go 提供了幾個內建函式,我們也新增了許多其他函式。

首先,我們新增了 Sprig library 中的所有函式,基於安全理由,不包含 envexpandenv

我們也新增了兩個特殊的範本函式:includerequiredinclude 函式讓您可以加入另一個範本,然後將結果傳遞給其他範本函式。

例如,這個範本片段包含名為 mytpl 的範本,然後將結果改成小寫,然後將其用雙引號包住。

value: {{ include "mytpl" . | lower | quote }}

required 函式讓您可以宣告範本渲染所需的特定值。如果值為空,範本渲染將會失敗,並顯示使用者提交的錯誤訊息。

以下 required 函式的範例宣告 .Values.who 的輸入是範本渲染的必要條件,並將在輸入遺失時印出錯誤訊息

value: {{ required "A valid .Values.who entry required!" .Values.who }}

引用字串,不要引用整數

當您處理字串資料時,總是引用字串會比不引用安全

name: {{ .Values.MyName | quote }}

但在處理整數時,請不要引用值。在許多情況下,這會造成 Kubernetes 內部的剖析錯誤。

port: {{ .Values.Port }}

此說明不適用於 env 變數值,即使它們表示整數,它們也會被預期為字串

env:
  - name: HOST
    value: "http://host"
  - name: PORT
    value: "1234"

使用「include」函式

Go 提供了一種使用內建 template 指令的方式,在一個範本中包含另一個範本。然而,內建函式不能用於 Go 範本管線。

Helm有個特殊的include函式,讓使用者得以加入範本,再針對該範本的輸出執行操作

{{ include "toYaml" $value | indent 2 }}

上方包含一個名為toYaml的範本,傳入$value,再將該範本的輸出傳遞給indent函式。

由於 YAML 會標示縮排層級和空白的重要性,這是一個包含程式碼片段和在相關脈絡中處理縮排的好方法。

使用「required」函式

Go 提供設定範本選項的方法,用於控制在使用不存在於映射中的金鑰對映射進行索引時的行為。這通常使用 template.Options("missingkey=option") 設定,其中 option 可以是 defaultzeroerror。雖然將這個選項設為 error 會停止執行並顯示錯誤訊息,但這將套用至該映射中所有的遺失金鑰。有時候,圖表開發人員希望對 values.yaml 檔案中的選取值套用此行為。

required 函式讓開發人員能宣告值項目為範本繪製所必需。如果 values.yaml 中的項目為空,範本將不會繪製,並會傳回開發人員提供的錯誤訊息。

範例

{{ required "A valid foo is required!" .Values.foo }}

.Values.foo 已定義時,上述範本將會繪製,但如果 .Values.foo 未定義,它將無法繪製並會結束執行。

使用「tpl」函式

tpl 函式讓開發人員得以在範本內將字串作為範本來評估。這可用於將範本字串作為值傳遞給圖表,或繪製外部設定檔。語法:{{ tpl TEMPLATE_STRING VALUES }}

範例

# values
template: "{{ .Values.name }}"
name: "Tom"

# template
{{ tpl .Values.template . }}

# output
Tom

繪製外部設定檔

# external configuration file conf/app.conf
firstName={{ .Values.firstName }}
lastName={{ .Values.lastName }}

# values
firstName: Peter
lastName: Parker

# template
{{ tpl (.Files.Get "conf/app.conf") . }}

# output
firstName=Peter
lastName=Parker

建立影像提取機密碼

影像提取機密碼基本上就是 登錄記錄使用者名稱密碼 的組合。您可能需要在所部署的應用程式中使用它們,但建立它們需要執行 base64 數次。我們可以撰寫一個協助範本來組成 Docker 設定檔,做為機密的酬載。以下是範例

首先,假設認證在 values.yaml 檔案中定義如下

imageCredentials:
  registry: quay.io
  username: someone
  password: sillyness
  email: someone@host.com

然後,我們定義自己的協助範本如下

{{- define "imagePullSecret" }}
{{- with .Values.imageCredentials }}
{{- printf "{\"auths\":{\"%s\":{\"username\":\"%s\",\"password\":\"%s\",\"email\":\"%s\",\"auth\":\"%s\"}}}" .registry .username .password .email (printf "%s:%s" .username .password | b64enc) | b64enc }}
{{- end }}
{{- end }}

最後,我們在較大的範本中使用協助範本來建立機密清單

apiVersion: v1
kind: Secret
metadata:
  name: myregistrykey
type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: {{ template "imagePullSecret" . }}

自動執行遞增部署

有時候,ConfigMap 或機密會作為設定檔注入容器中,或者有其他的外部相關性變更需要持續執行 pod。這取決於應用程式本身,後續在使用 helm upgrade 進行更新時可能需要重新啟動,但如果部署規格本身沒有變更,則應用程式將持續執行舊的設定,造成部署不一致。

sha256sum 函式可用於確認部署的註解區段在當其他檔案變更時已更新

kind: Deployment
spec:
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
[...]

注意事項:如果您將此新增至函式庫圖表中,您將無法存取檔案中的 $.Template.BasePath。取而代之,您可以使用 {{ include ("mylibchart.configmap") . | sha256sum }} 參照您的定義。

如果您總是想要將佈署移轉,您可以使用與上方類似的註解步驟,不同之處是將其替換為隨機字串,如此一來它會持續變更並導致佈署移轉

kind: Deployment
spec:
  template:
    metadata:
      annotations:
        rollme: {{ randAlphaNum 5 | quote }}
[...]

每次呼叫範本函數都會產生唯一的隨機字串。這表示如果需要同步多個資源使用的隨機字串,所有相關資源都必須在同一個範本檔案中。

這兩種方法都能讓您的佈署運用內建更新策略邏輯,避免發生停機時間。

注意事項:在過去,我們建議使用 --recreate-pods 旗標作為另一個選項。此旗標已在 Helm 3 中標示為已棄用,而推薦使用上述較為宣告性的方法。

通知 Helm 不要移除資源

有時有一些資源不應在 Helm 執行 helm uninstall 時移除。圖表開發人員可以新增註解至資源,以防止其遭移除。

kind: Secret
metadata:
  annotations:
    helm.sh/resource-policy: keep
[...]

註解 helm.sh/resource-policy: keep 指示 Helm 在 helm 作業(例如 helm uninstallhelm upgradehelm rollback)造成其被刪除時略過刪除此資源。不過,此資源會變得孤立無援。Helm 不會再以任何方式管理它。如果針對已移除但已保留資源的版本使用 helm install --replace,這可能會導致問題。

使用「部分」和範本包含

有時您想要在圖表中建立一些可重複使用的部分,不論是區塊或範本部分。而且通常會將這些放在他們自己的檔案中會比較簡潔。

templates/ 目錄中,任何從底線 (_) 開始的檔案都不會預期會輸出 Kubernetes 清單檔案。因此依慣例,helper 範本和部分會放置在 _helpers.tpl 檔案中。

具有許多依賴項的複雜圖表

CNCF Artifact Hub 中的許多圖表是建立更進階應用程式的「建構組塊」。但圖表可用於建立大型應用程式的執行個體。這種情況下,單一總括圖表可能有多個子圖表,每個子圖表都作為整體的一個部分運作。

從不連續的部分組成複雜應用程式的目前最佳實務是建立公開全域組態的頂層總括圖表,然後使用 charts/ 子目錄將每個元件嵌入其中。

YAML 是 JSON 的超集

根據 YAML 規範,YAML 是 JSON 的超集。這表示任何有效的 JSON 架構都應在 YAML 中有效。

這種方式具有優點:有時候,範本開發人員可能會覺得使用類似 JSON 的語法來表示資料結構比應付 YAML 的空白符敏感性來得更容易。

作為最佳範例,範本應遵循類似 YAML 的語法,除非 JSON 語法會大幅降低格式化問題的風險。

小心產生亂數字元

Helm 中有許多可讓您產生亂數資料、加密金鑰等等的函式。這些功能很好用。但是請注意,在升級期間,範本會重新執行。當範本執行時,產生的資料與上一次執行時不同,就會觸發該資源的更新。

使用單一指令安裝或升級發行版

Helm 提供一個方法可以將安裝和升級執行為單一指令。使用 helm upgrade 並搭配 --install 指令。這會讓 Helm 檢查發行版是否已經安裝。如果還沒有安裝,它就會執行安裝。如果已經安裝,則會升級現有的發行版。

$ helm upgrade --install <release name> --values <values file> <chart directory>