ตั้ง Docker Swarm Cluster บน VPS
Docker Swarm เป็น container orchestration tool ที่ built-in กับ Docker สามารถจัดการ container หลายตัวบนหลาย node ได้อย่างง่าย เพิ่ม container ใหม่หรือขยายจำนวน replica ของ service เพียงสั่งผ่าน API เดียว Swarm จะวางตำแหน่ง container ให้เหมาะสมบน node ต่างๆ โดยอัตโนมัติ ถ้าเทียบกับ Kubernetes Swarm ง่ายและเร็วกว่าในการตั้งค่า เหมาะสำหรับทีมที่ต้องการ cluster ที่ใช้งานได้เร็ว โดยไม่ต้องแบกรับความซับซ้อนเกินความจำเป็น
เตรียม VPS แต่ละ Node
ก่อน initialize Swarm ต้องติดตั้ง Docker บน server ทุกตัว ให้ network สามารถ communicate กันได้ ต่อไปยังบน manager node ด้วย SSH แล้วติดตั้ง Docker:
sudo apt update
sudo apt install docker.io docker-compose -y
sudo usermod -aG docker $USER
newgrp docker
# เปิด firewall port สำหรับ Swarm
sudo ufw allow 2376/tcp
sudo ufw allow 2377/tcp
sudo ufw allow 7946/tcp
sudo ufw allow 7946/udp
sudo ufw allow 4789/udp
Initialize Docker Swarm บน Manager Node
SSH เข้า manager node แรก (node ที่จะเป็น leader) แล้ว initialize Swarm:
docker swarm init --advertise-addr=MANAGER_IP
# จะได้ output เหล่านี้:
# Swarm initialized: current node (xxx) is now a manager.
#
# To add a worker to this swarm, run the following command:
# docker swarm join --token SWMTKN-1-xxx MANAGER_IP:2377
#
# To add a manager to this swarm, run:
# docker swarm join-token manager
MANAGER_IP เป็น IP address ของ manager node ที่ worker node สามารถเข้าถึงได้ (ไม่ใช่ loopback 127.0.0.1) ถ้ามี manager หลายตัวให้ใช้ floating IP หรือ load balancer เพื่อความ high availability
Join Worker Nodes เข้า Cluster
บน worker node แต่ละตัว (อื่นที่ไม่ใช่ manager แรก) ให้รัน docker swarm join command ที่ได้มาจากขั้นตอนก่อนหน้า:
# ในที่นี้ SWMTKN-1-xxx คือ token ที่ได้จากขั้นตอน initialize
docker swarm join --token SWMTKN-1-xxx MANAGER_IP:2377
# หลังสำเร็จจะได้ "This node joined a swarm as a worker."
ถ้าต้องการเพิ่ม manager node เพื่อ high availability ให้ขอ token สำหรับ manager ก่อน:
# รัน command นี้บน manager node ที่มีอยู่
docker swarm join-token manager
# ผลลัพธ์จะให้ token สำหรับ manager
docker swarm join --token SWMTKN-1-manager-xxx MANAGER_IP:2377
สร้าง Service จากภาพ Docker
หลังจาก Swarm cluster พร้อม ให้สร้าง service ที่ใช้ image Docker:
# สร้าง service ชื่อ "web" จาก image nginx พร้อม 3 replica
docker service create \
--name web \
--publish 80:80 \
--replicas 3 \
nginx:latest
# ขยายจำนวน replica เป็น 5
docker service scale web=5
# ดู log ของ service
docker service logs web
# ลบ service
docker service rm web
--constraint เช่น --constraint node.hostname==worker-1
Deploy Stack จากไฟล์ Docker Compose
แทนที่จะสร้าง service ทีละตัว สามารถเตรียม docker-compose.yml แล้ว deploy เป็น stack ทั้งหมด:
version: '3.8'
services:
web:
image: nginx:latest
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
ports:
- "80:80"
db:
image: postgres:13
deploy:
replicas: 1
placement:
constraints: [node.role == manager]
environment:
POSTGRES_PASSWORD: secret123
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
สำหรับ deploy stack บน manager node:
docker stack deploy -c docker-compose.yml myapp
# ดู stack ที่มีอยู่
docker stack ls
# ดู service ภายใน stack
docker stack services myapp
# ดู task (running container instance) ของ stack
docker stack ps myapp
# ลบ stack
docker stack rm myapp
ตั้ง Overlay Network สำหรับ Internal Communication
Overlay network ช่วยให้ container บน node ต่างๆ สื่อสารกันได้ผ่าน VXLAN โดย control-plane traffic (gossip ระหว่าง manager) ถูก encrypt ด้วย AES-GCM อยู่แล้วโดยอัตโนมัติ แต่ data-plane traffic (ข้อมูลจริงระหว่าง container) จะยังไม่ encrypt จนกว่าจะสร้าง network ด้วย flag --opt encrypted:
# สร้าง overlay network แบบเข้ารหัส data-plane traffic
docker network create --driver overlay --opt encrypted --attachable mynet
# ใช้ network นั้นสำหรับ service
docker service create \
--name myapp \
--network mynet \
--publish 8080:8080 \
myapp:latest
# Service ที่เชื่อต่อ mynet จะรู้ IP address ของกันเองผ่าน DNS
# โดยใช้ชื่อ service เป็น hostname เช่น ping myapp จะไป container ตัวหนึ่งของ service myapp
ตรวจสอบว่า Docker Swarm ทำงานถูกต้อง
# ดู status ของ cluster
docker info | grep Swarm
# ดู node ทั้งหมด
docker node ls
# ตรวจสอบ node specific
docker node inspect node-name
# ดู service ทั้งหมด
docker service ls
# ดู task/container ที่ running
docker service ps web
# ดู network ทั้งหมด
docker network ls | grep overlay
docker node update --availability drain node-name เพื่อไม่ให้ container ใหม่วางบน node นั้น แล้วทำการซ่อม ตัว container ที่ทำงานอยู่จะย้ายไปยัง node อื่นอัตโนมัติ
แก้ปัญหาที่พบบ่อย
Error: "node is not part of a swarm"
Node ยังไม่ได้ join เข้า Swarm cluster หรือ leave มาแล้ว ให้ run docker swarm init (ถ้าจะเป็น manager) หรือ docker swarm join (ถ้าจะเป็น worker) อีกครั้ง:
# ตรวจสอบ Swarm status
docker info | grep Swarm
# ถ้าเป็น "inactive" ให้ initialize
docker swarm init --advertise-addr=LOCAL_IP
Error: "could not choose an IP address to advertise"
Docker ไม่พบ IP address ที่สามารถใช้ได้ สั่ง initialize ด้วย flag --advertise-addr ชี้ IP ที่ชัดเจน:
# หา IP address ของ interface
ip addr show
# Initialize ด้วย IP ที่ชัดเจน
docker swarm init --advertise-addr=192.168.1.10
Error: "cannot accept new swarm requests" or "node is already part of a swarm"
Node อยู่ใน Swarm อื่นหรือเป็น standalone แล้ว ต้อง leave ออกจากอันเก่าก่อน:
# ออกจาก Swarm
docker swarm leave --force
# แล้วจึง join เข้าอันใหม่
docker swarm join --token SWMTKN-1-xxx MANAGER_IP:2377
Error: "container status is not running"
Service container ที่ deploy ไม่ start ขึ้น ตรวจสอบ log ของ service เพื่อรู้สาเหตุ:
docker service logs SERVICE_NAME --tail 50
# ดู task/container specific
docker service ps SERVICE_NAME
# ตรวจสอบแต่ละ container
docker ps -a
docker logs CONTAINER_ID
Error: "timeout when dialing" หรือ manager node ไม่ responsive
Network latency สูงหรือ firewall block port สำหรับ Swarm ต้องเปิด port เหล่านี้:
# 2376/tcp - TLS port
# 2377/tcp - Swarm manager communication
# 7946/tcp, 7946/udp - Swarm node communication
# 4789/udp - Overlay network traffic
# ตรวจสอบ firewall
sudo ufw status numbered
# ถ้า port ยังปิด ให้เปิด
sudo ufw allow 2377/tcp
sudo ufw allow 7946/tcp
sudo ufw allow 7946/udp
sudo ufw allow 4789/udp
คำถามที่พบบ่อย
Docker Swarm กับ Kubernetes ต่างกันอย่างไร?
Swarm built-in มากับ Docker เลย ตั้งค่าง่ายและเร็ว ไม่ต้องติดตั้ง extra software ส่วน Kubernetes ซับซ้อนกว่าแต่มี advanced feature เช่น auto-scaling, custom scheduler, network policy ให้เลือกใช้มากกว่า เหมาะสำหรับ production ที่ต้องการความยืดหยุ่นสูง ส่วน Swarm เหมาะสำหรับทีมที่ต้องการความเรียบง่าย และดูแล container ได้ในระดับหลักร้อยถึงหลักพัน
Overlay network ใน Swarm ปลอดภัยไหม?
Overlay network ใช้ VXLAN encapsulation control-plane traffic ระหว่าง manager node ถูก encrypt ด้วย AES-GCM โดยอัตโนมัติอยู่แล้ว แต่ data-plane traffic ของ application ต้องสร้าง network ด้วย --opt encrypted เองถึงจะเข้ารหัส ความปลอดภัยที่เหลือขึ้นอยู่กับการกำหนด network ให้เข้มงวด ควรแบ่ง network แต่ละ stack และจำกัดให้ service สื่อสารกันได้เท่าที่จำเป็น
Manager node สามารถรัน container ได้ไหม?
ได้ แต่ไม่ควรทำ manager node ควรทำหน้าที่ orchestration เท่านั้น ไม่ควรรับโหลด application เพื่อความเสถียรของ cluster ถ้าจำเป็น สามารถ drain manager node แล้ว uncordon ด้วย docker node update --availability active node-name แต่ best practice คือให้ worker node รับภาระ application ทั้งหมด