Skaffold Dev SaaS Architecture คืออะไร

Skaffold เป็น open source CLI tool จาก Google ที่ช่วย automate development workflow สำหรับ Kubernetes applications ทำให้ build, push และ deploy เร็วขึ้นด้วย hot-reload SaaS (Software as a Service) Architecture คือการออกแบบระบบ software ที่ให้บริการผ่าน cloud แบบ multi-tenant subscription-based การรวมสองแนวคิดนี้ช่วยให้ทีม development สร้าง SaaS applications บน Kubernetes ได้เร็วขึ้น ด้วย inner development loop ที่ smooth และ architecture ที่ scalable

Skaffold Fundamentals

# skaffold_basics.py — Skaffold fundamentals
import json

class SkaffoldBasics:
 FEATURES = {
 "build": {
 "name": "Build",
 "description": "สร้าง container images อัตโนมัติ — Docker, Buildpacks, Jib, Ko",
 "options": ["Docker", "Google Cloud Build", "Buildpacks", "Jib (Java)", "Ko (Go)"],
 },
 "deploy": {
 "name": "Deploy",
 "description": "Deploy ไป Kubernetes อัตโนมัติ — kubectl, Helm, Kustomize",
 "options": ["kubectl", "Helm", "Kustomize", "Cloud Run"],
 },
 "dev": {
 "name": "Dev Mode (skaffold dev)",
 "description": "Watch files → auto build → auto deploy → stream logs",
 "benefit": "Inner development loop เร็วมาก — เปลี่ยน code → เห็นผลใน K8s ทันที",
 },
 "debug": {
 "name": "Debug",
 "description": "Remote debugging สำหรับ containers ที่รันใน K8s",
 "support": "Go, Java, Node.js, Python",
 },
 "profiles": {
 "name": "Profiles",
 "description": "Configuration สำหรับ environments ต่างๆ — dev, staging, production",
 },
 }

 SKAFFOLD_YAML = """
# skaffold.yaml — Basic configuration
apiVersion: skaffold/v4beta6
kind: Config
metadata:
 name: my-saas-app

build:
 artifacts:
 - image: my-saas-api
 context: services/api
 docker:
 dockerfile: Dockerfile
 - image: my-saas-worker
 context: services/worker
 - image: my-saas-web
 context: services/web
 local:
 push: false
 useBuildkit: true

deploy:
 helm:
 releases:
 - name: my-saas
 chartPath: charts/my-saas
 valuesFiles:
 - charts/my-saas/values-dev.yaml
 setValueTemplates:
 api.image: "{{.IMAGE_FULLY_QUALIFIED_my_saas_api}}"
 worker.image: "{{.IMAGE_FULLY_QUALIFIED_my_saas_worker}}"
 web.image: "{{.IMAGE_FULLY_QUALIFIED_my_saas_web}}"

profiles:
 - name: dev
 activation:
 - command: dev
 patches:
 - op: replace
 path: /deploy/helm/releases/0/valuesFiles/0
 value: charts/my-saas/values-dev.yaml
 
 - name: staging
 build:
 artifacts:
 - image: gcr.io/my-project/my-saas-api
 context: services/api
 deploy:
 helm:
 releases:
 - name: my-saas
 chartPath: charts/my-saas
 valuesFiles: [charts/my-saas/values-staging.yaml]

portForward:
 - resourceType: service
 resourceName: my-saas-api
 port: 8080
 localPort: 8080
 - resourceType: service
 resourceName: my-saas-web
 port: 3000
 localPort: 3000
"""

 def show_features(self):
 print("=== Skaffold Features ===\n")
 for key, f in self.FEATURES.items():
 print(f"[{f['name']}]")
 print(f" {f['description']}")
 print()

 def show_yaml(self):
 print("=== skaffold.yaml ===")
 print(self.SKAFFOLD_YAML[:500])

basics = SkaffoldBasics()
basics.show_features()
basics.show_yaml()

SaaS Architecture Design

# saas_arch.py — SaaS architecture design
import json

