Helm Chart模板詳述和樣例

Helm最核心的就是模板,即模板化的Kubernetes清單文件,模板經過渲染後會被提交到Kubernetes中,本質上就是Go語言的template模板,模板文件位於template/目錄中。

將Kubernetes清單文件中可能經常變動的字段,通過指定一個變量,在安裝的過程中該變量將被值value動態替換掉,這個過程就是模板的渲染。

變量的值定義在values.yaml文件中,該文件中定義了變量的缺省值,但可以在helm install命令中配置新的值來覆蓋缺省值。

  • 內置對象

對象從模板引擎傳遞到模板中。如使用{{.Release.Name}}將Release的名稱插入到模板中。Release是可以在模板中訪問的頂級對象之一。

對象可以很簡單,只有一個值。或者他們可以包含其他對象或函數。例如,Release對象包含多個對象(如Release.Name),並且Files對象具有一些函數。

Helm內置了多個頂級對象:

  • Release:這個對象描述了Release本身,它裏面有幾個對象:
    • Release.Name:Release名稱。
    • Release.Namespace:Release的Namespace。
    • Release.IsUpgrade:如果當前操作是升級或回滾,則將其設置爲true。
    • Release.IsInstall:如果當前操作是安裝,則設置爲true。
    • Release.Revision:此Release 的修訂版本號。
    • Release.Service:渲染此模板的服務,Helm中總是“Helm”。
  • Values:從values.yaml文件和用戶提供的文件傳入模板的值。默認情況下,Values是空的。
  • Chart:Chart.yaml文件的內容。
  • Files:提供對Chart中所有非特殊文件的訪問。雖然您不能使用它來訪問模板,但是可以使用它來訪問Chart圖表中的其他文件。
    • Files.Get是用於按名稱獲取文件。
    • Files.GetBytes是用於以字節數組而不是字符串的形式獲取文件內容的函數。 這對於諸如圖像之類的東西很有用。
    • Files.Glob是一個函數,該函數返回名稱與給定的Shell Glob模式匹配的文件列表。
    • Files.Lines是一項功能,可逐行讀取文件。 這對於遍歷文件中的每一行很有用。
    • Files.AsSecrets是一個函數,以Base 64編碼的字符串形式返回文件主體。
    • Files.AsConfig是一個將文件正文作爲YAML映射返回的函數。
  • Capabilities:提供了有關Kubernetes集羣支持哪些功能的信息。
    • Capabilities.APIVersions是一組版本。
    • Capabilities.APIVersions.Has:$version指示羣集上是否有版本(例如,batch/v1)或資源(例如,apps/v1/Deployment)。
    • Capabilities.KubeVersion是Kubernetes版本。
    • Capabilities.KubeVersion.Version是Kubernetes版本。
    • Capabilities.KubeVersion.Major是Kubernetes的主要版本。
    • Capabilities.KubeVersion.Minor是Kubernetes的次要版本。
  • Template:包含有關正在執行的當前模板的信息。
    • Name:當前模板的命名空間文件路徑(例如mychart/templates/mytemplate.yaml)
    • BasePath:當前Chart的模板目錄的命名空間路徑(例如mychart/templates)。

這些值可用於任何頂級模板。內置值始終以大寫字母開頭,這符合Go的命名約定。

  • Values文件

四個內置對象之一的Values,該對象提供對傳入Chart的值的訪問。其內容來自四個來源:

  • Chart中的values.yaml文件。
  • 如果這是一個子Chart,來自父Chart的values.yaml文件。
  • values文件通過helm install或helm upgrade的-f標誌傳入文件(helm install -f myvals.yaml ./mychart)。
  • 通過–set(helm install --set foo=bar ./mychart)。

上面的列表按照特定的順序排列:values.yaml是默認級別,父級Chart的可以覆蓋該默認級別,而該values.yaml又可以被用戶提供的values文件覆蓋,而該文件又可以被–set參數覆蓋。

我們先創建一個Chart。

helm create mychart
Creating mychart

我們將默認的values.yaml文件內容刪除,並設置一個參數:

vi mychart/values.yaml
favoriteDrink: coffee

爲了簡單起見,刪除templates/目錄中所有文件,並創建configmap.yaml模板文件。

模板指令放在{{和}}塊之間,模板指令{{ .Release.Name }}表示將Release名稱注入模板。可以將傳遞到模板中的值視爲命名空間對象,其中句號".“用來分割每個命名空間元素,前導”."表示當前的作用域,此處表示頂級命名空間。{{ .Release.Name }}表示從頂級命名空間開始,找到Release對象,然後在其中查找名爲Name的對象。{{ .Values.favoriteDrink }}表示從頂級命名空間開始,找到Values對象,然後在其中查找名爲favoriteDrink的對象。

