👤
Novice Handbook
  • Novice Handbook
  • Guide
  • Internet และ Web
    • HTML
  • Computer Language
    • Basic Computer Language (LV.1)
    • C Language (LV.1)
    • Python3 (LV.1)
  • Operating System
    • Linux
      • Basic Linux (LV.1)
  • TOOLS
    • Text Editor
      • Vim Editor
    • Source Control
      • GitLab
        • GitLab for small site (LV.1)
    • Container
      • Docker
        • Docker (LV.1)
        • Docker (LV.2)
      • Kubernetes
        • Kubernetes Intro (LV.0)
        • Kubernetes Basic (LV.1)
        • Kubernetes Intermediate (LV.2)
        • Helm (LV.2)
        • RKE2 (LV.3)
        • K3S (LV.3)
        • K3D (LV.3)
    • Repository
      • Harbor
        • Harbor for small site (LV.1)
        • Harbor for enterprise (LV.2)
    • Database
      • Redis
        • Redis on Docker Compose (LV.1)
        • Redis on Kubernetes (LV.2)
      • Elastic Stack
        • Elasticsearch & Kibana for small site (LV.1)
    • Observability
      • Prometheus
        • Prometheus for small site (LV.1)
        • Prometheus Operator (LV.2)
    • Security
      • Certbot (LV.1)
      • Falco
      • Hashicorp Vault
    • Collaboration
      • Nextcloud
Powered by GitBook
On this page
  • ขั้นตอนการติดตั้ง Helm
  • macOS
  • Helm Chart
  • เริ่มต้นเรียนรู้ Helm Chart
  • Built-in Object ใน Helm ที่ถูกใช้บ่อยๆ
  • การอ้างถึงค่า Values
  • Template functions และ pipelines
  • function ที่พบได้บ่อยๆใน Helm Chart
  • การใช้ condition ใน Helm Chart
  • การใช้ variable
  • Subchart
  • Global values
  • Chart & Subchart in real-world use case

Was this helpful?

  1. TOOLS
  2. Container
  3. Kubernetes

Helm (LV.2)

Helm เป็นเครื่องมือที่ช่วยจัดการกับ Kubernetes application ผ่านทาง package manager ที่เรียกว่า Helm Chart

ขั้นตอนการติดตั้ง Helm

macOS

brew install helm

Helm Chart

Helm Chart เป็น repo ที่เก็บ template ของหลายๆ Kubernetes resource ที่เกี่ยวข้องกับ application หนึ่งๆ และมีการแยกส่วนของ configuration file ที่ช่วยให้ปรับแต่ง application ง่ายขึ้น

การสร้าง Helm chart ทำได้โดยคำสั่งดังนี้

helm create demo

จะเป็นการสร้าง chart ชื่อ demo

เริ่มต้นเรียนรู้ Helm Chart

เข้าไปใน folder chart demo ด้วยคำสั่งดังนี้

cd demo

ภายใน folder จะประกอบด้วยโครงสร้าง file ดังต่อไปนี้

├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml

ให้ทำการลบไฟล์ใน folder template ทิ้งทั้งหมดก่อน และ clear content ใน values.yaml

