it

Skaffold Dev 12 Factor App

Skaffold Dev 12 Factor App
สรุปคำตอบ: Skaffold คือ Google open-source tool สำหรับ continuous development บน Kubernetes ทำงานร่วมกับ 12-Factor App methodology ช่วย automate build-push-deploy cycle ในระหว่าง development ฟีเจอร์หลัก: file sync (code sync โดยไม่ต้อง rebuild), port-forward อัตโนมัติ, multi-profile support (dev/staging/production) และ integration กับ Helm/Kustomize

โดย อ.บอม กิตติทัศน์ | 28/03/2026 | SiamCafe.net Since 1997

Skaffold คืออะไร และแก้ปัญหาอะไร

Skaffold เป็น command-line tool จาก Google ที่ช่วย automate workflow ของ Kubernetes development ปัญหาที่ Skaffold แก้คือ feedback loop ที่ช้าในการพัฒนา Kubernetes application: ทุกครั้งที่แก้ code ต้องรัน docker build, docker push, kubectl apply, รอ pod restart ซึ่งใช้เวลาหลายนาที Skaffold ทำทุกอย่างนี้โดยอัตโนมัติและทำให้เร็วขึ้นมากด้วย file sync

Skaffold release ครั้งแรกโดย Google ในปี 2018 และกลายเป็น CNCF project ในปัจจุบัน ทำงานร่วมกับ builders หลายตัว (Docker, Buildpacks, Bazel, Jib สำหรับ Java) และ deployers หลายตัว (kubectl, Helm, Kustomize)

เนื้อหาเกี่ยวข้อง — Docker Compose V2 Team Productivity

12-Factor App Methodology คืออะไร

12-Factor App เป็น methodology สำหรับสร้าง software-as-a-service app ที่ scale ได้ดี เขียนโดย Adam Wiggins จาก Heroku เหมาะมากสำหรับ containerized applications บน Kubernetes

12 factors สรุปสั้นๆ: I. Codebase: หนึ่ง repo ต่อ app, II. Dependencies: ประกาศ explicit ทุก dependency, III. Config: เก็บ config ใน environment variables, IV. Backing services: ใช้ URL-based service ที่เปลี่ยนได้, V. Build/release/run: แยก stages ชัดเจน, VI. Processes: stateless, share-nothing processes, VII. Port binding: export services via port, VIII. Concurrency: scale ด้วย process model, IX. Disposability: fast startup/graceful shutdown, X. Dev/prod parity: ให้ environments เหมือนกันที่สุด, XI. Logs: stream logs เป็น stdout/stderr, XII. Admin processes: รัน admin tasks เป็น one-off processes

ติดตั้ง Skaffold

# Linux/Mac
curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
sudo install skaffold /usr/local/bin/
skaffold version

# Windows (Chocolatey)
choco install skaffold

# macOS (Homebrew)
brew install skaffold

# ตรวจสอบ
skaffold version

skaffold.yaml: Configuration File พื้นฐาน

# skaffold.yaml - basic setup
apiVersion: skaffold/v4beta6
kind: Config
metadata:
  name: my-app

build:
  artifacts:
    - image: gcr.io/my-project/my-app
      docker:
        dockerfile: Dockerfile
        buildArgs:
          APP_VERSION: "{{.VERSION}}"
      sync:
        # File sync: copy files ตรงเข้า container ไม่ต้อง rebuild
        manual:
          - src: "src/**/*.py"
            dest: /app/src
          - src: "templates/**"
            dest: /app/templates

