CircleCI Orbs กับ SaaS Architecture — วิธีสร้าง

CircleCI Orbs สำหรับ SaaS

SaaS Architecture มักประกอบด้วยหลาย Microservices, Database, Message Queue, Cache และ External Services การสร้าง CI/CD Pipeline ที่มีประสิทธิภาพต้องจัดการ Build, Test และ Deploy หลาย Service พร้อมกัน CircleCI Orbs ช่วยลดความซับซ้อนด้วย Reusable Configuration
เนื้อหาเกี่ยวข้อง — ดูเพิ่มเติมเรื่อง คู่มือฉบับสมบูรณ์ PlanetScale Vitess AR VR Development 2026: เปลี่ยนโลกด้วยเท…
บทความนี้แสดงวิธีสร้าง CI/CD Pipeline สำหรับ SaaS ที่ครอบคลุม Multi-service Build, Database Migration, Feature Flags, Environment Promotion และ Deployment Strategies ต่างๆ
เนื้อหาเกี่ยวข้อง — แนะนำให้อ่าน PagerDuty Incident Pod Scheduling — จัดการ
Multi-service CI/CD Pipeline
# .circleci/config.yml — SaaS Multi-service Pipeline
version: 2.1
orbs:
aws-ecr: circleci/aws-ecr@9.0.4
aws-eks: circleci/aws-eks@2.2.0
slack: circleci/slack@4.13.3
node: circleci/node@5.2.0
python: circleci/python@2.1.1
# Parameters สำหรับ Dynamic Configuration
parameters:
run-api:
type: boolean
default: false
run-web:
type: boolean
default: false
run-worker:
type: boolean
default: false
run-all:
type: boolean
default: false
# Executors
executors:
node-executor:
docker:
- image: cimg/node:20.11
resource_class: medium
python-executor:
docker:
- image: cimg/python:3.12
- image: cimg/postgres:16.1 # Test Database
environment:
POSTGRES_DB: test_db
POSTGRES_USER: test
POSTGRES_PASSWORD: test
- image: cimg/redis:7.2 # Test Redis
resource_class: medium
# Reusable Commands
commands:
setup-env:
parameters:
service:
type: string
steps:
- checkout
- run:
name: Setup Environment
command: |
echo "SERVICE=<< parameters.service >>" >> $BASH_ENV
echo "IMAGE_TAG=" >> $BASH_ENV
echo "REGISTRY=.dkr.ecr..amazonaws.com" >> $BASH_ENV
run-migrations:
parameters:
environment:
type: string
steps:
- run:
name: Run Database Migrations
command: |
cd services/api
# Dry-run migration ก่อน
python manage.py migrate --check
# รัน Migration จริง
python manage.py migrate --no-input
environment:
DATABASE_URL: << parameters.environment >>
notify-slack:
parameters:
status:
type: string
service:
type: string
steps:
- slack/notify:
channel: deployments
event: << parameters.status >>
template: |
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "<< parameters.status >> | *<< parameters.service >>* deployed to \nCommit: by "
}
}
]
}
# Jobs
jobs:
# Path Filtering — ตรวจสอบว่า Service ไหนเปลี่ยน
detect-changes:
docker:
- image: cimg/base:current
steps:
- checkout
- run:
name: Detect Changed Services
command: |
# เปรียบเทียบกับ main branch
CHANGED=$(git diff --name-only origin/main...HEAD)
echo "Changed files:"
echo "$CHANGED"
API_CHANGED=$(echo "$CHANGED" | grep -c "services/api/" || true)
WEB_CHANGED=$(echo "$CHANGED" | grep -c "services/web/" || true)
WORKER_CHANGED=$(echo "$CHANGED" | grep -c "services/worker/" || true)
SHARED_CHANGED=$(echo "$CHANGED" | grep -c "shared/" || true)
# ถ้า Shared เปลี่ยน Build ทุก Service
if [ "$SHARED_CHANGED" -gt 0 ]; then
echo '{"run-all": true}' > /tmp/pipeline-params.json
else
echo "{\"run-api\": $([ $API_CHANGED -gt 0 ] && echo true || echo false), \"run-web\": $([ $WEB_CHANGED -gt 0 ] && echo true || echo false), \"run-worker\": $([ $WORKER_CHANGED -gt 0 ] && echo true || echo false)}" > /tmp/pipeline-params.json
fi
cat /tmp/pipeline-params.json
- persist_to_workspace:
root: /tmp
paths: [pipeline-params.json]
# Build & Test API Service
build-api:
executor: python-executor
steps:
- setup-env:
service: api
- python/install-packages:
pkg-manager: pip
app-dir: services/api
- run:
name: Run Linting
command: |
cd services/api
ruff check .
mypy .
- run:
name: Run Tests
command: |
cd services/api
pytest --cov=. --cov-report=xml --junitxml=test-results/results.xml -v
- store_test_results:
path: services/api/test-results
- store_artifacts:
path: services/api/coverage.xml
# Build & Test Web Service
build-web:
executor: node-executor
steps:
- setup-env:
service: web
- node/install-packages:
app-dir: services/web
- run:
name: Lint & Type Check
command: |
cd services/web
npm run lint
npm run type-check
- run:
name: Run Tests
command: |
cd services/web
npm run test -- --coverage --ci
- run:
name: Build
command: |
cd services/web
npm run build
- persist_to_workspace:
root: .
paths: [services/web/dist]
# Docker Build & Push
docker-build:
parameters:
service:
type: string
docker:
- image: cimg/base:current
steps:
- setup-env:
service: << parameters.service >>
- setup_remote_docker:
docker_layer_caching: true
- run:
name: Build & Push Docker Image
command: |
aws ecr get-login-password | docker login --username AWS --password-stdin $REGISTRY
docker build -t $REGISTRY/<< parameters.service >>:$IMAGE_TAG \
-f services/<< parameters.service >>/Dockerfile \
--build-arg BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) \
--build-arg VCS_REF=$CIRCLE_SHA1 \
.
docker push $REGISTRY/<< parameters.service >>:$IMAGE_TAG
# Deploy to Environment
deploy:
parameters:
service:
type: string
environment:
type: string
docker:
- image: cimg/base:current
steps:
- checkout
- run:
name: Deploy << parameters.service >> to << parameters.environment >>
command: |
# Update Kubernetes Deployment
kubectl set image deployment/<< parameters.service >> \
<< parameters.service >>=$REGISTRY/<< parameters.service >>:$IMAGE_TAG \
-n << parameters.environment >>
# Wait for Rollout
kubectl rollout status deployment/<< parameters.service >> \
-n << parameters.environment >> --timeout=300s
- notify-slack:
status: pass
service: << parameters.service >>
# Workflows
workflows:
build-test-deploy:
jobs:
- detect-changes:
filters:
branches:
ignore: main
- build-api:
requires: [detect-changes]
filters:
branches:
ignore: main
- build-web:
requires: [detect-changes]
- docker-build:
name: docker-api
service: api
requires: [build-api]
context: aws-prod
- docker-build:
name: docker-web
service: web
requires: [build-web]
context: aws-prod
- deploy:
name: deploy-staging-api
service: api
environment: staging
requires: [docker-api]
context: aws-staging
- deploy:
name: deploy-staging-web
service: web
environment: staging
requires: [docker-web]
context: aws-staging
# Production Deploy — ต้อง Approve
- hold-production:
type: approval
requires:
- deploy-staging-api
- deploy-staging-web
- deploy:
name: deploy-prod-api
service: api
environment: production
requires: [hold-production]
context: aws-prod
- deploy:
name: deploy-prod-web
service: web
environment: production
requires: [hold-production]
context: aws-prod