class SaaSArchitecture:
 COMPONENTS = {
 "api_gateway": {
 "name": "API Gateway",
 "description": "Entry point — routing, rate limiting, authentication",
 "options": "Kong, Traefik, NGINX Ingress, AWS API Gateway",
 },
 "auth": {
 "name": "Authentication & Authorization",
 "description": "User management, JWT, OAuth2, multi-tenant isolation",
 "options": "Auth0, Keycloak, Supabase Auth, custom JWT",
 },
 "api_services": {
 "name": "API Services (Microservices)",
 "description": "Business logic แยกตาม domain — users, billing, core features",
 "options": "FastAPI (Python), Express (Node), Go services",
 },
 "database": {
 "name": "Database (Multi-tenant)",
 "description": "เก็บข้อมูล tenant — shared DB, schema-per-tenant, or DB-per-tenant",
 "options": "PostgreSQL, MongoDB, CockroachDB",
 },
 "message_queue": {
 "name": "Message Queue",
 "description": "Async processing — background jobs, events, notifications",
 "options": "Redis (BullMQ), RabbitMQ, Kafka",
 },
 "billing": {
 "name": "Billing & Subscription",
 "description": "จัดการ plans, payments, invoices",
 "options": "Stripe, Paddle, custom billing service",
 },
 }

 MULTI_TENANT = {
 "shared_db": {
 "name": "Shared Database (tenant_id column)",
 "pros": "ง่าย, ประหยัด, scale ง่าย",
 "cons": "Isolation ต่ำ, noisy neighbor risk",
 "use": "SaaS ขนาดเล็ก-กลาง, tenants ไม่ต้องการ isolation สูง",
 },
 "schema_per_tenant": {
 "name": "Schema per Tenant",
 "pros": "Isolation ดีกว่า, migration ง่ายกว่า DB-per-tenant",
 "cons": "Schema จำนวนมาก, connection pooling ซับซ้อน",
 "use": "SaaS กลาง-ใหญ่, ต้องการ data isolation ระดับหนึ่ง",
 },
 "db_per_tenant": {
 "name": "Database per Tenant",
 "pros": "Isolation สูงสุด, backup/restore per tenant",
 "cons": "แพง, ดูแลยาก, ไม่ scale ถ้า tenants เยอะ",
 "use": "Enterprise SaaS, compliance requirements (PDPA, HIPAA)",
 },
 }

 def show_components(self):
 print("=== SaaS Components ===\n")
 for key, comp in self.COMPONENTS.items():
 print(f"[{comp['name']}]")
 print(f" {comp['description']}")
 print()

 def show_multi_tenant(self):
 print("=== Multi-tenant Strategies ===")
 for key, mt in self.MULTI_TENANT.items():
 print(f"\n[{mt['name']}]")
 print(f" Pros: {mt['pros']}")
 print(f" Cons: {mt['cons']}")

arch = SaaSArchitecture()
arch.show_components()
arch.show_multi_tenant()

Development Workflow

# dev_workflow.py — Skaffold development workflow
import json