deploy:
  kubectl:
    manifests:
      - k8s/*.yaml

portForward:
  - resourceType: service
    resourceName: my-app
    port: 8000
    localPort: 8000

profiles:
  - name: dev
    patches:
      - op: replace
        path: /build/artifacts/0/docker/dockerfile
        value: Dockerfile.dev

  - name: production
    deploy:
      helm:
        releases:
          - name: my-app
            chartPath: charts/my-app
            valuesFiles:
              - values-production.yaml

Skaffold Workflow: Dev Loop

# Start dev loop - watch files และ auto-deploy
skaffold dev --profile dev

# ตัวเลือกที่มีประโยชน์
skaffold dev \
  --profile dev \
  --port-forward \
  --cleanup=false \    # ไม่ cleanup resources เมื่อ exit
  --tail                # stream logs

# Build และ deploy ครั้งเดียว (ไม่ watch)
skaffold run --profile staging

# Debug mode - remote debugging
skaffold debug --profile dev

# Build only
skaffold build -t latest

# Render manifests only
skaffold render --profile production > final-manifests.yaml

12-Factor: Config ใน Environment Variables กับ Kubernetes

Factor III ของ 12-Factor คือ Config ต้องเก็บใน environment variables ไม่ใช่ hard-code ใน code Kubernetes รองรับด้วย ConfigMap และ Secret:

# k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_ENV: "production"
  APP_PORT: "8000"
  LOG_LEVEL: "info"
  DATABASE_HOST: "postgres-service"
  DATABASE_PORT: "5432"
  REDIS_HOST: "redis-service"
---
# k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
stringData:
  DATABASE_PASSWORD: "supersecretpassword"
  SECRET_KEY: "production-secret-key"
  API_KEY: "external-api-key"
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    spec:
      containers:
        - name: my-app
          image: gcr.io/my-project/my-app
          envFrom:
            - configMapRef:
                name: app-config
            - secretRef:
                name: app-secrets
          # 12-Factor IX: Disposability - graceful shutdown
          lifecycle:
            preStop:
              exec:
                command: ["sleep", "5"]
          # 12-Factor IX: fast startup
          startupProbe:
            httpGet:
              path: /health
              port: 8000
            failureThreshold: 30
            periodSeconds: 2

เนื้อหาเกี่ยวข้อง — Ubuntu Server 2026

12-Factor: Logs เป็น Event Stream (Factor XI)

Factor XI กำหนดให้ app log ออกมาเป็น unbuffered stdout/stderr ไม่ควร write log ลง file ใน container เอง Kubernetes จะ collect logs เหล่านี้ผ่าน logging infrastructure:

# Python - 12-Factor logging setup
import logging
import sys
import json

class JSONFormatter(logging.Formatter):
    def format(self, record):
        log_obj = {
            "timestamp": self.formatTime(record),
            "level": record.levelname,
            "message": record.getMessage(),
            "module": record.module,
        }
        if record.exc_info:
            log_obj["exception"] = self.formatException(record.exc_info)
        return json.dumps(log_obj, ensure_ascii=False)

# Setup
handler = logging.StreamHandler(sys.stdout)  # stdout ไม่ใช่ file
handler.setFormatter(JSONFormatter())
logging.basicConfig(handlers=[handler], level=logging.INFO)

logger = logging.getLogger(__name__)
logger.info("Application started", extra={"version": "1.0.0"})
# FastAPI app ที่ follow 12-Factor logging
from fastapi import FastAPI, Request
import logging, time, uuid

app = FastAPI()
logger = logging.getLogger(__name__)

@app.middleware("http")
async def log_requests(request: Request, call_next):
    request_id = str(uuid.uuid4())[:8]
    start = time.time()
    response = await call_next(request)
    duration = (time.time() - start) * 1000
    logger.info(
        "HTTP request",
        extra={
            "request_id": request_id,
            "method": request.method,
            "path": request.url.path,
            "status": response.status_code,
            "duration_ms": round(duration, 2),
        }
    )
    return response

Skaffold กับ Helm Integration

Skaffold ทำงานร่วมกับ Helm ได้ดีมาก เหมาะสำหรับ production deployment ที่ต้องการ values ต่างกันในแต่ละ environment:

# skaffold.yaml พร้อม Helm
apiVersion: skaffold/v4beta6
kind: Config

build:
  artifacts:
    - image: my-registry/my-app

deploy:
  helm:
    releases:
      - name: my-app
        chartPath: charts/my-app
        setValues:
          image.repository: my-registry/my-app
          image.tag: "{{.IMAGE_TAG}}"
        valuesFiles:
          - charts/my-app/values.yaml

profiles:
  - name: staging
    deploy:
      helm:
        releases:
          - name: my-app
            setValues:
              replicaCount: 2
              resources.requests.memory: 256Mi
            valuesFiles:
              - charts/my-app/values.yaml
              - charts/my-app/values-staging.yaml

  - name: production
    deploy:
      helm:
        releases:
          - name: my-app
            setValues:
              replicaCount: 5
              autoscaling.enabled: true
              resources.requests.memory: 512Mi
            valuesFiles:
              - charts/my-app/values.yaml
              - charts/my-app/values-production.yaml

12-Factor: Dev/Prod Parity (Factor X)

Factor X คือ keep development, staging, production as similar as possible Skaffold ช่วยเรื่องนี้ด้วย profile system และ Kubernetes-native dev loop ทำให้ code รันใน environment เดียวกัน (Kubernetes) ตั้งแต่ development

แนวทางปฏิบัติสำหรับ dev/prod parity: ใช้ image เดิมในทุก environment เปลี่ยนแค่ configuration, ใช้ database engine เดียวกัน (ไม่ใช้ SQLite ใน dev กับ PostgreSQL ใน prod), ใช้ backing services เดียวกัน (Redis, Elasticsearch) แม้แต่ในการ dev ท้องถิ่น Kubernetes ด้วย minikube หรือ kind ช่วยเรื่องนี้ได้มาก

Skaffold Pipeline ใน CI/CD

# GitHub Actions กับ Skaffold
name: Deploy
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: google-github-actions/setup-gcloud@v2

      - name: Configure Docker
        run: gcloud auth configure-docker

      - name: Install Skaffold
        run: |
          curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
          sudo install skaffold /usr/local/bin/

      - name: Configure kubectl
        run: |
          gcloud container clusters get-credentials my-cluster \
            --zone asia-southeast1-a

      - name: Deploy to staging
        run: |
          skaffold run \
            --profile staging \
            --tag ${{ github.sha }} \
            --default-repo gcr.io/my-project

Skaffold File Sync: เร่งความเร็ว Dev Loop

File sync เป็น feature ที่ทำให้ Skaffold เหมาะมากสำหรับ development เมื่อแก้ไขไฟล์ที่กำหนดไว้ใน sync config Skaffold จะ copy ไฟล์เข้า container โดยตรงโดยไม่ต้อง rebuild image ทำให้ feedback loop จากหลายนาทีลดเหลือไม่กี่วินาที

# skaffold.yaml - sync config
build:
  artifacts:
    - image: my-app
      docker:
        dockerfile: Dockerfile
      sync:
        # Auto sync: ถ้า Dockerfile มี COPY src/ /app/src/
        # Skaffold auto-detect sync paths
        auto: {}

        # หรือกำหนด manual
        manual:
          - src: "**/*.py"
            dest: /app
          - src: "static/**/*"
            dest: /app/static
          - src: "templates/**/*"
            dest: /app/templates

        # Infer จาก Dockerfile COPY instructions
        infer:
          - "**/*.py"

