เขียน YAML สำหรับ Kubernetes ฉบับเริ่มต้น พร้อมตัวอย่างใช้งานจริง

บทนำ: YAML คืออะไร และทำไมจึงสำคัญสำหรับ Kubernetes

YAML (YAML Ain’t Markup Language) เป็นรูปแบบข้อมูลที่อ่านง่ายและเขียนง่าย ซึ่งใช้กันอย่างแพร่หลายในการกำหนดค่า (Configuration) สำหรับ Kubernetes ทุกครั้งที่คุณต้องการเรียกใช้งาน Pod, Deployment, Service หรือ Resource อื่น ๆ บน Kubernetes คุณจะต้องเขียน YAML manifest เพื่ออธิบายว่าคุณต้องการให้ระบบทำอะไร

เมื่อคุณใช้งาน Cloud VPS ของ ผู้ให้บริการโฮสติ้ง เพื่อรันคลัสเตอร์ Kubernetes ของตัวเอง การเข้าใจ YAML จะช่วยให้คุณสามารถจัดการและปรับแต่งการทำงานของระบบได้อย่างมีประสิทธิภาพ

YAML Syntax พื้นฐาน

1. Indentation (การเยื้อง)

YAML ใช้การเยื้อง (Indentation) เพื่อแสดงโครงสร้างลำดับชั้น (Hierarchy) ของข้อมูล สิ่งสำคัญคือต้องใช้ Space ไม่ใช่ Tab:

parent:
  child: value
  another_child: another_value
  nested:
    deep_value: example

2. Key-Value Pairs (คู่คีย์-ค่า)

ข้อมูลในรูปแบบคู่คีย์และค่า โดยคั่นด้วยเครื่องหมายโคลอน:

name: my-app
version: "1.0.0"
port: 8080
active: true

3. Lists (รายการ)

ใช้เครื่องหมายยัติภังค์ (-) เพื่อสร้างรายการ:

replicas: 3
containers:
  - name: app
    image: myapp:latest
  - name: logger
    image: logger:latest
env:
  - DEBUG=true
  - LOG_LEVEL=INFO

4. Multiline Strings (ข้อความหลายบรรทัด)

สำหรับข้อความยาว ใช้ | (preserve newlines) หรือ > (fold lines):

description: |
  This is a multiline string
  that spans multiple lines
  and preserves line breaks

script: >
  This is a folded string
  that will be converted to
  a single line of text

Kubernetes Manifest Structure

ทุก Kubernetes manifest ประกอบด้วยส่วนสำคัญ 4 ส่วน:

1. apiVersion

ระบุเวอร์ชันของ API ที่ใช้ เช่น v1 หรือ apps/v1 ตัวอย่างเช่น:

  • v1 – Pod, Service, ConfigMap
  • apps/v1 – Deployment, StatefulSet, DaemonSet
  • batch/v1 – Job, CronJob

2. kind

ระบุประเภทของ Resource เช่น Pod, Deployment, Service, StatefulSet เป็นต้น

3. metadata

ข้อมูลที่ใช้ระบุตัวตน เช่น name, namespace, labels, annotations:

metadata:
  name: my-resource
  namespace: production
  labels:
    app: myapp
    version: v1
  annotations:
    description: "My application resource"
    team: backend

4. spec

ข้อมูลรายละเอียดของการตั้งค่า ซึ่งแตกต่างกันไปตามประเภท Resource

ตัวอย่าง 1: เขียน Pod YAML

Pod คือ Unit ที่เล็กที่สุดใน Kubernetes ตัวอย่างนี้สร้าง Pod ที่รัน Nginx container:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  namespace: default
  labels:
    app: nginx
    tier: web
spec:
  containers:
  - name: nginx
    image: nginx:1.21
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
      name: http
    - containerPort: 443
      name: https
    resources:
      requests:
        memory: "64Mi"
        cpu: "100m"
      limits:
        memory: "128Mi"
        cpu: "200m"
  restartPolicy: Always

ในตัวอย่างนี้:

  • apiVersion: v1 – ใช้ API version ของ Pod
  • kind: Pod – ประเภท Resource คือ Pod
  • metadata.name: nginx-pod – ชื่อของ Pod
  • spec.containers – อาร์เรย์ของ Container ที่จะรันใน Pod นี้
  • containerPort: 80 – Port ที่ Container ฟังการเชื่อมต่อ
  • resources.requests – ทรัพยากรที่ Pod ต้องการเสมอ
  • resources.limits – ทรัพยากรสูงสุดที่ Pod สามารถใช้ได้

ตัวอย่าง 2: เขียน Deployment YAML ที่สมบูรณ์

