Docker Swarm เป็น Container Orchestration Platform ที่พัฒนาโดย Docker เพื่อใช้ในการจัดการและประสานงาน Docker containers หลายๆ ตัวบนเครื่องหลายๆ เครื่อง (cluster) โดย Swarm จะช่วยให้เราสามารถ:
graph TB
subgraph "Docker Swarm Cluster"
LB[Load Balancer]
subgraph "Manager Nodes"
M1[Manager 1
Leader]
M2[Manager 2]
M3[Manager 3]
end
subgraph "Worker Nodes"
W1[Worker 1]
W2[Worker 2]
W3[Worker 3]
W4[Worker 4]
end
subgraph "Services"
S1[Service A
3 replicas]
S2[Service B
2 replicas]
end
end
M1 -.Raft Consensus.-> M2
M2 -.Raft Consensus.-> M3
M3 -.Raft Consensus.-> M1
M1 -->|Schedule Tasks| W1
M1 -->|Schedule Tasks| W2
M2 -->|Schedule Tasks| W3
M3 -->|Schedule Tasks| W4
LB -->|Route Traffic| S1
LB -->|Route Traffic| S2
S1 -.->|Runs on| W1
S1 -.->|Runs on| W2
S1 -.->|Runs on| W3
S2 -.->|Runs on| W3
S2 -.->|Runs on| W4
Node: เครื่องแต่ละเครื่องใน Swarm cluster
Service: นิยามของ application ที่ต้องการรัน
Task: Container instance ของ service แต่ละตัว
Stack: กลุ่มของ services ที่เกี่ยวข้องกัน (deploy ด้วย docker-compose.yml)
ต้องมี Docker Engine ติดตั้งอยู่แล้ว (version 1.12 ขึ้นไป)
# ตรวจสอบ Docker version
docker --version
# บนเครื่อง Manager
docker swarm init --advertise-addr <MANAGER-IP>
ตัวอย่าง:
docker swarm init --advertise-addr 192.168.1.100
ผลลัพธ์:
Swarm initialized: current node (xyz123) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-xxx... 192.168.1.100:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
# บนเครื่อง Worker แต่ละเครื่อง
docker swarm join --token <WORKER-TOKEN> <MANAGER-IP>:2377
ตัวอย่าง:
docker swarm join --token SWMTKN-1-3pu6hszjas19xyp7ghgosyx9k8atbfcr8p2is99znpy26u2lkl-1awxwuwd3z9j1z3puu7rcgdbx 192.168.1.100:2377
# ดู join token สำหรับ manager
docker swarm join-token manager
# บนเครื่อง Manager ใหม่
docker swarm join --token <MANAGER-TOKEN> <MANAGER-IP>:2377
# ดูรายชื่อ nodes ทั้งหมด
docker node ls
ตัวอย่างผลลัพธ์:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
xyz123abc * manager1 Ready Active Leader
abc456def worker1 Ready Active
def789ghi worker2 Ready Active
# ดูข้อมูล Swarm
docker info
# ดูข้อมูลโดยละเอียด
docker swarm inspect
# Update task history retention
docker swarm update --task-history-limit 3
# Update dispatcher heartbeat
docker swarm update --dispatcher-heartbeat 5s
# บน Worker Node
docker swarm leave
# บน Manager Node (บังคับ)
docker swarm leave --force
# ดูรายชื่อ nodes
docker node ls
# ดูข้อมูลโดยละเอียดของ node
docker node inspect <NODE-ID>
# ดูแบบ pretty format
docker node inspect --pretty <NODE-ID>
# เปลี่ยน availability
docker node update --availability drain <NODE-ID>
# drain: ไม่รับ tasks ใหม่และย้าย tasks ปัจจุบันออก
# active: รับ tasks ปกติ
# pause: ไม่รับ tasks ใหม่แต่เก็บ tasks ปัจจุบันไว้
# เพิ่ม label
docker node update --label-add type=database <NODE-ID>
docker node update --label-add environment=production <NODE-ID>
# เปลี่ยน role
docker node promote <NODE-ID> # เปลี่ยนเป็น Manager
docker node demote <NODE-ID> # เปลี่ยนเป็น Worker
# ลบ node ออกจาก cluster (รัน on Manager)
docker node rm <NODE-ID>
# บังคับลบ (ถ้า node offline)
docker node rm --force <NODE-ID>
# ดู worker token
docker swarm join-token worker
# ดู manager token
docker swarm join-token manager
# สร้าง token ใหม่ (rotate)
docker swarm join-token --rotate worker
docker swarm join-token --rotate manager
Service คือหัวใจหลักของ Docker Swarm ที่ใช้ในการ deploy applications
# สร้าง service แบบง่าย
docker service create --name web nginx:latest
# สร้างพร้อม replicas
docker service create \
--name web \
--replicas 3 \
nginx:latest
docker service create \
--name web \
--replicas 3 \
--publish published=80,target=80 \
nginx:latest
# รูปแบบสั้น
docker service create \
--name web \
--replicas 3 \
-p 80:80 \
nginx:latest
docker service create \
--name myapp \
--replicas 2 \
--env MYSQL_ROOT_PASSWORD=secret \
--env MYSQL_DATABASE=mydb \
mysql:8.0
docker service create \
--name web \
--replicas 3 \
--limit-cpu 0.5 \
--limit-memory 256M \
--reserve-cpu 0.25 \
--reserve-memory 128M \
nginx:latest
# รันเฉพาะ nodes ที่มี label environment=production
docker service create \
--name web \
--replicas 3 \
--constraint node.labels.environment==production \
nginx:latest
# รันเฉพาะ Manager nodes
docker service create \
--name monitoring \
--constraint node.role==manager \
prometheus:latest
# รันเฉพาะ nodes ที่มี hostname เฉพาะ
docker service create \
--name db \
--constraint node.hostname==worker1 \
postgres:13
docker service create \
--name monitoring-agent \
--mode global \
monitoring-agent:latest
# ดูรายชื่อ services ทั้งหมด
docker service ls
# ดูข้อมูลโดยละเอียด
docker service inspect <SERVICE-NAME>
docker service inspect --pretty <SERVICE-NAME>
# ดู tasks ของ service
docker service ps <SERVICE-NAME>
# ดู logs
docker service logs <SERVICE-NAME>
docker service logs -f <SERVICE-NAME> # follow mode
docker service logs --tail 100 <SERVICE-NAME>
# เพิ่มจำนวน replicas
docker service scale web=5
# scale หลาย services พร้อมกัน
docker service scale web=5 api=3 worker=10
# update image version
docker service update --image nginx:1.21 web
# update พร้อม rolling update config
docker service update \
--image nginx:1.21 \
--update-delay 10s \
--update-parallelism 2 \
web
docker service update \
--env-add NEW_VAR=value \
--env-rm OLD_VAR \
myapp
docker service update \
--publish-add published=8080,target=80 \
web
docker service update \
--publish-rm 8080 \
web
docker service update \
--limit-cpu 1.0 \
--limit-memory 512M \
web
# rollback ไปเวอร์ชันก่อนหน้า
docker service rollback web
# update พร้อม rollback config
docker service update \
--image nginx:1.21 \
--rollback-delay 5s \
--rollback-monitor 10s \
--rollback-max-failure-ratio 0.2 \
web
# ลบ service
docker service rm <SERVICE-NAME>
# ลบหลาย services
docker service rm service1 service2 service3
Docker Stack เป็นวิธีการ deploy หลาย services พร้อมกันโดยใช้ไฟล์ docker-compose.yml แบบเดียวกับ Docker Compose แต่เพิ่มความสามารถสำหรับ Swarm mode
สร้างไฟล์ docker-compose.yml:
version: '3.8'
services:
web:
image: nginx:latest
ports:
- "80:80"
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
networks:
- webnet
api:
image: myapi:latest
environment:
- DATABASE_URL=postgres://db:5432/mydb
deploy:
replicas: 2
placement:
constraints:
- node.role == worker
resources:
limits:
cpus: '0.5'
memory: 256M
reservations:
cpus: '0.25'
memory: 128M
networks:
- webnet
- backend
db:
image: postgres:13
environment:
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
- POSTGRES_DB=mydb
volumes:
- db-data:/var/lib/postgresql/data
deploy:
replicas: 1
placement:
constraints:
- node.labels.type == database
secrets:
- db_password
networks:
- backend
networks:
webnet:
driver: overlay
backend:
driver: overlay
volumes:
db-data:
secrets:
db_password:
external: true
สร้างไฟล์ microservices-stack.yml:
version: '3.8'
services:
# Frontend Service
frontend:
image: myapp/frontend:v1.0
ports:
- "80:80"
- "443:443"
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
order: start-first
rollback_config:
parallelism: 1
delay: 5s
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`example.com`)"
configs:
- source: nginx_config
target: /etc/nginx/nginx.conf
networks:
- frontend
# API Gateway
gateway:
image: myapp/gateway:v1.0
ports:
- "8080:8080"
environment:
- SERVICE_DISCOVERY=consul
- LOG_LEVEL=info
deploy:
replicas: 2
placement:
constraints:
- node.role == worker
resources:
limits:
cpus: '1.0'
memory: 512M
networks:
- frontend
- backend
# User Service
user-service:
image: myapp/user-service:v1.0
environment:
- DATABASE_HOST=user-db
- REDIS_HOST=redis
- JWT_SECRET_FILE=/run/secrets/jwt_secret
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
max_attempts: 3
window: 120s
secrets:
- jwt_secret
networks:
- backend
- database
# Order Service
order-service:
image: myapp/order-service:v1.0
environment:
- DATABASE_HOST=order-db
- MESSAGE_QUEUE=rabbitmq
deploy:
replicas: 2
labels:
- "app=order-service"
- "tier=backend"
networks:
- backend
- database
# Payment Service
payment-service:
image: myapp/payment-service:v1.0
environment:
- PAYMENT_GATEWAY=stripe
- API_KEY_FILE=/run/secrets/stripe_key
deploy:
replicas: 2
placement:
constraints:
- node.labels.security == high
secrets:
- stripe_key
networks:
- backend
# User Database
user-db:
image: postgres:13
environment:
- POSTGRES_DB=users
- POSTGRES_PASSWORD_FILE=/run/secrets/user_db_password
volumes:
- user-db-data:/var/lib/postgresql/data
deploy:
replicas: 1
placement:
constraints:
- node.labels.type == database
restart_policy:
condition: on-failure
secrets:
- user_db_password
networks:
- database
# Order Database
order-db:
image: postgres:13
environment:
- POSTGRES_DB=orders
- POSTGRES_PASSWORD_FILE=/run/secrets/order_db_password
volumes:
- order-db-data:/var/lib/postgresql/data
deploy:
replicas: 1
placement:
constraints:
- node.labels.type == database
secrets:
- order_db_password
networks:
- database
# Redis Cache
redis:
image: redis:6-alpine
deploy:
replicas: 1
placement:
constraints:
- node.role == worker
networks:
- backend
# RabbitMQ Message Queue
rabbitmq:
image: rabbitmq:3-management
ports:
- "15672:15672" # Management UI
environment:
- RABBITMQ_DEFAULT_USER=admin
- RABBITMQ_DEFAULT_PASS_FILE=/run/secrets/rabbitmq_password
deploy:
replicas: 1
secrets:
- rabbitmq_password
networks:
- backend
# Monitoring - Prometheus
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
configs:
- source: prometheus_config
target: /etc/prometheus/prometheus.yml
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
networks:
- monitoring
# Monitoring - Grafana
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD_FILE=/run/secrets/grafana_password
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
secrets:
- grafana_password
networks:
- monitoring
networks:
frontend:
driver: overlay
attachable: true
backend:
driver: overlay
database:
driver: overlay
internal: true # ไม่สามารถเข้าถึงจากภายนอกได้
monitoring:
driver: overlay
volumes:
user-db-data:
order-db-data:
secrets:
jwt_secret:
external: true
stripe_key:
external: true
user_db_password:
external: true
order_db_password:
external: true
rabbitmq_password:
external: true
grafana_password:
external: true
configs:
nginx_config:
external: true
prometheus_config:
external: true
# deploy stack
docker stack deploy -c docker-compose.yml mystack
# deploy พร้อม prune services เก่า
docker stack deploy -c docker-compose.yml --prune mystack
# deploy จากหลายไฟล์
docker stack deploy \
-c docker-compose.yml \
-c docker-compose.prod.yml \
mystack
ตัวอย่างการ Deploy แบบละเอียด:
# ขั้นตอนที่ 1: สร้าง secrets
echo "mysecretpassword" | docker secret create db_password -
echo "jwt_secret_key_here" | docker secret create jwt_secret -
# ขั้นตอนที่ 2: สร้าง configs
docker config create nginx_config nginx.conf
# ขั้นตอนที่ 3: เพิ่ม labels ให้ nodes
docker node update --label-add type=database worker1
docker node update --label-add security=high worker2
# ขั้นตอนที่ 4: deploy stack
docker stack deploy -c docker-compose.yml production
# ตรวจสอบสถานะ
docker stack ps production
# ดูรายชื่อ stacks
docker stack ls
# ดู services ใน stack
docker stack services mystack
# ดู tasks/containers ใน stack
docker stack ps mystack
# ดูแบบละเอียด (รวม stopped tasks)
docker stack ps --no-trunc mystack
docker stack ps --no-resolve mystack
# แก้ไข docker-compose.yml แล้ว deploy ใหม่
docker stack deploy -c docker-compose.yml mystack
# Docker จะทำ rolling update อัตโนมัติตาม update_config
# ลบ stack ทั้งหมด
docker stack rm mystack
# จะลบ services, networks, secrets, configs ที่สร้างโดย stack
# แต่จะไม่ลบ volumes โดยอัตโนมัติ
graph TD
A[เตรียม docker-compose.yml] --> B[สร้าง Secrets/Configs]
B --> C[กำหนด Node Labels
ถ้าจำเป็น]
C --> D[docker stack deploy]
D --> E{Deploy สำเร็จ?}
E -->|Yes| F[Services Running]
E -->|No| G[ตรวจสอบ Logs]
G --> H[แก้ไขปัญหา]
H --> D
F --> I[Monitor Services]
I --> J{ต้องการ Update?}
J -->|Yes| K[แก้ไข docker-compose.yml]
K --> D
J -->|No| I
F --> L{ต้องการลบ?}
L -->|Yes| M[docker stack rm]
M --> N[ลบ Volumes
ถ้าจำเป็น]
Docker Swarm ใช้ overlay networks เพื่อให้ containers บน nodes ต่างๆ สื่อสารกันได้
# สร้าง overlay network พื้นฐาน
docker network create --driver overlay mynetwork
# สร้างพร้อม subnet
docker network create \
--driver overlay \
--subnet 10.0.0.0/24 \
--gateway 10.0.0.1 \
mynetwork
# สร้าง encrypted network
docker network create \
--driver overlay \
--opt encrypted \
secure-network
# สร้าง attachable network (สำหรับ standalone containers)
docker network create \
--driver overlay \
--attachable \
frontend-network
# ดูรายชื่อ networks
docker network ls
# ดูข้อมูลโดยละเอียด
docker network inspect mynetwork
# เชื่อม service เข้ากับ network
docker service update --network-add mynetwork web
# ถอด service ออกจาก network
docker service update --network-rm mynetwork web
docker network rm mynetwork
# สร้าง volume พื้นฐาน
docker volume create myvolume
# สร้างพร้อม driver options
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=192.168.1.200,rw \
--opt device=:/path/to/dir \
nfs-volume
# ดูรายชื่อ volumes
docker volume ls
# ดูข้อมูลโดยละเอียด
docker volume inspect myvolume
# mount volume เข้ากับ service
docker service create \
--name db \
--mount type=volume,source=db-data,target=/var/lib/postgresql/data \
postgres:13
# หรือใช้ syntax แบบสั้น
docker service create \
--name db \
--mount source=db-data,target=/var/lib/postgresql/data \
postgres:13
# ลบ volume
docker volume rm myvolume
# ลบ volumes ที่ไม่ได้ใช้งาน
docker volume prune
Secrets ใช้สำหรับเก็บข้อมูลที่เป็นความลับ เช่น passwords, API keys, certificates
# สร้างจาก stdin
echo "mysecretpassword" | docker secret create db_password -
# สร้างจากไฟล์
docker secret create db_password ./password.txt
# สร้างจาก environment variable
echo "$MY_PASSWORD" | docker secret create db_password -
# ดูรายชื่อ secrets
docker secret ls
# ดูข้อมูลโดยละเอียด (ไม่แสดงค่าจริง)
docker secret inspect db_password
docker service create \
--name db \
--secret db_password \
--env POSTGRES_PASSWORD_FILE=/run/secrets/db_password \
postgres:13
# secret จะถูก mount ที่ /run/secrets/<secret_name>
# ไม่สามารถ update secret ได้โดยตรง
# ต้องสร้างใหม่และ update service
# สร้าง secret ใหม่
echo "newsecretpassword" | docker secret create db_password_v2 -
# update service ให้ใช้ secret ใหม่
docker service update \
--secret-rm db_password \
--secret-add source=db_password_v2,target=db_password \
db
# ลบ secret (ต้องไม่มี service ใช้งานอยู่)
docker secret rm db_password
Configs ใช้สำหรับเก็บไฟล์ configuration ที่ไม่เป็นความลับ
# สร้างจากไฟล์
docker config create nginx_config nginx.conf
# สร้างจาก stdin
cat <<EOF | docker config create app_config -
{
"database": {
"host": "db",
"port": 5432
}
}
EOF
# ดูรายชื่อ configs
docker config ls
# ดูข้อมูลโดยละเอียด
docker config inspect nginx_config
# ดูเนื้อหา config
docker config inspect --pretty nginx_config
docker service create \
--name web \
--config source=nginx_config,target=/etc/nginx/nginx.conf \
nginx:latest
# กำหนด permissions
docker service create \
--name web \
--config source=nginx_config,target=/etc/nginx/nginx.conf,mode=0440 \
nginx:latest
# สร้าง config ใหม่
docker config create nginx_config_v2 nginx-updated.conf
# update service
docker service update \
--config-rm nginx_config \
--config-add source=nginx_config_v2,target=/etc/nginx/nginx.conf \
web
docker config rm nginx_config
# สร้าง secrets สำหรับ passwords
echo "wordpress_db_password" | docker secret create wp_db_password -
echo "mysql_root_password" | docker secret create mysql_root_password -
version: '3.8'
services:
wordpress:
image: wordpress:latest
ports:
- "80:80"
environment:
- WORDPRESS_DB_HOST=mysql:3306
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD_FILE=/run/secrets/wp_db_password
- WORDPRESS_DB_NAME=wordpress
secrets:
- wp_db_password
deploy:
replicas: 2
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
networks:
- wordpress-network
mysql:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_root_password
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD_FILE=/run/secrets/wp_db_password
secrets:
- mysql_root_password
- wp_db_password
volumes:
- mysql-data:/var/lib/mysql
deploy:
replicas: 1
placement:
constraints:
- node.labels.type == database
networks:
- wordpress-network
networks:
wordpress-network:
driver: overlay
volumes:
mysql-data:
secrets:
wp_db_password:
external: true
mysql_root_password:
external: true
# กำหนด node สำหรับ database
docker node update --label-add type=database worker1
docker stack deploy -c docker-compose.yml wordpress
# ดู services
docker stack services wordpress
# ดู tasks
docker stack ps wordpress
# ดู logs
docker service logs wordpress_wordpress
docker service logs wordpress_mysql
# เพิ่ม replicas
docker service scale wordpress_wordpress=5
# หรือ update stack file แล้ว deploy ใหม่
graph TB
subgraph "Frontend Layer"
LB[Load Balancer
Traefik]
WEB[Web Frontend
React - 3 replicas]
ADMIN[Admin Panel
Vue - 2 replicas]
end
subgraph "API Layer"
GW[API Gateway
2 replicas]
AUTH[Auth Service
3 replicas]
PROD[Product Service
3 replicas]
ORDER[Order Service
2 replicas]
PAY[Payment Service
2 replicas]
end
subgraph "Data Layer"
REDIS[(Redis Cache)]
PDB[(Product DB
PostgreSQL)]
ODB[(Order DB
PostgreSQL)]
UDB[(User DB
PostgreSQL)]
end
subgraph "Message Queue"
MQ[RabbitMQ]
WORKER[Background Workers
3 replicas]
end
LB -->|Route| WEB
LB -->|Route| ADMIN
WEB -->|API Calls| GW
ADMIN -->|API Calls| GW
GW --> AUTH
GW --> PROD
GW --> ORDER
GW --> PAY
AUTH --> UDB
AUTH --> REDIS
PROD --> PDB
PROD --> REDIS
ORDER --> ODB
PAY --> MQ
MQ --> WORKER
WORKER --> ODB
1. สร้าง Secrets และ Configs
# Database passwords
echo "user_db_pass123" | docker secret create user_db_password -
echo "product_db_pass123" | docker secret create product_db_password -
echo "order_db_pass123" | docker secret create order_db_password -
# API Keys
echo "stripe_sk_test_xxx" | docker secret create stripe_api_key -
echo "jwt_secret_key_xxx" | docker secret create jwt_secret -
echo "admin_rabbitmq_pass" | docker secret create rabbitmq_password -
# Application Configs
docker config create traefik_config traefik.yml
docker config create redis_config redis.conf
2. สร้าง docker-compose.yml
version: '3.8'
services:
# Load Balancer / Reverse Proxy
traefik:
image: traefik:v2.9
command:
- "--api.insecure=true"
- "--providers.docker.swarmMode=true"
- "--providers.docker.exposedByDefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
ports:
- "80:80"
- "443:443"
- "8080:8080" # Traefik dashboard
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
configs:
- source: traefik_config
target: /etc/traefik/traefik.yml
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
networks:
- frontend
# Web Frontend
web-frontend:
image: ecommerce/frontend:v1.0
environment:
- API_GATEWAY_URL=http://api-gateway:8080
- NODE_ENV=production
deploy:
replicas: 3
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`shop.example.com`)"
- "traefik.http.services.frontend.loadbalancer.server.port=80"
update_config:
parallelism: 1
delay: 10s
order: start-first
resources:
limits:
cpus: '0.5'
memory: 256M
networks:
- frontend
# Admin Panel
admin-panel:
image: ecommerce/admin:v1.0
environment:
- API_GATEWAY_URL=http://api-gateway:8080
deploy:
replicas: 2
labels:
- "traefik.enable=true"
- "traefik.http.routers.admin.rule=Host(`admin.example.com`)"
- "traefik.http.services.admin.loadbalancer.server.port=80"
networks:
- frontend
# API Gateway
api-gateway:
image: ecommerce/gateway:v1.0
environment:
- AUTH_SERVICE=auth-service:8080
- PRODUCT_SERVICE=product-service:8080
- ORDER_SERVICE=order-service:8080
- PAYMENT_SERVICE=payment-service:8080
deploy:
replicas: 2
labels:
- "traefik.enable=true"
- "traefik.http.routers.gateway.rule=Host(`api.example.com`)"
- "traefik.http.services.gateway.loadbalancer.server.port=8080"
resources:
limits:
cpus: '1.0'
memory: 512M
networks:
- frontend
- backend
# Auth Service
auth-service:
image: ecommerce/auth-service:v1.0
environment:
- DATABASE_HOST=user-db
- DATABASE_PORT=5432
- DATABASE_NAME=users
- REDIS_HOST=redis
- JWT_SECRET_FILE=/run/secrets/jwt_secret
secrets:
- jwt_secret
- user_db_password
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
max_attempts: 3
networks:
- backend
- database
# Product Service
product-service:
image: ecommerce/product-service:v1.0
environment:
- DATABASE_HOST=product-db
- DATABASE_PORT=5432
- DATABASE_NAME=products
- REDIS_HOST=redis
- CACHE_TTL=3600
secrets:
- product_db_password
deploy:
replicas: 3
resources:
limits:
cpus: '0.75'
memory: 512M
networks:
- backend
- database
# Order Service
order-service:
image: ecommerce/order-service:v1.0
environment:
- DATABASE_HOST=order-db
- DATABASE_PORT=5432
- DATABASE_NAME=orders
- MESSAGE_QUEUE_HOST=rabbitmq
secrets:
- order_db_password
- rabbitmq_password
deploy:
replicas: 2
networks:
- backend
- database
- messagequeue
# Payment Service
payment-service:
image: ecommerce/payment-service:v1.0
environment:
- STRIPE_API_KEY_FILE=/run/secrets/stripe_api_key
- MESSAGE_QUEUE_HOST=rabbitmq
secrets:
- stripe_api_key
- rabbitmq_password
deploy:
replicas: 2
placement:
constraints:
- node.labels.security == high
networks:
- backend
- messagequeue
# User Database
user-db:
image: postgres:13
environment:
- POSTGRES_DB=users
- POSTGRES_USER=userapp
- POSTGRES_PASSWORD_FILE=/run/secrets/user_db_password
volumes:
- user-db-data:/var/lib/postgresql/data
secrets:
- user_db_password
deploy:
replicas: 1
placement:
constraints:
- node.labels.type == database
restart_policy:
condition: on-failure
networks:
- database
# Product Database
product-db:
image: postgres:13
environment:
- POSTGRES_DB=products
- POSTGRES_USER=productapp
- POSTGRES_PASSWORD_FILE=/run/secrets/product_db_password
volumes:
- product-db-data:/var/lib/postgresql/data
secrets:
- product_db_password
deploy:
replicas: 1
placement:
constraints:
- node.labels.type == database
networks:
- database
# Order Database
order-db:
image: postgres:13
environment:
- POSTGRES_DB=orders
- POSTGRES_USER=orderapp
- POSTGRES_PASSWORD_FILE=/run/secrets/order_db_password
volumes:
- order-db-data:/var/lib/postgresql/data
secrets:
- order_db_password
deploy:
replicas: 1
placement:
constraints:
- node.labels.type == database
networks:
- database
# Redis Cache
redis:
image: redis:6-alpine
configs:
- source: redis_config
target: /usr/local/etc/redis/redis.conf
command: redis-server /usr/local/etc/redis/redis.conf
deploy:
replicas: 1
placement:
constraints:
- node.role == worker
networks:
- backend
# RabbitMQ
rabbitmq:
image: rabbitmq:3-management
environment:
- RABBITMQ_DEFAULT_USER=admin
- RABBITMQ_DEFAULT_PASS_FILE=/run/secrets/rabbitmq_password
secrets:
- rabbitmq_password
deploy:
replicas: 1
networks:
- messagequeue
# Background Workers
worker:
image: ecommerce/worker:v1.0
environment:
- MESSAGE_QUEUE_HOST=rabbitmq
- DATABASE_HOST=order-db
secrets:
- rabbitmq_password
- order_db_password
deploy:
replicas: 3
resources:
limits:
cpus: '0.5'
memory: 256M
networks:
- messagequeue
- database
# Monitoring - Prometheus
prometheus:
image: prom/prometheus:latest
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
volumes:
- prometheus-data:/prometheus
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
networks:
- monitoring
# Monitoring - Grafana
grafana:
image: grafana/grafana:latest
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin123
volumes:
- grafana-data:/var/lib/grafana
deploy:
replicas: 1
labels:
- "traefik.enable=true"
- "traefik.http.routers.grafana.rule=Host(`monitoring.example.com`)"
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
placement:
constraints:
- node.role == manager
networks:
- monitoring
- frontend
networks:
frontend:
driver: overlay
attachable: true
backend:
driver: overlay
database:
driver: overlay
internal: true
messagequeue:
driver: overlay
monitoring:
driver: overlay
volumes:
user-db-data:
product-db-data:
order-db-data:
prometheus-data:
grafana-data:
secrets:
jwt_secret:
external: true
stripe_api_key:
external: true
user_db_password:
external: true
product_db_password:
external: true
order_db_password:
external: true
rabbitmq_password:
external: true
configs:
traefik_config:
external: true
redis_config:
external: true
3. เตรียม Nodes
# กำหนด labels สำหรับ nodes
docker node update --label-add type=database worker1
docker node update --label-add type=database worker2
docker node update --label-add security=high worker3
4. Deploy Stack
# deploy
docker stack deploy -c docker-compose.yml ecommerce
# ตรวจสอบ
watch docker stack ps ecommerce
5. Monitoring และ Maintenance
# ดู logs แบบ real-time
docker service logs -f ecommerce_product-service
# ตรวจสอบ resource usage
docker stats
# ดูสถานะ services
docker stack services ecommerce
# scale services
docker service scale ecommerce_product-service=5
docker service scale ecommerce_auth-service=5
# ใช้ Manager nodes จำนวนคี่ (3, 5, 7)
# เพื่อการ consensus ที่ดี
# ตัวอย่าง: cluster ขนาดกลาง
- 3 Manager nodes
- 5+ Worker nodes
# กำหนด resource limits และ reservations เสมอ
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
# กำหนด health checks สำหรับ services
services:
api:
image: myapi:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# กำหนด update config ที่เหมาะสม
deploy:
update_config:
parallelism: 2 # update ทีละ 2 tasks
delay: 10s # delay ระหว่าง batches
failure_action: rollback # rollback ถ้า fail
monitor: 60s # monitor เวลา 60s
max_failure_ratio: 0.2 # ยอมให้ fail ได้ 20%
order: start-first # start ตัวใหม่ก่อนปิดตัวเก่า
# ใช้ placement constraints อย่างชาญฉลาด
deploy:
placement:
constraints:
- node.role == worker
- node.labels.type == database
- node.hostname != old-server
preferences:
- spread: node.labels.datacenter # กระจายตาม datacenter
# ใช้ secrets สำหรับข้อมูลลับทุกตัว
# ไม่ควรใส่ passwords ใน environment variables
# ใช้ encrypted networks
docker network create --opt encrypted mynetwork
# จำกัดการเข้าถึง internal networks
networks:
database:
driver: overlay
internal: true # ไม่สามารถเข้าถึงจากภายนอกได้
# ใช้ logging driver
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Deploy monitoring stack
- Prometheus สำหรับ metrics
- Grafana สำหรับ visualization
- ELK Stack สำหรับ log aggregation
# Backup volumes เป็นประจำ
docker run --rm \
-v volume_name:/volume \
-v $(pwd):/backup \
alpine tar czf /backup/backup.tar.gz /volume
# Backup swarm configurations
docker config ls -q | xargs -I {} sh -c 'docker config inspect {} > config-{}.json'
docker secret ls -q | xargs -I {} sh -c 'docker secret inspect {} > secret-{}.json'
# แยก networks ตามชั้น
networks:
frontend: # สำหรับ public-facing services
driver: overlay
attachable: true
backend: # สำหรับ internal services
driver: overlay
database: # สำหรับ databases เท่านั้น
driver: overlay
internal: true
# เขียน documentation ใน docker-compose.yml
# ใช้ comments อธิบาย
# เก็บ version history
# ใช้ Git สำหรับ version control
# สร้าง README.md สำหรับแต่ละ stack
# ตรวจสอบ logs
docker service logs <service-name>
# ดู tasks ที่ fail
docker service ps <service-name> --no-trunc
# ตรวจสอบ events
docker events
# ดู node availability
docker node ls
# ตรวจสอบ overlay network
docker network ls
docker network inspect <network-name>
# ทดสอบ connectivity
docker run --rm --network <network-name> alpine ping <service-name>
# restart docker daemon บน nodes ที่มีปัญหา
sudo systemctl restart docker
# ตรวจสอบ volume
docker volume ls
docker volume inspect <volume-name>
# ตรวจสอบ permissions
docker run --rm -v <volume>:/data alpine ls -la /data
# ตรวจสอบ secret
docker secret ls
docker secret inspect <secret-name>
# update service ด้วย secret ใหม่
docker service update \
--secret-rm old_secret \
--secret-add new_secret \
<service-name>
# rollback service
docker service rollback <service-name>
# ตรวจสอบ update status
docker service inspect --pretty <service-name>
# force update
docker service update --force <service-name>
Docker Swarm เป็นเครื่องมือที่ทรงพลังสำหรับการจัดการ containers แบบ cluster ที่มีความสามารถในการ:
✅ Deploy และ Scale applications ได้ง่ายและรวดเร็ว
✅ High Availability ด้วย automatic failover
✅ Load Balancing อัตโนมัติ
✅ Rolling Updates โดยไม่มี downtime
✅ Security ด้วย built-in TLS และ secrets management
✅ Service Discovery อัตโนมัติ
การใช้งาน Docker Swarm จะช่วยให้การ deploy และจัดการ applications ของคุณมีความน่าเชื่อถือและปรับขนาดได้ง่ายขึ้น โดยเฉพาะเมื่อใช้ร่วมกับ Docker Stack ที่ทำให้การจัดการ multi-service applications เป็นเรื่องง่าย