class DevWorkflow:
 COMMANDS = """
# Skaffold CLI commands
skaffold dev # Watch + build + deploy + logs (main command)
skaffold dev --port-forward # + auto port forward
skaffold dev --trigger=polling # Poll for changes (ไม่ใช้ file watcher)
skaffold run # One-time build + deploy
skaffold run -p staging # Deploy with staging profile
skaffold debug # Dev mode + remote debugger attached
skaffold render # Output rendered K8s manifests (dry-run)
skaffold build # Build images only
skaffold delete # Clean up deployed resources
skaffold diagnose # Check config for issues
"""

 PROJECT_STRUCTURE = """
# SaaS project structure with Skaffold
my-saas/
├── skaffold.yaml # Skaffold config
├── services/
│ ├── api/
│ │ ├── Dockerfile
│ │ ├── src/
│ │ │ ├── main.py # FastAPI app
│ │ │ ├── routers/
│ │ │ ├── models/
│ │ │ └── middleware/
│ │ │ └── tenant.py # Multi-tenant middleware
│ │ └── requirements.txt
│ ├── worker/
│ │ ├── Dockerfile
│ │ └── src/
│ │ └── tasks.py # Background workers
│ └── web/
│ ├── Dockerfile
│ └── src/ # Next.js frontend
├── charts/
│ └── my-saas/
│ ├── Chart.yaml
│ ├── values.yaml
│ ├── values-dev.yaml
│ ├── values-staging.yaml
│ └── templates/
│ ├── api-deployment.yaml
│ ├── worker-deployment.yaml
│ └── web-deployment.yaml
├── migrations/
│ └── 001_initial.sql
└── scripts/
 └── seed.py
"""

 FAST_DEV = """
# fast_dev.py — Optimize Skaffold dev loop
# skaffold.yaml additions for faster dev:

build:
 artifacts:
 - image: my-saas-api
 context: services/api
 sync:
 manual:
 - src: "src/**/*.py"
 dest: /app/src
 docker:
 dockerfile: Dockerfile
 cacheFrom: ["my-saas-api:latest"]

# With file sync, Python changes sync directly to container
# without rebuilding Docker image → < 2 second feedback loop
# Combine with uvicorn --reload for instant hot-reload
"""

 def show_commands(self):
 print("=== Skaffold Commands ===")
 print(self.COMMANDS[:500])

 def show_structure(self):
 print(f"\n=== Project Structure ===")
 print(self.PROJECT_STRUCTURE[:500])

 def show_fast_dev(self):
 print(f"\n=== Fast Dev Loop ===")
 print(self.FAST_DEV[:400])

wf = DevWorkflow()
wf.show_commands()
wf.show_structure()

SaaS API Implementation

# saas_api.py — Multi-tenant SaaS API with FastAPI
import json

class SaaSAPI:
 CODE = """
# main.py — Multi-tenant FastAPI SaaS application
from fastapi import FastAPI, Depends, HTTPException, Header
from pydantic import BaseModel
from typing import Optional
import jwt

app = FastAPI(title="My SaaS API")

# Tenant middleware
async def get_current_tenant(authorization: str = Header(None)):
 if not authorization:
 raise HTTPException(401, "Missing authorization")
 
 token = authorization.replace("Bearer ", "")
 try:
 payload = jwt.decode(token, "secret", algorithms=["HS256"])
 return {
 "tenant_id": payload["tenant_id"],
 "user_id": payload["user_id"],
 "plan": payload.get("plan", "free"),
 }
 except jwt.InvalidTokenError:
 raise HTTPException(401, "Invalid token")

# Rate limiting by plan
PLAN_LIMITS = {"free": 100, "pro": 1000, "enterprise": 10000}

async def check_rate_limit(tenant=Depends(get_current_tenant)):
 limit = PLAN_LIMITS.get(tenant["plan"], 100)
 # Check against Redis counter
 # if current_count > limit: raise HTTPException(429, "Rate limit exceeded")
 return tenant

# API routes
class Project(BaseModel):
 name: str
 description: Optional[str] = None

@app.post("/api/projects")
async def create_project(project: Project, tenant=Depends(check_rate_limit)):
 # All queries filtered by tenant_id
 result = await db.execute(
 "INSERT INTO projects (name, description, tenant_id) VALUES ($1, $2, $3) RETURNING id",
 project.name, project.description, tenant["tenant_id"],
 )
 return {"id": result, "tenant_id": tenant["tenant_id"]}

@app.get("/api/projects")
async def list_projects(tenant=Depends(get_current_tenant)):
 projects = await db.fetch_all(
 "SELECT * FROM projects WHERE tenant_id = $1",
 tenant["tenant_id"],
 )
 return projects

# Billing webhook
@app.post("/webhooks/stripe")
async def stripe_webhook(event: dict):
 if event["type"] == "customer.subscription.updated":
 subscription = event["data"]["object"]
 tenant_id = subscription["metadata"]["tenant_id"]
 plan = subscription["items"]["data"][0]["price"]["lookup_key"]
 await db.execute(
 "UPDATE tenants SET plan = $1 WHERE id = $2",
 plan, tenant_id,
 )
 return {"received": True}
"""

 def show_code(self):
 print("=== SaaS API (FastAPI) ===")
 print(self.CODE[:600])

