返回
Featured image of post Helm - Chart 如何撰寫

Helm - Chart 如何撰寫

The package manager for Kubernetes

起手式

$ helm create helm-workflow
Create helm-workflow
$ rm -rf helm-workflow/templates/*  # 教學使用,後續看個人

目錄

.helmignore     # ignore file
Chart.yaml      # 定義 Chart
values.yaml     # 定義 替換 value
charts          
templates       # templates(主要工作區) 可以先將裡頭刪除

example

helm-workflow/templates/comfigmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: helm-workflow-configmap
data:
  myvalue: "Hello World"
$ helm install helm-workflow ./helm-workflow        # 嘗試安裝
NAME: helm-workflow
LAST DEPLOYED: Tue Jul 19 17:51:34 2022
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
$ kubectl get cm                                    # 取得 configmap 因為測試是以c onfigmap
NAME                      DATA   AGE
helm-workflow-configmap   1      33s
$ kubectl get cm helm-workflow-configmap -o yaml    # 查看 yaml
apiVersion: v1
data:
  myvalue: Hello World
kind: ConfigMap
metadata:
  annotations:
    meta.helm.sh/release-name: helm-workflow
    meta.helm.sh/release-namespace: default
  creationTimestamp: "2022-07-19T09:51:34Z"
  labels:
    app.kubernetes.io/managed-by: Helm
  name: helm-workflow-configmap
  namespace: default
  resourceVersion: "4767002"
  uid: 667a6b8b-a401-41e2-9852-9238e2476768

Debug 模式

$ helm install --debug --dry-run goodly-guppy ./helm-workflow # --debug --dry-run 這樣才不會真的install
... #輸出全部的資料

$ helm list ./helm-workflow # 驗證chart是否遵循最佳實踐的方式

template

Examle

helm-workflow/templates/comfigmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
$ helm install --debug --dry-run goodly-guppy ./helm-workflow
...
---
# Source: helm-workflow/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: goodly-guppy-configmap    # 基本上這邊就被替換掉了
data:
  myvalue: "Hello World"

常用的模板變數

  • Release - 描述了Release本身
    • Release.Name - Release 名稱
    • Release.Namespace - 指定的NameSpace (如果 manifest 沒覆寫的話)
  • Values - 來自 values.yaml 裡頭 (自定義變數)
  • Chart - 來自 Chart.yaml裡頭 (Helm固定變數)
  • Files - 主要訪問 Chart 專案中的檔案位置,操作指南
    • Files.Get - 打開檔案
    • Files.AsSecrets - 轉 Base64
    • Files.AsConfig - 將檔案反射成 yaml 檔

控制 Chart Template yaml

  • if/else
  • with - 類似 if/else
  • range - 迴圈

Example

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  {{- with .Values.favorite }}
  # 一律建議加上 quote 於 k8s 文件,不然是整數不是String 很容易這邊出錯
  drink: {{ .drink | default "tea" | quote }}    # .Values.favorite.drink 就能使用 .drink 使用
  food: {{ .food | upper | quote }}              # 最前面一樣要按yaml的縮排撰寫不然會錯誤
  {{- if eq .drink "coffee" }}
  mug: "true"
  {{- end }}
  toppings: |-
    {{- range $.Values.pizzaToppings }}          #  在 with 裡頭 要用 $ 指定到最外才能操作 helm 其他模板變數
    - {{ . | title | quote }}
    {{- end }}        
  {{- end }}

常用函數列表 - {{}} 內使用的功能

# values.yaml
theArg1: true
theArg2: false
theNum1: 1
theNum2: 2
theStr1: 'Str1'
theStr2: 'Str2'

animals:
  Mammals:
  - name: Artiodactyla
  - name: Carnivora
  - name: Cetacea
  - name: Chiroptera
  - name: Erinaceomorpha
  - name: Lagomorpha
  - name: Pholidota
  - name: Primates
  - name: Rodentia
  - name: Soricomorpha
# 判斷
key1: {{ and .Values.theArg1 .Values.theArg2 }} # theArg1 == true && theArg2 == true 輸出 boolean
key2: {{ or .Values.theArg1 .Values.theArg2 }} # theArg1 == true || theArg2 == true 輸出 boolean
key3: {{ not .Values.theArg1 }} # theArg1 !== true 輸出 boolean
key4: {{ eq .Values.theArg1 true }} # theArg1 == theArg2 輸出 boolean
key5: {{ ne .Values.theArg1 false }} # theArg1 != theArg2 輸出 boolean
key6: {{ lt .Values.theArg1 false }} # theArg1 < theArg2 輸出 boolean
key7: {{ le .Values.theArg1 false }} # theArg1 <= theArg2 輸出 boolean
key8: {{ gt .Values.theArg1 false }} # theArg1 > theArg2 輸出 boolean
key9: {{ ge .Values.theArg1 false }} # theArg1 >= theArg2 輸出 boolean
key10: {{ default "foo" .Values.theArg1 }} # 如果 theArg1 空的 使用 default
# String
key11: {{ lower "HELLO" }} # 輸出 "hello"
key12: {{ upper "hello" }} # 輸出 "HELLO"
key13: {{ title "hello world" }} # 輸出 "Hello World"
key14: {{ untitle "Hello World" }} # 輸出 "hello world"
key15: {{ repeat 3 "hello" }} # 輸出 "hellohellohello"
key16: {{ "Hello World" | replace " " "-" }} # 輸出 "Hello-World"
key17: {{ snakecase "HttpServer" }} # 輸出 "http_server"
key18: {{ camelcase "http_server" }} # 輸出 "HttpServer"
key19: {{ kebabcase "HttpServer" }} # 輸出 "http-server"
# Type
sample.yaml: |-
  arr: {{ list 1 2 3 | toStrings }}  # 輸出 [1 2 3]  
animals.json: |-
  {{ toJson .Values.animals }} # 輸成JSON {"Mammals":[{"name":"Artiodactyla"},{"name":"Carnivora"},{"name":"Cetacea"},{"name":"Chiroptera"},{"name":"Erinaceomorpha"},{"name":"Lagomorpha"},{"name":"Pholidota"},{"name":"Primates"},{"name":"Rodentia"},{"name":"Soricomorpha"}]}  
# 加密和安全功能
key20: {{ sha1sum "Hello world!" }} # 輸出 SHA1 d3486ae9136e7856bc42212385ea797094475802
key21: {{ sha256sum "Hello world!" }} # 輸出 SHA256 c0535e4be2b79ffd93291305436bf889314e4a3faec05ecffcbb7df31ad9e51a
# Date
key22: {{ now | htmlDate }} # 輸出 2022-07-20

進階模板(1) - 迴圈引用

favorite:
  drink: "coffee"
  food: "apple"
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  {{- range $key, $val := Values.favorite }}
  {{ $key }}: {{ $val | quote }}
  {{- end }}   

進階模板(2) - 變數引用

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  {{- $relname := .Release.Name -}}              # 設置變數
  release: {{ $relname }}                        # 可以用這個變數

template 中的共用模板 - .tpl

狂拆模板,即是唯一解,.tpl,共用定義,簡單介紹一下 templates/ 這資料夾

  • 主要的檔案於此資料夾是處理 K8s yaml files
  • 預設產出的 NOTES.txt 一個例外
  • 名稱以_開頭檔案為內部使用,可導用於任何Chart使用

example

/templates/_helper.tpl

{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
  labels:
    generator: helm
    date: {{ now | htmlDate }}
    chart: {{ .Chart.Name }}
    version: {{ .Chart.Version }}
{{- end }}

/templates/configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
  # 引用 注意 `.` 這樣才能把 .Chart 的相關資訊帶入否則出錯,且若有同 tpl 輸入於同 yaml 請上 indent 這 template function,否則輸出yaml成功但縮排錯誤
  {{- template "mychart.labels" . | indent 2 }}   # 指前方縮格為2字元
data:
  {{- range $key, $val := .Values.favorite }}
  {{ $key }}: {{ $val | quote }}
  {{- end }}

File 檔案讀取 (Helm version > v2.0.2 )

/conf/sample1.yaml

aaa:
  bbb:
    - name: test

/conf/sample2.yaml

token: "qwertyuiopasdfghjklzxcvbnm"
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
{{ (.Files.Glob "conf/*").AsConfig | indent 2 }} 
---
apiVersion: v1
kind: Secret
metadata:
  name: very-secret
type: Opaque
data:
{{ (.Files.Glob "conf/*").AsSecrets | indent 2 }} 
---
apiVersion: v1
kind: Secret
metadata:
  name: {{ .Release.Name }}-secret
type: Opaque
data:
  token: |-
    {{ .Files.Get "/conf/sample2.yaml" | b64enc }} # 確保 base64 for token    

NOTES.txt

在安裝的時候會順勢輸出的相關資訊,給用戶提供如何安裝的細節訊息,非必填之項目,類似README


Charts - 父子層 Chart 關係

$ cd ./charts
$ helm create subchart
Creating subchart
$ rm -rf subchart/templates/*
# 檔案結構
- /helm-workflow/
  |- Charts.yaml
  |- values.yaml
  |- templates/
  |- charts/
    |- subchart/
      |- Charts.yaml
      |- values.yaml
      |- templates/
      |- charts/

父層為: helm-workflow,子層為: subchart

父覆子層的 values

# /helm-workflow/charts/subchart/values.yaml
dessert: cake
# /helm-workflow/values.yaml
subchart:
  dessert: ice cream
$ helm install --dry-run --debug helm-workflow .

可看到 子層的 value 被覆寫

global 全局設值

# /helm-workflow/values.yaml
global:
  name: global-sample # {{ .Values.global.name }} 都能以這方式訪問

後紀

Helm 官網寫得很詳細且有中文,蠻建議跟著官網走一遍應該會收穫不少

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus