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

PSG vs Monaco: ศึก 100 นัดเดือด ลีกเอิง และบทเรียนที่ปาร์ค เดส์ แพร็งซ์

PSG vs Monaco: ศึก 100 นัดเดือด ลีกเอิง และบทเรียนที่ปาร์ค เดส์ แพร็งซ์

สรุปผลและวิเคราะห์เกมเดือด PSG พบ Monaco ในลีกเอิงนัดที่ 25 ซึ่งเป็นการพบกันครั้งที่ 100 ในประวัติศาสตร์ลีก ความพ่ายแพ้ 1-3 คาบ้านของ PSG และบทบาทของ Akliouche พร้อมผลกระทบต่อเส้นทางแชมเปี้ยนส์ลีก

By ทีมงาน devdog
บาเยิร์นผงาดไร้เคน! ถล่มกลัดบัค 4-1 โชว์ความลึกของทีมก่อนลุยศึก UCL

บาเยิร์นผงาดไร้เคน! ถล่มกลัดบัค 4-1 โชว์ความลึกของทีมก่อนลุยศึก UCL

บาเยิร์น มิวนิค โชว์ฟอร์มแกร่ง แม้ไม่มีแฮร์รี่ เคน ถล่ม โบรุสเซีย มึนเชนกลัดบัค 4-1 ก่อนเตรียมลุยศึกแชมเปียนส์ลีกกับอตาลันต้า!

By ทีมงาน devdog
PSG: มหาอำนาจลูกหนังฝรั่งเศส กับศึกดวลเดือดโมนาโก และเป้าหมายสู่บัลลังก์ยุโรป

PSG: มหาอำนาจลูกหนังฝรั่งเศส กับศึกดวลเดือดโมนาโก และเป้าหมายสู่บัลลังก์ยุโรป

เจาะลึกเส้นทาง PSG สู่มหาอำนาจลูกหนัง วิเคราะห์สถานการณ์ลีกเอิง เตรียมพร้อมศึกใหญ่กับโมนาโก พร้อมความมุ่งมั่นสู่แชมป์ยุโรป

By ทีมงาน devdog
ลาลีกา: มนต์เสน่ห์ฟุตบอลสเปน, นวัตกรรมเรโทร, และบิ๊กแมตช์แห่งอนาคต

ลาลีกา: มนต์เสน่ห์ฟุตบอลสเปน, นวัตกรรมเรโทร, และบิ๊กแมตช์แห่งอนาคต

สำรวจลาลีกา ฟุตบอลสเปนอันทรงเสน่ห์ พร้อมไฮไลต์บิ๊กแมตช์ 2025/26 นวัตกรรมสัปดาห์เรโทร และบทบาทต่อวัฒนธรรมและเศรษฐกิจ.

By ทีมงาน devdog