rm -rf mychart/templates/*

vi mychart/templates/configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favoriteDrink }}

我們看看渲染的效果。

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: coffee

參數favoriteDrink在默認values.yaml文件中設置爲coffee,但可以在helm template命令中通過加一個–set添標誌來覆蓋,因爲–set的優先級更高。

helm template myrelease mychart --set favoriteDrink=tea
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: tea

values文件也可以包含更多結構化內容。在values.yaml文件中可以創建favorite添加幾個鍵:

vi mychart/values.yaml
favorite:
  drink: coffee
  food: pizza

vi mychart/templates/configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink }}
  food: {{ .Values.favorite.food }}

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: coffee
  food: pizza
  • 函數

在模板文件中有時不想直接引用對象,而是需要對對象做一些轉換,比如將對象作爲字符串引用,可以使用函數quote。

vi mychart/templates/configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ quote .Values.favorite.drink }}
  food: {{ quote .Values.favorite.food }}

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "pizza"

模板函數遵循語法functionName arg1 arg2…。在上面的代碼段中,quote .Values.favorite.drink調用quote函數並將其傳遞給單個參數。

  • 管道

模板語言的強大功能之一是其管道概念。像Linux中的管道一樣,是將一系列模板命令鏈接在一起以緊湊表示一系列轉換的工具。管道是按順序完成多項工作的有效方式。

vi mychart/templates/configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | quote }}
  food: {{ .Values.favorite.food | quote }}

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "pizza"

管道符號"|"將前面的對象作爲後面函數的參數,上面的例子我們將.Values.favorite.drink對象通過管道傳遞給quote函數。

管道方便的地方在可以順序將對象在函數中傳遞。

vi mychart/templates/configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | repeat 5 | quote }}
  food: {{ .Values.favorite.food | upper | quote }}

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: "coffeecoffeecoffeecoffeecoffee"
  food: "PIZZA"

上例將.Values.favorite.drink對象作爲repeat函數的第二個參數,而第一個參數爲5。

  • 缺省值

模板中經常需要用到缺省值功能:default DEFAULT_VALUE GIVEN_VALUE,此功能允許在模板內部指定缺省值,沒有定義該對象或者對象爲空時有缺省值對應。

vi mychart/templates/configmap.yaml
---
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 }}

helm template myrelease mychart --set favorite.drink=null
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: "tea"
  food: "PIZZA"
  • Helm流程控制-If/Else

Helm通過If/Else塊有條件地控制模板中是否包含文本塊。

{{ if PIPELINE }}
  # Do something
{{ else if OTHER PIPELINE }}
  # Do something else
{{ else }}
  # Default case
{{ end }}

注意if後面是管道,當值爲以下情況時,管道視爲false。

  • a boolean false:邏輯值false
  • a numeric zero:數字值0
  • an empty string:空字符串
  • a nil (empty or null)-值爲空或者null
  • an empty collection (map, slice, tuple, dict, array):一個空的集合

以下模板根據條件顯示mug: true。

vi mychart/templates/configmap.yaml
---
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 }}

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  mug: true
  • Helm流程控制-縮進

以上的方式控制mug: true的顯示不易閱讀,嘗試使用縮進。

vi mychart/templates/configmap.yaml
---
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}}

helm template myrelease mychart
Error: YAML parse error on mychart/templates/configmap.yaml: error converting YAML to JSON: yaml: line 9: did not find expected key

在渲染時報錯,實際上模板被渲染爲了如下清單文件,多縮進了兩個空格。

# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
    mug: true

重新嘗試縮進設置。

vi mychart/templates/configmap.yaml
---
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}}

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"

  mug: true

結果發現縮進正確,但卻多出了一個空行。原因是模板渲染時,渲染引擎會直接替換到{{ … }},然後原樣保留之外的所有字符。所以{{if eq .Values.favorite.drink “coffee”}}後面的換行符被保留了,導致了一個空行。

可以使用特殊字符修改模板聲明的大括號語法,以告訴模板引擎填充空白。"{{- “表示刪除左邊的所有空格,直到非空格字符,而” -}}"表示刪除右邊的所有空格。注意,換行符也是空格!當然還包括空格,TAB字符。

vi mychart/templates/configmap.yaml
---
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 }}

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  mug: true

這次縮進完全控制正確了,上面由於空格不顯示出來不容易理解,我們可以使用*替換空格,使用$替換換行符,這樣看的更清楚一些。{{- … }}表示將左邊的$和**刪除。{{ … -}}表示將右邊的$和**刪除。這樣就剩下了中間的$和**,換行符$恰好就是food和mug兩行之間的換行符。

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

當然控制縮進更推薦使用函數indent,更容易理解。

vi mychart/templates/configmap.yaml
---
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" | indent 2 }}
  {{- end }}    

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  mug: true
  • Helm流程控制-with

with用來控制變量作用域。前面提過,前導"."是對當前作用域的引用。.Values告訴模板在當前範圍中查找Values對象。

語法with類似於一個簡單的if語句:

{{ with PIPELINE }}
  # restricted scope
{{ end }}

作用域是可以更改的,可以將當前作用域"."設置爲特定對象。

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,所以在with塊中,我們直接使用.drink和.food。

注意:在with受限作用域中,是無法父作用域或者頂級作用域訪問其他對象。

{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ .Release.Name }}
{{- end }}

在with塊中不能引用{{ .Release.Name }},因爲當前作用域不是頂級作用域,是無法找到頂級對象Release的。

  • Helm流程控制-range

在Helm的模板語言中,使用rang來迭代集合。我們在values.yaml中定義一個列表。

vi mychart/values.yaml
favorite:
  drink: coffee
  food: pizza
pizzaToppings:
  - mushrooms
  - cheese
  - peppers
  - onions

我們將列表展示在configmap中。使用range來迭代列表的值,"."表示迭代的當前值,通過管道傳遞給title函數,將首字母大寫,然後再通過管道傳遞給quote,轉爲字符串。

vi mychart/templates/configmap.yaml
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 }}

渲染模板之後可以看出確實迭代List。

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  toppings: |-
    - "Mushrooms"
    - "Cheese"
    - "Peppers"
    - "Onions"

順便看看如何在命令行中設置數組參數。values.yaml文件可以不配置任何參數。

vi mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
{{- if .Values.pizzaToppings }}
  toppings:
{{ toYaml .Values.pizzaToppings | indent 4 }}
{{ end }}

helm template myrelease mychart \
  --set pizzaToppings[0]=chili \
  --set pizzaToppings[1]=pork \
  --set pizzaToppings[2]=bamboo \
  --set pizzaToppings[3]=pineapple
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  toppings: |-
    - chili
    - pork
    - bamboo
    - pineapple

再看看另一種數組。values.yaml文件可以不配置任何參數。

vi mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
{{- if .Values.favorites }}
  favorites:
{{ toYaml .Values.favorites | indent 4 }}
{{ end }}

helm template myrelease mychart \
  --set favorites[0].drink=coffee \
  --set favorites[0].food=pizza \
  --set favorites[1].drink=tea \
  --set favorites[1].food=hotpot
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  favorites:
    - drink: coffee
      food: pizza
    - drink: tea
      food: hotpot

參數值中的逗號","需要轉義。

vi mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink }}

helm template myrelease mychart \
  --set favorite.drink="coffee\,tea"
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: coffee,tea
  • 變量

在Helm模板中,變量是對另一個對象的命名引用。它遵循$name格式,變量使用特殊的賦值運算符進行賦值":="。

vi mychart/values.yaml
favorite:
  drink: coffee
  food: pizza

vi mychart/templates/configmap.yaml
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 }}

因爲.Release.Name不能在with塊中直接使用,所以在with之前將.Release.Name賦值給變量relname。

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  release: myrelease
  • 命名模板

Helm支持在一個文件中定義命名模板,然後在其他模板中使用命名模板。命名模板使用define聲明,使用template使用模板。

我們可以在模板文件中使用define創建命名模板,語法如下:

{{ define "MY.NAME" }}
  # body of template here
{{ end }}

模板名稱是全局的,如果聲明兩個具有相同名稱的模板,則只會使用的是最後定義的模板。因爲Sub Chart中的模板是與父Chart模板一起編譯的,所以應謹慎命名命名模板。一種流行的命名約定是在每個命名模板前添加Chart名稱{{define “mychart.labels”}},可以避免由於兩個不同的Chart定義了相同名稱的模板而引起的任何衝突。

可以在configmap.yaml中直接定義命名模板,然後使用template使用該命名模板。

vi mychart/templates/configmap.yaml
{{- 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"

渲染效果如下。

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
  labels:
    generator: helm
    date: 2020-03-29
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"

我們先看一下templates/目錄下的文件命名約定:

  • NOTES.txt是一個例外,改文件是安裝後的說明文件,不是Kubernetes清單文件。
  • 名稱以下劃線"_"開頭的文件不是Kubernetes清單文件。_helpers.tpl就是缺省的命名模板定義文件。
  • 除此之外都是Kubernetes清單文件,在安裝時會自動渲染並加載到Kubernetes中。

我們將以上的命名模板移到_helpers.tpl文件中。

vi mychart/templates/_helpers.tpl
{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
{{- end }}

刪除configmap.yaml中的命名模板。

vi mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  {{- template "mychart.labels" }}
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}

有相同的渲染效果。

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
  labels:
    generator: helm
    date: 2020-03-29
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"

我們也可以使用include使用命名模板。

vi mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
{{- include "mychart.labels" . }}
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}

也有相同的渲染效果。

helm template myrelease mychart
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
  labels:
    generator: helm
    date: 2020-03-29
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章