Docker Swarm: รันแอปแบบ HA ง่ายๆ ไม่ต้องปวดหัวมาก
ช่วงนี้ใครๆ ก็พูดถึง Kubernetes เนอะ แต่เอาจริงๆ มันก็ใหญ่ไปสำหรับหลายๆ โปรเจกต์นะ บางทีเราแค่อยากรันแอปหลายๆ ตัว ให้มันมี HA (High Availability) หน่อย หรืออยากจัดการ service ง่ายๆ Docker Swarm นี่แหละ คือคำตอบที่โคตรง่าย
ทำไมถึงเลือก Swarm?
ก็อย่างที่บอกอ่ะ มันง่ายโคตรๆ ตั้งค่าง่าย จัดการ service ง่าย เหมาะกับโปรเจกต์ขนาดกลางๆ หรือใครที่เริ่มจาก Docker Compose มาแล้วอยากขยับขยายขึ้นมาอีกนิด Swarm มันตอบโจทย์ ไม่ต้องไปเรียนรู้อะไรใหม่เยอะเลย (ซึ่งส่วนตัวชอบตรงนี้แหละ ประหยัดเวลาไปได้เยอะเลย)
ลองมาสร้าง Swarm กัน!
สมมติว่าเรามี server อยู่ 3 ตัวนะ ตั้งชื่อ manager01, worker01, worker02 (อันนี้สมมตินะ ปกติใช้ IP หรือ hostname)
1. เริ่ม Swarm Manager:
ล็อกอินเข้า manager01 แล้วรันคำสั่งนี้เลย:
docker swarm init --advertise-addr <IP_ของ_manager01>
แทนที่ <IP_ของ_manager01> ด้วย IP Address จริงๆ ของเครื่อง manager01 นะ
พอรันแล้วมันจะบอก command ให้เอาไปรันที่ worker เพื่อ join เข้ามาใน swarm ของเรา หน้าตาประมาณนี้เลย:
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxx <IP_ของ_manager01>:2377
2. เอา Worker เข้ามาใน Swarm:
ไปที่ worker01 กับ worker02 แล้วแปะ command ที่ได้มาจาก manager01 เมื่อกี้เลย (copy มาแปะทั้งบรรทัดนั่นแหละ):
docker swarm join --token SWMTKN-1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxx <IP_ของ_manager01>:2377
เสร็จแล้ว! ทีนี้กลับไปที่ manager01 ลองเช็คดูว่า node มาครบมั้ย:
docker node ls
น่าจะเห็นประมาณนี้:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
fjklsdafjsldkfjsdlfkj manager01 Ready Active Leader 24.0.5
dsfsdkfjsdklfjklsdfjs worker01 Ready Active 24.0.5
ewqrewqrewqrewqrewqre worker02 Ready Active 24.0.5
เยี่ยมเลย! Swarm ของเราพร้อมใช้งานแล้ว
Deploy แอปง่ายๆ ด้วย Service
ทีนี้เราจะลอง deploy เว็บ Nginx ง่ายๆ ซักตัวให้มันรัน 3 replica แล้วต่อกับ Redis ด้วย (เผื่อเว็บเราต้องใช้ cache หรือเก็บ session อะไรพวกนี้ไง)
สร้างไฟล์ docker-compose.yml อันนี้เลย (ใช่แล้ว! Swarm ใช้ compose file ได้ด้วย เจ๋งมั้ยล่ะ):
version: '3.8'
services:
web:
image: nginx:latest
ports:
- "80:80"
deploy:
replicas: 3 # รัน 3 ตัวเลย เพื่อ HA
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure # ถ้าพังก็ให้มัน restart เอง
depends_on:
- redis # อันนี้บอกว่า web service ต้องพึ่ง redis นะ
redis:
image: redis:latest
deploy:
replicas: 1 # Redis ตัวเดียวพอ
restart_policy:
condition: on-failure
volumes:
- redis_data:/data # เก็บข้อมูล redis ลง volume ให้มันไม่หายไปไหน
volumes:
redis_data:
เซฟไฟล์นี้ไว้ที่ manager01 แล้วรันคำสั่งนี้:
docker stack deploy -c docker-compose.yml myapp
myapp นี่คือชื่อ stack ของเรานะ จะตั้งอะไรก็ได้ตามใจเลย
ลองเช็คดู service ที่รันอยู่:
docker service ls
หรืออยากดูละเอียดขึ้นว่าแต่ละ service ไปรันอยู่บน node ไหนบ้าง:
docker service ps myapp_web
docker service ps myapp_redis
เราจะเห็นว่า myapp_web มันรัน 3 ตัวกระจายๆ กันไปใน node ที่เรามี (Swarm จะพยายามกระจายให้เราเอง) ส่วน myapp_redis ก็รัน 1 ตัวตามที่เราสั่ง
ปัญหาที่เคยเจอจริงๆ นะ! (และวิธีแก้)
อันนี้เจอเองบ่อยมากๆ เลย คือตอน deploy service ที่ใช้ ports แบบ publish port (เช่น 80:80 เหมือน Nginx เมื่อกี้) บางทีมันไปชนกับ port ที่รันอยู่บน host นั้นๆ พอดี ทำให้ service มันรันไม่ได้แล้วก็วนลูป restarting ไปเรื่อยๆ
ตัวอย่าง error ที่เคยเห็นใน docker service ps หรือ docker logs <container_id> ก็ประมาณนี้:
Error response from daemon: driver failed programming external connectivity on endpoint myapp_web.1.<container_id> (<hash>): Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use
เห็นคำว่า bind: address already in use นี่รู้เลยว่า port ชนแน่นอน วิธีแก้ก็คือ ต้องไปหาว่าโปรแกรมอะไรมันใช้ port นั้นอยู่ (ใช้ sudo netstat -tulpn | grep :80 ดูได้) แล้วก็จัดการปิดมันซะ หรือไม่ก็เปลี่ยน port ของ service เราให้ไม่ชนกับใครเลย
อีกอันที่เจอบ่อยคือ เวลาอัปเดตอิมเมจ แล้ว service มันไม่ยอมดึงอิมเมจใหม่มาใช้ ทั้งๆ ที่เรา build ใหม่แล้วแท็กเดิม (เช่น myapp:latest) อันนี้ต้องบังคับให้มันดึงใหม่ด้วย docker service update --force --with-registry-auth myapp_web หรือเปลี่ยนแท็กอิมเมจไปเลยเป็นเวอร์ชันใหม่ๆ แทน (ซึ่งส่วนตัวแนะนำอันหลังสุด เพราะมันจัดการเวอร์ชันได้ง่ายกว่าเยอะ)
สรุปนะ
Docker Swarm มันเป็นเครื่องมือที่เรียบง่ายแต่ทรงพลังโคตรๆ สำหรับการทำ container orchestration ไม่ต้องเสียเวลาไปเรียนรู้อะไรที่ซับซ้อน ถ้าโปรเจกต์เราไม่ได้ใหญ่โตมโหฬารเท่า Google Swarm ก็คือคำตอบที่ดีเลยแหละ ลองเล่นดูนะ ไม่ผิดหวังแน่นอน! เหมาะสำหรับคนอยากเริ่มจัดระเบียบ Docker containers ของตัวเองจริงๆ