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