FAQ: Skaffold และ 12-Factor App

Q: Skaffold ต่างจาก Tilt อย่างไร?

A: ทั้งคู่แก้ปัญหา Kubernetes dev loop เหมือนกัน Skaffold เป็น Google project มี integration กับ GKE ดีกว่า Tilt มี Tiltfile ที่ยืดหยุ่นกว่าและรองรับ multi-service development ได้ดีกว่า เลือกตาม preference และ ecosystem ของทีม

Q: 12-Factor App ใช้ได้กับทุกภาษาไหม?

A: ใช่ 12-Factor App เป็น language-agnostic methodology ใช้ได้กับ Python, Node.js, Go, Java, Ruby ทุกภาษา หลักการสำคัญคือ design pattern ไม่ใช่ implementation specifics

Q: Skaffold รองรับ local Kubernetes อะไรบ้าง?

A: minikube, kind, k3s/k3d, Docker Desktop Kubernetes, MicroK8s ทุกตัว Skaffold auto-detect environment และปรับ behavior ให้เหมาะสม เช่น ไม่ push image เมื่อใช้ local registry

Skaffold กับ Local Kubernetes Development

การ setup local Kubernetes development environment ที่ดีด้วย Skaffold ต้องเลือก local cluster ที่เหมาะสม minikube เป็นตัวเลือก classic ที่รองรับ addons มากมาย kind (Kubernetes IN Docker) เหมาะมากสำหรับ CI/CD เพราะ boot เร็วมาก k3s/k3d เบาที่สุดและเหมาะสำหรับ resource-constrained environment

# Setup minikube สำหรับ Skaffold dev
minikube start --driver=docker --cpus=4 --memory=8192
minikube addons enable ingress
minikube addons enable metrics-server

# Skaffold auto-detect minikube และใช้ minikube docker daemon
eval $(minikube docker-env)

# รัน Skaffold dev
skaffold dev --profile dev

# Setup kind สำหรับ CI
kind create cluster --name dev-cluster
kubectl cluster-info --context kind-dev-cluster

Skaffold มีฟีเจอร์ skaffold init ที่ช่วย auto-generate skaffold.yaml จาก existing Dockerfiles และ Kubernetes manifests ในโปรเจค ทำให้เริ่มต้นง่ายมาก:

# Auto-generate skaffold.yaml
skaffold init --generate-manifests

