ข้ามไปเนื้อหาหลัก
คอนเทนเนอร์· ~35 นาที

แยก 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 เหมือนเดิม
📄 templates/ingress.yaml — เพิ่ม host จาก values (ส่วน paths เหมือนเดิม)
ingress:
  host: video.local
📄 values.yaml — เพิ่มค่า default ของ host ท้ายไฟล์
echo "127.0.0.1 video.local dev.video.local" | sudo tee -a /etc/hosts
💻 สอนเครื่องเราให้รู้จักสอง hostname นี้ (ชี้เข้า 127.0.0.1 ทั้งคู่)

ไฟล์ values ของแต่ละ env

กติกาสำคัญ: ไฟล์ values ของ env ใส่เฉพาะค่าที่ต่างจาก default — ค่าที่ไม่เขียนจะ fallback ไปใช้ values.yaml ใน chart อัตโนมัติ (Helm merge ให้) ไฟล์เลยสั้นและอ่านออกทันทีว่า env นี้พิเศษตรงไหน:

api:
  replicas: 1

minio:
  storage: 1Gi

ingress:
  host: dev.video.local
📄 chart/values-dev.yaml — dev เอาเล็กไว้ก่อน ประหยัดเครื่อง
api:
  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.local
📄 chart/values-prod.yaml — prod จัดเต็มกว่า และรหัสผ่านคนละชุด

Helm 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 }
📄 templates/setup-bucket.yaml — Job ที่รันเองหลัง helm install

ติดตั้งสอง 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 สั่ง!
💻 เก็บกวาด release เดี่ยวจากบทที่แล้ว แล้วเปิดสาขา dev + 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 ยังเท่าเดิม
💻 ดูแลแต่ละ env แยกกันอิสระ

สรุป 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
อ่านจบแล้วอย่าลืมทำเครื่องหมาย