Deployment Strategies สำหรับ SaaS
- Blue-Green Deployment: มี 2 Environment (Blue/Green) Deploy ไป Green แล้ว Switch Traffic ทั้งหมด Rollback ง่ายแค่ Switch กลับ
- Canary Deployment: Deploy Version ใหม่ให้ 5% ของ Traffic ก่อน Monitor Error Rate และ Latency แล้วค่อยขยายเป็น 25%, 50%, 100%
- Rolling Update: อัปเดต Pod ทีละตัว ค่อยเป็นค่อยไป ไม่ต้องมี Environment เพิ่ม แต่ Rollback ช้ากว่า
- Feature Flags: Deploy Code ทั้งหมดแต่ซ่อนหลัง Feature Flag เปิดให้ User ทีละกลุ่ม ยืดหยุ่นที่สุดแต่ซับซ้อนกว่า
- Ring Deployment: แบ่ง Users เป็น Rings (Internal → Beta → GA) Deploy ไปทีละ Ring เหมาะกับ SaaS ที่มี Multi-tenant
CircleCI Orbs คืออะไร
CircleCI Orbs เป็น Reusable Configuration Packages รวม Jobs, Commands และ Executors ลดการเขียน Config ซ้ำ มี Orbs สำเร็จรูปสำหรับ AWS, Docker, Kubernetes, Slack ใช้แค่ Reference แล้ว Config ไม่กี่บรรทัด ช่วยให้สร้าง Pipeline ได้เร็ว
แนะนำเพิ่มเติม — XM Signal
เนื้อหาเกี่ยวข้อง — Scrum Tool คืออะไร — ข้อมูลครบถ้วน 2026





