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 ของตัวเองจริงๆ

Read more

ไอลีน กู: ตำนานนักสกีฟรีสไตล์ผู้พลิกโฉมวงการและความหมายของชัยชนะ

ไอลีน กู: ตำนานนักสกีฟรีสไตล์ผู้พลิกโฉมวงการและความหมายของชัยชนะ

เจาะลึกเรื่องราวของ Eileen Gu นักสกีฟรีสไตล์ผู้สร้างประวัติศาสตร์ในโอลิมปิก 2026 สถิติที่ไม่เคยมีมาก่อน ประเด็นถกเถียง และความแข็งแกร่งส่วนตัวที่ทำให้เธอก้าวสู่ระดับโลก

By ทีมงาน devdog
วันพระ: คู่มือฉบับสมบูรณ์สำหรับพุทธศาสนิกชนและผู้สนใจยุคใหม่

วันพระ: คู่มือฉบับสมบูรณ์สำหรับพุทธศาสนิกชนและผู้สนใจยุคใหม่

เจาะลึกวันพระและความสำคัญของวันมาฆบูชา 2569 ทั้งวันหยุดราชการ ธนาคาร กิจกรรมเวียนเทียนต้นไม้ และผลกระทบต่อบริการขนส่ง เตรียมตัววางแผนทำบุญและพักผ่อน

By ทีมงาน devdog
ถอดรหัสรักแท้: "บังมัดคลองตันต้นข้าว" เรื่องราวที่สะท้อนการให้อภัยและการเริ่มต้นใหม่

ถอดรหัสรักแท้: "บังมัดคลองตันต้นข้าว" เรื่องราวที่สะท้อนการให้อภัยและการเริ่มต้นใหม่

เจาะลึกงานวิวาห์ "บังมัดคลองตัน" กับ "ต้นข้าว มิสแกรนด์" พร้อมเหตุผลจากใจเจ้าสาวที่เลือกความรักเหนือกาลเวลาและคำวิจารณ์ สู่การเริ่มต้นชีวิตคู่ที่สะท้อนการให้อภัย

By ทีมงาน devdog
ไฮไลท์บอลไทยลีก 2: มหาสารคาม เอสบีที เอฟซี กับฟอร์มร้อนแรงสู่เส้นทางเพลย์ออฟ

ไฮไลท์บอลไทยลีก 2: มหาสารคาม เอสบีที เอฟซี กับฟอร์มร้อนแรงสู่เส้นทางเพลย์ออฟ

เจาะลึกไฮไลท์บอลไทยลีก 2 ของมหาสารคาม เอสบีที เอฟซี กับฟอร์มร้อนแรง ชัยชนะสำคัญจาก ชิตชนก และบทบาทโค้ชดุสิต สู่เส้นทางเพลย์ออฟที่น่าจับตา!

By ทีมงาน devdog