api = SaaSAPI()
api.show_code()

Kubernetes Deployment

# k8s_deploy.py — Kubernetes deployment for SaaS
import json

class K8sDeployment:
 HELM_VALUES = """
# values.yaml — Helm values for SaaS deployment
api:
 replicas: 3
 image: my-saas-api:latest
 resources:
 requests:
 cpu: 250m
 memory: 512Mi
 limits:
 cpu: 1000m
 memory: 1Gi
 env:
 DATABASE_URL: "postgresql://user:pass@postgres:5432/saas"
 REDIS_URL: "redis://redis:6379"
 STRIPE_SECRET_KEY: ""
 autoscaling:
 enabled: true
 minReplicas: 2
 maxReplicas: 10
 targetCPU: 70

worker:
 replicas: 2
 image: my-saas-worker:latest
 resources:
 requests:
 cpu: 500m
 memory: 1Gi

web:
 replicas: 2
 image: my-saas-web:latest

postgresql:
 enabled: true
 primary:
 persistence:
 size: 50Gi

redis:
 enabled: true
 architecture: standalone

ingress:
 enabled: true
 className: nginx
 annotations:
 cert-manager.io/cluster-issuer: letsencrypt-prod
 hosts:
 - host: api.mysaas.com
 paths: [{path: /, pathType: Prefix, service: api}]
 - host: app.mysaas.com
 paths: [{path: /, pathType: Prefix, service: web}]
 tls:
 - secretName: mysaas-tls
 hosts: [api.mysaas.com, app.mysaas.com]
"""

 def show_values(self):
 print("=== Helm Values ===")
 print(self.HELM_VALUES[:600])

 def deployment_tips(self):
 print(f"\n=== Deployment Tips ===")
 tips = [
 "ใช้ Skaffold profiles: dev (local), staging (shared), production (HA)",
 "ใช้ Sealed Secrets หรือ External Secrets สำหรับ sensitive config",
 "ตั้ง HPA (Horizontal Pod Autoscaler) สำหรับ API pods",
 "ใช้ PDB (Pod Disruption Budget) ป้องกัน downtime ระหว่าง rolling update",
 "Enable Prometheus metrics + Grafana dashboards per tenant",
 ]
 for tip in tips:
 print(f" • {tip}")

k8s = K8sDeployment()
k8s.show_values()
k8s.deployment_tips()

FAQ - คำถามที่พบบ่อย

Q: Skaffold กับ Tilt อันไหนดี?

A: Skaffold: Google-backed, CLI-focused, CI/CD integration ดี, profiles สำหรับหลาย environments Tilt: UI dashboard ดี, Tiltfile (Starlark), live update เร็ว ใช้ Skaffold: CI/CD pipeline integration, simple config, Google Cloud ใช้ Tilt: development-only, ต้องการ UI dashboard, complex microservices

Q: Multi-tenant แบบไหนดี?

A: Shared DB + tenant_id: เริ่มต้นดีที่สุด — ง่าย, ประหยัด, scale ได้ Schema-per-tenant: เมื่อต้องการ isolation มากขึ้น DB-per-tenant: enterprise/compliance requirements เริ่มจาก shared DB → migrate เมื่อจำเป็น 80% ของ SaaS ใช้ shared DB + row-level security

Q: SaaS architecture ต้องมีอะไรบ้าง?

A: Must-have: Authentication (JWT/OAuth), Multi-tenancy, Billing (Stripe), API rate limiting Important: Background workers, Email/notifications, Audit logging, Admin dashboard Nice-to-have: Feature flags, A/B testing, Analytics, SSO, Custom domains เริ่ม MVP: Auth + Core features + Billing → เพิ่มทีหลัง

Q: Skaffold dev loop เร็วแค่ไหน?

A: Without sync: 10-30 seconds (build Docker image + deploy) With file sync: 1-3 seconds (sync files ไม่ rebuild image) With hot-reload (uvicorn/nodemon): < 1 second (code change → see result) Key: ใช้ file sync + hot-reload framework = fastest inner loop