Deployment ใช้สำหรับจัดการ Replicas ของ Pod และอัปเดตแอปพลิเคชันอย่างปลอดภัย:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-deployment
  namespace: default
  labels:
    app: webapp
    version: v2
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
        tier: backend
    spec:
      containers:
      - name: webapp
        image: mywebapp:1.0.5
        imagePullPolicy: Always
        ports:
        - containerPort: 3000
          name: http
        env:
        - name: DATABASE_URL
          value: "postgresql://db:5432/mydb"
        - name: ENVIRONMENT
          value: "production"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5
        resources:
          requests:
            memory: "128Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "1000m"
        volumeMounts:
        - name: config
          mountPath: /etc/config
          readOnly: true
      volumes:
      - name: config
        configMap:
          name: app-config

ในตัวอย่างนี้:

  • replicas: 3 – จะสร้าง 3 Pod พร้อมๆ กัน
  • strategy: RollingUpdate – อัปเดต Pod ทีละตัวเพื่อไม่ให้ service down
  • livenessProbe – ตรวจสอบว่า Container ยังทำงานอยู่หรือไม่
  • readinessProbe – ตรวจสอบว่า Container พร้อมรับ traffic หรือไม่
  • volumeMounts – เชื่อมต่อ Volume เข้ากับ Container

ตัวอย่าง 3: เขียน Service YAML

Service ใช้สำหรับเปิด Pod ไปยังเครือข่ายภายนอก หรือเชื่อมต่อ Pod กันภายในคลัสเตอร์:

apiVersion: v1
kind: Service
metadata:
  name: webapp-service
  namespace: default
  labels:
    app: webapp
spec:
  type: LoadBalancer
  selector:
    app: webapp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000
    nodePort: 30080
    name: http
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800

ในตัวอย่างนี้:

  • type: LoadBalancer – เปิด Pod ไปยังอินเทอร์เน็ตสาธารณะ
  • selector: app: webapp – เลือก Pod ที่มี Label app=webapp
  • port: 80 – Port ของ Service ที่ Client จะใช้
  • targetPort: 3000 – Port ที่แอปพลิเคชันฟัง
  • nodePort: 30080 – Port บน Node ที่ traffic เข้ามา

ตัวอย่าง 4: เขียน ConfigMap และ Secret YAML

ConfigMap ใช้เก็บข้อมูลการตั้งค่าแบบไม่มี Secret:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: default
data:
  LOG_LEVEL: "INFO"
  API_TIMEOUT: "30"
  CACHE_TTL: "3600"
  app.properties: |
    server.port=8080
    server.ssl.enabled=true
    server.ssl.protocol=TLSv1.2
---
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
  namespace: default
type: Opaque
data:
  db-password: cGFzc3dvcmQxMjM=  # base64 encoded
  api-key: c2VjcmV0LWFwaS1rZXk=  # base64 encoded

YAML Anchors & Aliases – ลดการซ้ำซ้อน

ใช้ & เพื่อสร้าง anchor และ * เพื่อใช้ซ้ำ:

defaults: &defaults
  namespace: default
  labels:
    environment: production
    team: backend

---
apiVersion: v1
kind: Pod
metadata:
  <<: *defaults
  name: pod-1
---
apiVersion: v1
kind: Pod
metadata:
  <<: *defaults
  name: pod-2

วิธีนี้ช่วยลดการซ้ำซ้อนของโค้ด YAML

Multi-Document YAML Files

คุณสามารถเก็บ Resource หลายตัวในไฟล์เดียวได้โดยใช้ --- (three dashes) เป็นตัวแบ่ง:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  config.yaml: |
    key: value
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deployment
spec:
  replicas: 1
  template:
    spec:
      containers:
      - name: app
        image: myapp:latest
---
apiVersion: v1
kind: Service
metadata:
  name: app-service
spec:
  ports:
  - port: 80
    targetPort: 3000

ใช้คำสั่ง:

kubectl apply -f multi-resource.yaml

kubectl apply vs kubectl create

มี 2 วิธีในการใช้งาน YAML manifest:

  • kubectl apply -f file.yaml - สร้าง Resource ใหม่ หรืออัปเดต Resource ที่มีอยู่แล้ว (Recommended)
  • kubectl create -f file.yaml - สร้าง Resource ใหม่เท่านั้น ถ้า Resource มีอยู่แล้ว จะเกิดข้อผิดพลาด

โดยทั่วไป ควรใช้ kubectl apply เพราะมันปลอดภัยกว่า

kubectl Dry-Run และ Diff

