แพ็กทั้งระบบเป็น Helm Chart
เขียน Helm chart ของตัวเองจาก manifests ที่มีอยู่ ติดตั้ง/อัปเกรด/ย้อนกลับทั้งระบบด้วยคำสั่งเดียว
พื้นฐานที่ควรรู้: ตอนนี้การ deploy ระบบของเรา = apply ไฟล์ 4 ฉบับตามลำดับ + สร้าง Secret ด้วยมือ + จำว่าต้อง build/load image ก่อน และค่าต่าง ๆ (image tag, ขนาด storage, replicas) ฝังตายอยู่ในไฟล์ — ถ้าอยากได้ระบบชุดที่สอง ต้อง copy ทั้งโฟลเดอร์มาไล่แก้ทีละจุด ใน Module 7 เราเคยใช้ Helm ฝั่ง "ผู้ใช้" (install chart สำเร็จรูปของคนอื่น) — บทนี้เราสลับมาเป็น ผู้เขียน chart เอง: ห่อ manifests ทั้งหมดเป็นแพ็กเกจเดียวที่ประกาศชัดว่า "ค่าไหนปรับได้บ้าง"
Chart เหมือนแม่พิมพ์ขนม — ตัว template คือแม่พิมพ์ (โครงเดิมทุกครั้ง) ส่วน values.yaml คือส่วนผสมที่เทลงไป (รสชาติ/สี/ขนาดเปลี่ยนได้) · อยากได้ขนมอีกถาดที่หวานน้อยลง ไม่ต้องแกะสลักแม่พิมพ์ใหม่ แค่เปลี่ยนส่วนผสม — นี่คือหัวใจของการ deploy หลาย environment ในบทถัดไป
brew install helm
helm version # ต้องเป็น v3.xสร้างโครง chart จาก manifests เดิม
เราไม่ใช้ helm create (มันสร้าง boilerplate ของ nginx มาให้เพียบ ต้องลบทิ้งเกือบหมด) — สร้างเองจากของที่เรามีอยู่แล้วจะเข้าใจทุกบรรทัด:
cd ~/projects/k8s-video-pipeline
mkdir -p chart/video-pipeline/templates
# เอา manifests เดิมมาเป็นตัวตั้ง (kind-config กับ job-test ไม่เอา —
# อันแรกเป็นของระดับ cluster อันหลังเป็นไฟล์ทดสอบมือ)
cp k8s/minio.yaml k8s/api.yaml k8s/rbac.yaml k8s/ingress.yaml \
chart/video-pipeline/templates/apiVersion: v2
name: video-pipeline
description: Video upload & transcoding pipeline (workshop)
type: application
version: 0.1.0 # เวอร์ชันของตัว chart (โครงสร้าง/template)
appVersion: "1.0" # เวอร์ชันของแอปข้างใน (ไว้สื่อสาร ไม่มีผลกับการ deploy)api:
image: video-api:v1
replicas: 1
resources:
requests: { cpu: 100m, memory: 128Mi }
limits: { cpu: 500m, memory: 256Mi }
transcoder:
image: video-transcoder:v1
minio:
auth:
user: admin
pass: password123
storage: 5Giแปลง manifest → template
กติกามี 2 ข้อ: (1) ลบ `namespace: video` ทิ้งทุกบรรทัด — ให้ผู้ติดตั้งเลือก namespace เองตอน helm install -n <ns> chart จะได้ลงที่ไหนก็ได้ · (2) ค่าที่อยากให้ปรับได้ แทนด้วย `{{ .Values.xxx }}` ตาม path ใน values.yaml
sed -i '' '/namespace: video/d' chart/video-pipeline/templates/*.yamlapiVersion: v1
kind: ServiceAccount
metadata:
name: video-api
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: video-api
spec:
replicas: {{ .Values.api.replicas }}
selector:
matchLabels:
app: video-api
template:
metadata:
labels:
app: video-api
spec:
serviceAccountName: video-api
containers:
- name: api
image: {{ .Values.api.image }}
imagePullPolicy: IfNotPresent
env:
- name: MINIO_HOST
value: minio
- name: MINIO_PORT # กัน service links ฉีดทับ (บทเรียนจากบท 8.5)
value: "9000"
- name: MINIO_USER
valueFrom:
secretKeyRef: { name: minio-creds, key: user }
- name: MINIO_PASS
valueFrom:
secretKeyRef: { name: minio-creds, key: pass }
- name: ENABLE_JOBS
value: "true"
- name: JOB_NAMESPACE # บอก API ว่าตัวเองอยู่ namespace ไหน
valueFrom:
fieldRef: { fieldPath: metadata.namespace }
- name: TRANSCODER_IMAGE
value: {{ .Values.transcoder.image }}
ports:
- containerPort: 3000
readinessProbe:
httpGet: { path: /healthz, port: 3000 }
initialDelaySeconds: 3
livenessProbe:
httpGet: { path: /healthz, port: 3000 }
periodSeconds: 10
resources:
{{- toYaml .Values.api.resources | nindent 12 }}
---
apiVersion: v1
kind: Service
metadata:
name: video-api
spec:
selector:
app: video-api
ports:
- port: 80
targetPort: 3000{{ .Values.api.replicas }}— ดึงค่าจาก values.yaml ตาม path ตรง ๆ{{- toYaml .Values.api.resources | nindent 12 }}— ยก block YAML ทั้งก้อนจาก values แล้วเยื้อง 12 ช่องให้พอดีตำแหน่ง (ท่านี้ใช้บ่อยสุดและพังบ่อยสุด — เยื้องผิด YAML เพี้ยนทันที)fieldRef: metadata.namespace(Downward API) — ให้ Pod อ่านค่า namespace ของตัวเองมาเป็น env var → API จะสร้าง Job ใน namespace เดียวกับตัวเองเสมอ ไม่ว่า chart ถูกติดตั้งที่ไหน
โค้ด API ต้องแก้นิดเดียวให้รับ image ของ transcoder จาก env (บรรทัด NAMESPACE เรารับจาก JOB_NAMESPACE อยู่แล้วตั้งแต่บท 8.6):
// เดิม: image: 'video-transcoder:v1',
image: process.env.TRANSCODER_IMAGE || 'video-transcoder:v1',Secret ที่เคยสร้างด้วยมือ (kubectl create secret) ย้ายเข้ามาเป็น template ด้วย — จะได้ติดตั้งครบทั้งระบบในคำสั่งเดียว:
apiVersion: v1
kind: Secret
metadata:
name: minio-creds
stringData: # stringData = เขียน plaintext ได้ K8s encode ให้เอง
user: {{ .Values.minio.auth.user | quote }}
pass: {{ .Values.minio.auth.pass | quote }}# ... ส่วนอื่นเหมือนเดิม (แค่ไม่มีบรรทัด namespace แล้ว)
resources:
requests:
storage: {{ .Values.minio.storage }}subjects:
- kind: ServiceAccount
name: video-api
namespace: {{ .Release.Namespace }} # namespace ที่ release นี้ถูกติดตั้งตรวจก่อนติดตั้ง: lint + template
helm lint chart/video-pipeline
# → 1 chart(s) linted, 0 chart(s) failed
# render ออกมาดูเป็น YAML จริง ๆ ว่าตัวแปรถูกแทนค่าถูกไหม (ยังไม่แตะ cluster)
helm template video chart/video-pipeline | lessติดตั้งด้วย Helm (ล้างของเก่าก่อน)
docker build -t video-api:v1 ./api
kind load docker-image video-api:v1 --name video
kubectl delete namespace video # ลบระบบที่ apply มือไว้ทั้งหมด
helm install video chart/video-pipeline -n video --create-namespace
helm list -n video # → video deployed video-pipeline-0.1.0
kubectl get pods -n video -w # รอจน Running ครบkubectl run mc -n video --rm -it --image=minio/mc --restart=Never --command -- /bin/sh
# mc alias set store http://minio:9000 admin password123
# mc anonymous set download store/vod
# exit
# เปิด http://localhost:8080 อัปโหลด sample.mp4 → ต้องทำงานเหมือนเดิมทุกอย่าง
# (เบื่อไหมที่ต้องตั้ง policy ด้วยมือทุกรอบ? บทหน้าให้ chart ทำเองอัตโนมัติ)พลังของ release: upgrade + rollback
# ขยาย API เป็น 2 ตัวด้วย --set (override ค่าใน values.yaml ชั่วคราว)
helm upgrade video chart/video-pipeline -n video --set api.replicas=2
kubectl get pods -n video # เห็น video-api สองตัว
helm history video -n video # ทุก upgrade = revision ใหม่
helm rollback video 1 -n video # ย้อนกลับ revision แรก → เหลือ 1 ตัวเหมือนเดิมสรุป Key Takeaways
- chart = templates + values.yaml — values คือสัญญาว่าปรับอะไรได้ · ลบ namespace ออกจาก template ให้ -n ตอน install กำหนดแทน
- toYaml + nindent ยก block จาก values · Downward API (fieldRef) ให้ Pod รู้ namespace ตัวเอง
- helm lint + helm template ตรวจก่อนติดตั้งเสมอ
- ทั้งระบบ = release เดียว: upgrade/history/rollback ได้ทั้งก้อน