# หรือให้ Skaffold analyze repo แล้วสร้าง config
skaffold init \
  --XXenableJibInit \
  --XXenableBuildpacksInit

12-Factor: Process Model และ Horizontal Scaling

Factor VIII ของ 12-Factor คือ Scale out via the process model หมายความว่า app ควรออกแบบให้ scale โดยการ run multiple processes แทนที่จะ scale up (เพิ่ม resource per instance) Kubernetes HorizontalPodAutoscaler (HPA) ทำ horizontal scaling อัตโนมัติ:

# k8s/hpa.yaml - Horizontal Pod Autoscaler
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 2
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300

12-Factor: Disposability (Factor IX) ใน Practice

Disposability หมายถึง processes ควร start ได้เร็วและ shutdown ได้อย่าง graceful ในทางปฏิบัติบน Kubernetes หมายความว่า pod ต้องรับ SIGTERM signal แล้วทำ graceful shutdown ภายใน terminationGracePeriodSeconds และไม่รับ request ใหม่หลังได้รับ SIGTERM

# Python FastAPI - graceful shutdown
import asyncio
import signal
from contextlib import asynccontextmanager
from fastapi import FastAPI

shutdown_event = asyncio.Event()

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup
    print("Starting up...")
    yield
    # Shutdown - handle gracefully
    print("Shutting down...")
    await asyncio.sleep(5)  # drain in-flight requests

app = FastAPI(lifespan=lifespan)

# Handle SIGTERM
def handle_sigterm(signum, frame):
    print("SIGTERM received, starting graceful shutdown")
    shutdown_event.set()

signal.signal(signal.SIGTERM, handle_sigterm)

Skaffold Debugging: Remote Debug ใน Kubernetes Pod

หนึ่งในฟีเจอร์ที่ดีที่สุดของ Skaffold คือ skaffold debug ที่ช่วยให้ debug code ที่รันอยู่ใน Kubernetes pod ได้จาก local IDE:

# รัน debug mode
skaffold debug --profile dev

# Skaffold จะ:
# 1. Build image พร้อม debug support
# 2. Inject debug container ด้วย port forward
# 3. Python: ใช้ debugpy port 5678
# 4. Node.js: ใช้ --inspect port 9229
# 5. Java: ใช้ JDWP port 5005
# Dockerfile.dev - พร้อม debugpy
FROM python:3.12-slim

RUN pip install debugpy uvicorn fastapi

WORKDIR /app
COPY . .

# Debug mode: ใช้ debugpy เป็น wrapper
CMD ["python", "-m", "debugpy",
     "--listen", "0.0.0.0:5678",
     "--wait-for-client",
     "-m", "uvicorn", "main:app",
     "--host", "0.0.0.0", "--port", "8000"]

ใน VS Code เพิ่ม launch configuration:

{
  "name": "Skaffold Remote Debug",
  "type": "python",
  "request": "attach",
  "connect": {
    "host": "localhost",
    "port": 5678
  },
  "pathMappings": [
    {
      "localRoot": "${workspaceFolder}/src",
      "remoteRoot": "/app/src"
    }
  ]
}

สรุป Skaffold และ 12-Factor App

Skaffold และ 12-Factor App methodology เป็นเครื่องมือและหลักการที่ส่งเสริมกันอย่างดีเยี่ยม Skaffold ทำให้ inner development loop บน Kubernetes เร็วขึ้นอย่างมีนัยสำคัญ ในขณะที่ 12-Factor App ให้หลักการออกแบบที่ทำให้ application พร้อมสำหรับ cloud-native environment ตั้งแต่วันแรก

ทีม engineering ที่นำ Skaffold มาใช้ร่วมกับ 12-Factor principles จะได้ประโยชน์จาก: development environment ที่ consistent กับ production, feedback loop ที่เร็วขึ้น, deployment pipeline ที่ automated และ reproducible, และ application architecture ที่ scale และ operate ได้ง่ายใน Kubernetes

ดูข้อมูลเพิ่มเติมที่ SiamLanCard และ Siam2R | SiamCafe Book

บทความที่เกี่ยวข้อง

XM Legend · เทรดเดอร์ & ผู้สอน Forex 13 ปี

ผู้ก่อตั้ง SiamCafe ตั้งแต่ปี 1997 · เทรดเดอร์สาย Forex มากกว่า 13 ปี ได้รับการยกย่องเป็น XM Legend · แบ่งปันความรู้ Forex, ไอที, AI และการเทรด จากประสบการณ์จริงในตลาดจริง