ก่อนปรับใช้ YAML ควรทำการทดลอง (dry-run) เพื่อดูว่าจะเกิดอะไรขึ้น:

# ตรวจสอบว่า YAML ถูกต้องและจะสร้างอะไร โดยไม่สร้างจริง
kubectl apply -f deployment.yaml --dry-run=client

# ดูความแตกต่างระหว่างไฟล์ปัจจุบันและไฟล์ใหม่
kubectl apply -f deployment.yaml --dry-run=client --output=yaml

# ดู diff ของสิ่งที่จะเปลี่ยน
kubectl diff -f deployment.yaml

YAML Linting Tools

ใช้เครื่องมือเหล่านี้เพื่อตรวจสอบ YAML syntax และ best practices:

# ใช้ kubeval สำหรับ Kubernetes schema validation
kubeval deployment.yaml

# ใช้ kube-linter สำหรับ Best practices
kube-linter lint deployment.yaml

# ใช้ yamllint สำหรับ YAML formatting
yamllint -d relaxed deployment.yaml

# ติดตั้ง kubeval (macOS)
brew install kubeval

Common YAML Mistakes

1. ใช้ Tab แทน Space

ผิด:

parent:
\tchildren: value  # ใช้ Tab

ถูก:

parent:
  children: value  # ใช้ 2 Spaces

2. ลืมใส่ Quotes ในค่าที่มี Special Characters

name: my-app:v1.0  # อาจเกิดข้อผิดพลาด
name: "my-app:v1.0"  # ถูก

3. Indentation ไม่สอดคล้องกัน

containers:
  - name: app
   image: myapp:latest  # Indentation ผิด

Best Practices การเขียน YAML

  • ใช้ 2 Spaces สำหรับ Indentation - มี Convention ที่ยอมรับในชุมชน
  • เพิ่ม Comments - ใช้ # เพื่อเพิ่มหมายเหตุอธิบาย
  • ใช้ Namespaces - แยก Resources ต่าง ๆ ออกจากกันโดยใช้ Namespace
  • ใส่ Labels และ Selectors - ช่วยให้ง่ายต่อการจัดการและค้นหา Resources
  • ตั้งค่า Resource Limits - กำหนด CPU และ Memory requests/limits เสมอ
  • ใส่ Health Checks - เพิ่ม liveness และ readiness probes
  • Version Control - เก็บ YAML files ใน Git repository
  • ใช้ Templates - พิจารณาใช้ Helm หรือ Kustomize สำหรับ YAML ที่ซับซ้อน

Tools ช่วยเหลือสำหรับ YAML

Online YAML Validators

IDE Extensions

  • VS Code: YAML extension, Kubernetes extension
  • JetBrains IDEs: Built-in YAML support

การใช้งาน YAML บน Cloud VPS ของ ผู้ให้บริการโฮสติ้ง

หากคุณสร้าง Kubernetes cluster บน Cloud VPS ของ ผู้ให้บริการโฮสติ้ง การใช้ YAML manifest ที่เขียนดีจะช่วยให้การ Deploy แอปพลิเคชันของคุณง่ายขึ้น ปลอดภัยขึ้น และง่ายต่อการบำรุงรักษา ด้วยความเป็นมืออาชีพและความเสถียรของ Cloud VPS ของ DE คุณสามารถจัดการทรัพยากร Kubernetes ได้อย่างเต็มที่

สรุป

การเขียน YAML สำหรับ Kubernetes อาจดูซับซ้อนตอนแรก แต่เมื่อคุณเข้าใจโครงสร้างพื้นฐาน syntax rules และ best practices คุณจะสามารถสร้างการกำหนดค่าที่ซับซ้อนและมีประสิทธิภาพได้ ต้องจำไว้ว่า:

  • ใช้ Spaces ไม่ใช่ Tab สำหรับ Indentation
  • ทดลอง (Dry-Run) ก่อนปรับใช้งาน
  • ใช้ Linting Tools เพื่อตรวจสอบความถูกต้อง
  • เขียนหมายเหตุ เพื่อให้ผู้อื่นเข้าใจได้
  • ทดลองกับตัวอย่าง เช่นจากบทความนี้เพื่อเรียนรู้

เริ่มด้วยตัวอย่างง่าย ๆ ทดสอบใช้งาน และค่อย ๆ เพิ่มความซับซ้อนให้กับการตั้งค่าของคุณ สำหรับการใช้งาน Kubernetes ระดับมืออาชีพ ศึกษาเพิ่มเติมเกี่ยวกับ Helm Charts และ Kustomize ซึ่งจะช่วยให้คุณจัดการ YAML ได้ดีขึ้น