rm -rf templates/*
echo > values.yaml

หลังจากนั้นสร้างไฟล์ configmap.yaml ใน folder templates

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"

ทดสอบ render output ด้วยคำสั่งดังนี้

helm template myrelease .

จะได้ผลลัพธ์ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mychart-configmap
data:
  myvalue: "Hello World"

จะเห็นว่าเราสามารถ render yaml output ตามที่ต้องการได้ ผ่านการสร้าง file และ content ใน folder templates

เวลาที่ใช้คำสั่งแล้วผลลัพธ์ไม่ออก บางทีอาจจะเกิดจาก template ผิด ให้ลองใช้ mode debug แทน โดยการใส่ option --debug ต่อท้าย เช่น helm template myrelease . --debug

หลังจากนั้น ให้แก้ไขไฟล์เป็นดังนี้

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

ทดสอบ render อีกรอบ จะได้ผลลัพธ์ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"

จะเห็นว่าส่วน {{ .Release.Name }} จะถูกแทนที่ด้วยคำว่า myrelease ที่เป็นเช่นนั้น เพราะว่าจาก command ของเรา จะมี pattern ดังนี้

helm template <release name> <chart location>

release name จะเป็นชื่อ release ที่จะต้องชื่อที่ไม่ซ้ำกันภายใน namespace นั้นๆ เพราะเราสามารถติดตั้ง application ประเภทเดียวกันได้ใน namespace เดียวกัน การมี release name จะทำให้เราสามารถ refer ได้ว่า Kubernetes resource นั้นเป็นของ application ไหน

chart location คือตำแหน่งที่เก็บ Chart.yaml ซึ่งในกรณีตัวอย่าง คือ current folder ที่เราอยู่ ซึ่งในกรณีแทนที่ได้ด้วย .

จะเห็นได้ว่าหากเราอยากให้ส่วนไหนใน Helm Chart ถูก render แบบ dynamic จะต้องเขียนไว้ในส่วนระหว่าง {{ และ }}

Built-in Object ใน Helm ที่ถูกใช้บ่อยๆ

Release เป็น Object ที่ให้รายละเอียดเกี่ยวกับ release นั้นๆ Release.name เป็นชื่อของ release Release.namespace เป็น namespace ที่ติดตั้ง release นั้น

Values เป็น Object ที่ refer ถึงค่าใน values.yaml และจากค่าที่ user pass ให้ทาง cli

Chart เป็น Object ที่ refer ถึง content ใน Chart.yaml ส่วนที่มักจะถูกใช้งานคือ Chart.Name และ Chart.Version

การอ้างถึงค่า Values

เปลี่ยน content ของ values.yaml เป็นดังนี้

values.yaml
favoriteDrink: coffee

เปลี่ยน content ของ templates/configmap.yaml เป็นดังนี้

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

ทดสอบ render จะได้ผลลัพธ์ดังนี้

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

ลอง override ค่าด้วยคำสั่ง set ดังนี้

helm template myrelease . --set favoriteDrink=slurm

จะได้ผลลัพธ์ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: "Hello World"
  drink: slurm

จะเห็นว่าคำสั่ง set สามารถ override ค่าทับ values ของ values.yaml ได้

ลองเพิ่มค่าอื่นๆลงใน values.yaml เพิ่มเติม

values.yaml
favorite:
  drink: coffee
  food: pizza

แก้ไข templates/configmap.yaml ดังนี้

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 .

จะได้ผลลัพธ์ดังนี้

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

จะเห็นว่าเราสามารถ refer ค่าใน values ที่ถูกจัดเป็น structure ได้ ซึ่งจะทำให้ configuration เป็นระเบียบมากขึ้น

Template functions และ pipelines

แก้ไขค่าใน templates/configmap.yaml ดังนี้

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

จะได้ผลลัพธ์จากการ render ดังนี้

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

ในที่นี้ quote คือ function หนึ่งใน Helm Chart และค่าใดๆที่ตามหลัง function จะเป็น argument ของ function นั้น

function quote นี้รับค่าเข้าไป และทำการ render ผลลัพธ์ออกมาเป็น string ที่ถูกครอบด้วย double quote (")

หลังจากนั้นลองแก้ไขค่าใน templates/configmap.yaml อีกรอบ

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

จะได้ผลลัพธ์จากการ render ดังนี้

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

ในที่นี้ เรามีการใช้ pipeline ( | ) ร่วมกับ function quote แสดงให้เห็นว่า ค่าใดๆก็ตามที่อยู่ก่อนหน้า pipeline จะถูก pass ไปเป็น argument สุดท้ายของ function หลัง pipeline

นอกจากนี้เรายังสามารถใช้ pipeline ร่วมกับหลายๆ function ได้อีกด้วย

ลองแก้ไขค่าใน templates/configmap.yaml ดังนี้

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

จะได้ผลลัพธ์จากการ render ดังนี้

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

คำว่า pizza จะถูกเปลี่ยนเป็น PIZZA ตัวพิมพ์ใหญ่ด้วย function upper ก่อนใส่ quote

pattern นี้เป็นสิ่งที่เราจะเห็นได้บ่อย เวลาใช้งาน Helm Chart

function ที่พบได้บ่อยๆใน Helm Chart

function default

ลองแก้ไขค่าใน templates/configmap.yaml ดังนี้

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

comment values ใน values.yaml

favorite:
  #drink: coffee
  food: pizza

จะได้ผลลัพธ์จากการ render ดังนี้

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

function printf

ลองแก้ไขค่าใน templates/configmap.yaml ดังนี้

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

จะได้ผลลัพธ์จากการ render ดังนี้

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

function trim

ลองแก้ไขค่าใน templates/configmap.yaml ดังนี้

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  myvalue: {{ "  Hello World  " | trim }}
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}

จะได้ผลลัพธ์จากการ render ดังนี้

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

function trunc

ลองแก้ไขค่าใน templates/configmap.yaml ดังนี้

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  myvalue: {{ "  Hello World  " | trim | trunc 5 }}
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}

จะได้ผลลัพธ์จากการ render ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: Hello
  drink: "tea"
  food: "PIZZA"

function toString

ลองแก้ไขค่าใน templates/configmap.yaml ดังนี้

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  myvalue: {{ list 1 2 3 | toString }}
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}

จะได้ผลลัพธ์จากการ render ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: [1 2 3]
  drink: "tea"
  food: "PIZZA"

function toYaml

แก้ไขค่าใน values.yaml ดังนี้

values.yaml
favorite:
  #drink: coffee
  food: pizza
data:
  foo: bar

ลองแก้ไขค่าใน templates/configmap.yaml ดังนี้

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  myvalue: {{ "  Hello World  " | trim | trunc 5 }}
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
  data:
    {{ toYaml .Values.data }}

จะได้ผลลัพธ์จากการ render ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: [1 2 3]
  drink: "tea"
  food: "PIZZA"
  data: 
    foo: bar

การใช้ condition ใน Helm Chart

การใช้ if และ end

แก้ไขค่าใน values.yaml ดังนี้

values.yaml
favorite:
  #drink: coffee
  food: pizza
enableData: true
data:
  foo: bar

ลองแก้ไขค่าใน templates/configmap.yaml ดังนี้

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  myvalue: {{ list 1 2 3 | toString }}
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
{{ if .Values.enableData }}  data:
    {{ toYaml .Values.data }}{{ end }}
  any: any

จะได้ผลลัพธ์จากการ render ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: [1 2 3]
  drink: "tea"
  food: "PIZZA"
  data: 
    foo: bar
  any: any

ปัญหาของการวาง code ในลักษณะนี้จะทำให้เกิดปัญหาด้าน readability เพื่อแก้ปัญหานั้น หน้าตาของ template/configmap.yaml ที่เราอยากได้ จะเป็นดังนี้

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  myvalue: {{ list 1 2 3 | toString }}
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
  {{ if .Values.enableData }}
  data:
    {{ toYaml .Values.data }}
  {{ end }}
  any: any

จะได้ผลลัพธ์จากการ render ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: [1 2 3]
  drink: "tea"
  food: "PIZZA"

  data: 
    foo: bar

  any: any

สาเหตที่เกิด whitespace ขึ้น เกิดจากการที่เรามีการ whitespace & newline ในส่วนอื่นๆของ content ในบริบทรอบข้าง {{ if }} และ {{ end }}

การแก้ไขปัญหา ทำได้โดยเพิ่ม - และ whitespace เพื่อบอกให้ engine ลบ whitespace ทิ้ง

แก้ไข templates/configmap.yaml ดังนี้

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  myvalue: {{ list 1 2 3 | toString }}
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
  {{- if .Values.enableData }}
  data:
    {{ toYaml .Values.data }}
  {{- end }}
  any: any

เป็นการบอกให้ engine ลบ whitespace และ newline ฝั่งซ้ายของ {{ if }} และ {{ end }}

จะได้ผลลัพธ์จากการ render ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: [1 2 3]
  drink: "tea"
  food: "PIZZA"
  data:
    foo: bar
  any: any

หากเปลี่ยนค่า enableData เป็น false จะได้ผลลัพธ์ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: [1 2 3]
  drink: "tea"
  food: "PIZZA"
  any: any

function indent และ nindent

ในบางกรณีเราอยากจะให้ function เป็นตัวกำหนดจำนวน whitespace charcter ของต้นบรรทัดนั้นๆ แทนที่จะพิมพ์ whitespace ลงไปตรงๆ ซึ่งผิดพลาดได้ง่าย เราสามารถใช้ function indent ทำหน้าที่นั้นแทนได้

หากลองแก้ไข templates/configmap.yaml ดังนี้

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  myvalue: {{ list 1 2 3 | toString }}
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
  {{- if .Values.enableData }}
  data:
{{ toYaml .Values.data | indent 4 }}
  {{- end }}
  any: any

และแก้ไขค่า enableData เป็น true จะได้ผลลัพธ์ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  myvalue: [1 2 3]
  drink: "tea"
  food: "PIZZA"
  data:
    foo: bar
  any: any

แต่การแก้ไขลักษณะนี้จะทำให้เราเสีย readability ไป ดังนั้นเราสามารถแก้ไขได้โดยการใส่ whitespace ลงไป แล้วใช้ - ในการลบ whitespace ก่อนหน้าแทน

หากลองแก้ไข templates/configmap.yaml ดังนี้

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  myvalue: {{ list 1 2 3 | toString }}
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
  {{- if .Values.enableData }}
  data:
    {{- toYaml .Values.data | indent 4 }}
  {{- end }}
  any: any

ลองสั่งด้วย mode debug (helm template myrelease . --debug) จะได้ผลลัพธ์ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  myvalue: [1 2 3]
  drink: "tea"
  food: "PIZZA"
  data:    foo: bar
  any: any

จะเห็นว่าผลลัพธ์ออกมาผิด

ในกรณีนี้เราสามารถแก้ไขได้โดยใช้ function nindent แทน indent ซึ่ง nindent จะทำให้เกิดการขึ้นบรรทัดใหม่ แล้วค่อย indent

หากลองแก้ไข templates/configmap.yaml ดังนี้

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  myvalue: {{ list 1 2 3 | toString }}
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
  {{- if .Values.enableData }}
  data:
    {{- toYaml .Values.data | nindent 4 }}
  {{- end }}
  any: any

จะได้ผลลัพธ์ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  myvalue: [1 2 3]
  drink: "tea"
  food: "PIZZA"
  data:
    foo: bar
  any: any

ผลลัพธ์จะออกมาถูกต้องแล้ว

การใช้ with

จากตัวอย่างก่อนหน้าจะเห็นว่า เรา refer ค่าของ favorite drink และ favorite food โดยการ refer ไปยัง value ใน nested scope ใต้ .Values.favorite ซึ่งทำให้เกิดการเขียน .Values.favorite ซ้ำกัน เราสามารถลดการพิมพ์ซ้ำๆนั้นได้โดยการใช้ function with และ refer value ใต้ current scope นั้น ดังนี้

แก้ไข templates/configmap.yaml

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  myvalue: {{ list 1 2 3 | toString }}
  {{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
  {{- end }}
  {{- if .Values.enableData }}
  data:
    {{- toYaml .Values.data | nindent 4 }}
  {{- end }}
  any: any

จะได้ผลลัพธ์ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  myvalue: [1 2 3]
  drink: "tea"
  food: "PIZZA"
  data:
    foo: bar
  any: any

การใช้ loop ด้วย function range

แก้ไขไฟล์ values.yaml ดังนี้

values.yaml
favorite:
  #drink: coffee
  food: pizza
enableData: true
data:
  foo: bar
pizzaToppings:
  - mushrooms
  - cheese
  - peppers
  - onions

แก้ไข templates/configmap.yaml

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  myvalue: {{ list 1 2 3 | toString }}
  {{- with .Values.favorite }}
  drink: {{ .drink | default "tea" | quote }}
  food: {{ .food | upper | quote }}
  {{- end }}
  toppings: |-
    {{- range .Values.pizzaToppings }}
    - {{ . | title | quote }}
    {{- end }}

จะได้ผลลัพธ์จากการ render ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  myvalue: [1 2 3]
  drink: "tea"
  food: "PIZZA"
  toppings: |-
    - "Mushrooms"
    - "Cheese"
    - "Peppers"
    - "Onions"

การใช้ variable

ใน helm เราสามารถ define variable ได้โดยการเขียนให้อยู่ในรูป $name และ assign ค่าให้กับ variable นั้นได้ด้วยเครื่องหมาย :=

ทดสอบแก้ไข templates/configmap.yaml ดังนี้

templates/configmap.yaml
{{- $fixedstr := "test" -}}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  toppings: |-
    {{- range .Values.pizzaToppings }}
    - {{ . | title | quote }}
    - {{ $fixedstr | quote }}
    {{- end }}

จะได้ผลลัพธ์จากการ render ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  toppings: |-
    - "Mushrooms"
    - "test"
    - "Cheese"
    - "test"
    - "Peppers"
    - "test"
    - "Onions"
    - "test"

ตัวอย่างการใช้ร่วมกับ range

ทดสอบแก้ไข templates/configmap.yaml ดังนี้

templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  {{- range $key, $val := .Values.favorite }}
  {{ $key }}: {{ $val | quote }}
  {{- end }}

จะได้ผลลัพธ์จากการ render ดังนี้

---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: release-name-configmap
data:
  food: "pizza"

Subchart

ในเนื้อหาที่ผ่านมา เรามีการสร้าง chart สำหรับ application หนึ่ง แต่ในความเป็นจริง มีโอกาสบ่อยครั้งที่หลายๆ application จะต้องการอีก application หนึ่งในการทำงานร่วมกัน เช่น ทั้ง application A และ application B ต้องการ redis เพื่อใช้งานร่วมกัน แต่เป็น redis คนละตัว ไม่ share กัน เราก็ไม่ควรจะต้องเขียน manifest ของ redis ลงในทั้ง chart ของ application A และ application B

ทางแก้หนึ่งก็คือ แยก chart redis ออกมา และบอกให้ chart ของ application A และ B รู้ว่า เมื่อจะ deploy application A และ B จะต้องมีการ deploy redis ด้วยเช่นกัน

การเขียนให้ chart ของ application A และ B ไป depend กับ chart redis นี้ เราจะเรียกว่า เป็นการกำหนดให้ redis เป็น subchart ของ chart application A

การจะ pass values เข้าไปให้ subchart redis ได้นั้น จะต้องอาศัยการ pass ผ่าน global values

สร้าง subchart

cd charts
helm create mysubchart
rm -rf mysubchart/templates/*
echo 'dessert: cake' > mysubchart/values.yaml
cd ..

ใส่ content ของ charts/mysubchart/templates/configmap.yaml ดังนี้

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-cfgmap2
data:
  dessert: {{ .Values.dessert }}

ทดสอบ render ด้วยคำสั่ง ดังนี้

helm template myrelease .

จะได้ผลลัพธ์ดังนี้

---
# Source: demo/charts/mysubchart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-cfgmap2
data:
  dessert: cake
---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  food: "pizza"

จะพบว่ามี configmap ของ subchart เพิ่มขึ้นมา

การ override value ของ subchart ผ่าน parent chart

เราจะใส่ values ในไฟล์ values.yaml เพิ่ม 2 บรรทัดท้าย ดังนี้

favorite:
  #drink: coffee
  food: pizza
enableData: true
data:
  foo: bar
pizzaToppings:
  - mushrooms
  - cheese
  - peppers
  - onions

mysubchart:
  dessert: ice cream

ทดสอบ render จะได้ผลลัพธ์ดังนี้

---
# Source: demo/charts/mysubchart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-cfgmap2
data:
  dessert: ice cream
---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  food: "pizza"

จะเห็นว่า ใน value file ท่อน mysubchart ซึ่งตรงกับชื่อของ subchart ที่เราได้สร้างไว้ ค่าใดๆก็ตามภายใต้นั้นจะถูก pass ลงไปยัง subchart

ถ้าสร้าง subchart เป็นชื่ออื่น ต้องแก้ชื่อใน value file ตามด้วย

Global values

ในบางกรณีเราต้องการ pass value ที่ share ร่วมกันในหลายๆ subchart เราสามารถเขียนได้ภายใต้ .Values.global ซึ่งจะทำให้เราไม่ต้อง maintain value หลายจุดในแต่ละ value สำหรับ subchart

แก้ values ในไฟล์ values.yaml เพิ่ม 2 บรรทัดท้าย ดังนี้

favorite:
  #drink: coffee
  food: pizza
enableData: true
data:
  foo: bar
pizzaToppings:
  - mushrooms
  - cheese
  - peppers
  - onions

mysubchart:
  dessert: ice cream

global:
  salad: caesar

แก้ templates/configmap.yaml ดังนี้

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ printf "%s-configmap" .Release.Name }}
data:
  {{- range $key, $val := .Values.favorite }}
  {{ $key }}: {{ $val | quote }}
  {{- end }}
  salad: {{ .Values.global.salad }}

แก้ charts/mysubchart/templates/configmap.yaml ดังนี้

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-cfgmap2
data:
  dessert: {{ .Values.dessert }}
  salad: {{ .Values.global.salad }}

ทดสอบ render จะได้ผลลัพธ์ดังนี้

---
# Source: demo/charts/mysubchart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-cfgmap2
data:
  dessert: ice cream
  salad: caesar
---
# Source: demo/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myrelease-configmap
data:
  food: "pizza"
  salad: caesar

Chart & Subchart in real-world use case

ในการใช้งานจริง เราจะไม่ทำ subchart เป็น folder ภายใต้ chart ติดไปด้วยกัน แต่จะใช้การ refer ผ่าน helm dependencies แทนเพื่อสะดวกต่อการ maintain

เราจะกำหนด dependencies ภายใน Chart.yaml ดังนี้

dependencies:
- condition: memcached.enabled
  name: memcached
  repository: oci://registry-1.docker.io/bitnamicharts
  version: 7.x.x
- condition: mariadb.enabled
  name: mariadb
  repository: oci://registry-1.docker.io/bitnamicharts
  version: 19.x.x
- name: common
  repository: oci://registry-1.docker.io/bitnamicharts
  tags:
  - bitnami-common
  version: 2.x.x

จากตัวอย่างจะมีการ refer ให้หา chart จาก oci://registry-1.docker.io/bitnamicharts โดยจะมี chart memcached, mariadb และ common ตาม version ที่กำหนดในท่อน version และจะถูกใช้ต่อเมื่อ ใน values.yaml แต่ละ value ของ subchart มีการกำหนด enabled ให้มีค่าเป็น true

ในเคสที่ subchart มีชื่อตรงกับ value อื่นๆ เราสามารถเปลี่ยนชื่อ subchart ได้โดยใช้ alias ทำให้เราสามารถใช้ alias name แทนใน values.yaml ได้

เช่น

dependencies:
- condition: database.enabled
  name: mariadb
  repository: oci://registry-1.docker.io/bitnamicharts
  version: 19.x.x
  alias: database

ตัวอย่างบางท่อนของ values.yaml

mariadb:
  enabled: true
  architecture: standalone

PreviousKubernetes Intermediate (LV.2)NextRKE2 (LV.3)

Last updated 6 months ago

Was this helpful?

ตัวอย่างจาก

https://github.com/bitnami/charts/blob/main/bitnami/wordpress/Chart.yaml