แยก environment: dev/prod บน cluster เดียวด้วย values
รัน pipeline สองชุด (dev/prod) จาก chart เดียวกัน แยกด้วย namespace + Ingress host และให้ Helm hook ตั้งค่า bucket อัตโนมัติ
พื้นฐานที่ควรรู้: ทีมจริงไม่มีใครแก้ของบน production ตรง ๆ — ต้องมี environment dev ไว้ลองก่อนเสมอ เป้าหมายบทนี้: รัน pipeline สองชุดอิสระจากกันบน kind cluster เดียว (namespace video-dev และ video-prod) โดยใช้ chart จากบทที่แล้วไฟล์เดียวกันเป๊ะ — สิ่งเดียวที่ต่างคือไฟล์ values ของแต่ละ env นี่คือหลัก "build once, deploy many" ที่ทุกทีม DevOps ใช้
chart เหมือนสูตรกลางของแฟรนไชส์ — สาขา food court (dev) ใช้โต๊ะ 1 ตัว วัตถุดิบสต็อกน้อย ส่วนสาขาห้างใหญ่ (prod) จัดเต็มโต๊ะ 2 ตัว สต็อก 10 เท่า — แต่เมนูและวิธีทำเหมือนกันทุกข้อ เพราะมาจากสูตรเดียวกัน ต่างแค่ "ใบสั่งขนาดสาขา" (values-dev.yaml / values-prod.yaml)
แยกทางเข้าด้วย Ingress host
ปัญหาแรก: ทั้งสอง env อยู่หลังพอร์ต localhost:8080 เดียวกัน และต่างก็อยากได้ path / — แยกด้วย path ไม่ได้แล้ว ต้องแยกด้วย hostname (dev.video.local vs video.local) แบบเดียวกับที่บริษัทจริงแยก dev.company.com / company.com — nginx อ่าน Host header จากเบราว์เซอร์แล้ว route ไปถูก namespace เอง
spec:
ingressClassName: nginx
rules:
- host: {{ .Values.ingress.host }}
http:
paths:
# ... /vod → minio และ / → video-api เหมือนเดิมingress:
host: video.localecho "127.0.0.1 video.local dev.video.local" | sudo tee -a /etc/hostsไฟล์ values ของแต่ละ env
กติกาสำคัญ: ไฟล์ values ของ env ใส่เฉพาะค่าที่ต่างจาก default — ค่าที่ไม่เขียนจะ fallback ไปใช้ values.yaml ใน chart อัตโนมัติ (Helm merge ให้) ไฟล์เลยสั้นและอ่านออกทันทีว่า env นี้พิเศษตรงไหน:
api:
replicas: 1
minio:
storage: 1Gi
ingress:
host: dev.video.localapi:
replicas: 2
resources:
requests: { cpu: 200m, memory: 256Mi }
limits: { cpu: "1", memory: 512Mi }
minio:
auth:
pass: pr0d-only-secret # ⚠️ ดู callout เรื่อง secret ท้ายบท
storage: 10Gi
ingress:
host: video.localHelm hook — เลิกตั้ง bucket policy ด้วยมือ
ทุกครั้งที่ติดตั้งเราต้อง kubectl run mc เข้าไปตั้ง anonymous download เอง — กำลังจะติดตั้ง 2 env แปลว่าทำมือ 2 รอบ พอกันที! Helm hook คือ resource ที่ Helm รันให้อัตโนมัติตามจังหวะชีวิตของ release (เช่น หลัง install เสร็จ) — เราใส่ Job ตั้งค่า bucket เป็น post-install hook:
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Release.Name }}-setup-bucket
annotations:
# รันทั้งหลัง install และหลัง upgrade — กัน config หลุดเวลาอัปเกรด
"helm.sh/hook": post-install,post-upgrade
# ลบ Job เก่าก่อนสร้างรอบใหม่ (กันชื่อชน) + สำเร็จแล้วลบตัวเอง
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
backoffLimit: 5
template:
spec:
restartPolicy: Never
containers:
- name: mc
image: minio/mc
command: ["/bin/sh", "-c"]
args:
- |
until mc alias set store http://minio:9000 "$MINIO_USER" "$MINIO_PASS"; do
echo "รอ MinIO ตื่นก่อน..."; sleep 3
done
mc mb --ignore-existing store/uploads store/vod
mc anonymous set download store/vod
echo "ตั้งค่า bucket เรียบร้อย"
env:
- name: MINIO_USER
valueFrom:
secretKeyRef: { name: minio-creds, key: user }
- name: MINIO_PASS
valueFrom:
secretKeyRef: { name: minio-creds, key: pass }ติดตั้งสอง env จาก chart เดียว
helm uninstall video -n video
kubectl delete namespace video
helm install video-dev chart/video-pipeline \
-n video-dev --create-namespace -f chart/values-dev.yaml
helm install video-prod chart/video-pipeline \
-n video-prod --create-namespace -f chart/values-prod.yaml
helm list -A # เห็นทั้งสอง release คนละ namespace
kubectl get pods -n video-dev # api 1 ตัว
kubectl get pods -n video-prod # api 2 ตัว ตามที่ values-prod สั่ง!# เปิดเบราว์เซอร์คนละ env — หน้าตาเหมือนกัน แต่คนละระบบ
open http://dev.video.local:8080
open http://video.local:8080
# อัปโหลดวิดีโอที่ฝั่ง dev แล้วดู:
kubectl get jobs -n video-dev # Job เกิดที่ dev
kubectl get jobs -n video-prod # prod เงียบสนิท = isolation สำเร็จ
# และวิดีโอโผล่เฉพาะหน้าเว็บ dev — prod ไม่เห็นอะไรเลยhelm get values video-prod -n video-prod # ดูว่า prod override อะไรบ้าง
# ปรับเฉพาะ prod — dev ไม่กระทบแม้แต่นิดเดียว
# --atomic = ถ้า upgrade พังกลางทาง ให้ rollback กลับเองอัตโนมัติ (ท่ามาตรฐานเวลาแตะ prod)
helm upgrade video-prod chart/video-pipeline -n video-prod \
-f chart/values-prod.yaml --set api.replicas=3 --atomic
kubectl get pods -n video-prod # 3 ตัว · ฝั่ง dev ยังเท่าเดิมสรุป Key Takeaways
- chart เดียว + values-<env>.yaml = deploy กี่ env ก็ได้ โดยไม่ copy manifest แม้แต่ไฟล์เดียว
- แยก env ด้วย namespace · แยกทางเข้าด้วย Ingress host (Host header) เหมือน subdomain จริง
- ไฟล์ values ใส่เฉพาะค่าที่ต่าง · ลำดับ override: values.yaml < -f < --set
- Helm hook รันงาน setup/migrate ให้อัตโนมัติตามจังหวะของ release
- รหัสผ่าน prod ห้ามลง Git — ใช้ --set จาก CI, SOPS หรือ External Secrets

