7. Swarm Mode
Mục lục
- 1. Orchestration & Swarm mode là gì?
- 2. Khái niệm nền tảng: node, manager/worker, service
- 3. Dựng 1 swarm
- 4. High availability của manager
- 5. Service — khai báo, scale, update, xóa
Chương này mô tả Swarm mode — công nghệ orchestration gốc của Docker, ra mắt từ Docker 1.12 (2016). Tại thời điểm sách gốc viết, đây là hướng đi orchestration chính của Docker, Inc. Cần biết thêm: theo thời gian, phần lớn ngành công nghiệp container đã dịch chuyển sang dùng Kubernetes làm công cụ orchestration phổ biến nhất (xem thêm ở tài liệu "Kubernetes for the Absolute Beginners" trên trang này) — Swarm mode vẫn tồn tại và vẫn được Docker Engine hỗ trợ, nhưng không còn là lựa chọn orchestration phổ biến nhất trong thực tế ngày nay. Đọc chương này để hiểu khái niệm nền tảng của orchestration (manager/worker, service, desired state, rolling update...) — phần lớn khái niệm này cũng chính là nền tảng để hiểu Kubernetes sau này.
1. Orchestration & Swarm mode là gì?
Biết cách cài Docker, pull image, và làm việc với container là chưa đủ — cần thêm 1 cách để làm việc với tất cả ở quy mô lớn. Đó là lúc orchestration và swarm mode xuất hiện.
Ở tầm nhìn cao, orchestration là tự động hóa và đơn giản hóa việc quản lý ứng dụng containerized ở quy mô lớn — như tự động reschedule container khi node hỏng, tự scale khi nhu cầu tăng, và đẩy update/fix vào production 1 cách êm ái.
Trước đây, việc này khá phức tạp — có Docker Swarm (bản classic) và Kubernetes, nhưng đều đòi hỏi cấu hình phức tạp. Rồi Docker 1.12 ra mắt swarm mode — clustering và orchestration native, tích hợp thẳng vào chính Docker platform, khiến mọi thứ dễ dàng hơn hẳn qua một đêm.
2. Khái niệm nền tảng: node, manager/worker, service
Đội ngũ Docker, Inc. không thích dùng từ "cluster" — họ gọi 1 cụm Docker host được orchestrate là swarm, và các host tham gia gọi là đang chạy ở swarm mode. Host không tham gia swarm được gọi là chạy ở single-engine mode.
Backward compatibility
Swarm mode hoàn toàn tùy chọn (optional) — cài Docker mặc định vẫn chạy ở single-engine mode, đảm bảo tương thích ngược 100% với các bản Docker cũ. Chỉ khi chủ động chuyển Docker host sang swarm mode, bạn mới có toàn bộ khả năng orchestration mới — đổi lại có thể phá vỡ tương thích với 1 số tool/app bên thứ 3 vốn quen làm việc ở single-engine mode.
Các thành phần chính
- Node: 1 server vật lý, VM, hay cloud instance tham gia swarm — yêu cầu duy nhất là mọi node trong swarm giao tiếp được với nhau qua network đáng tin cậy.
- Manager: trông coi trạng thái cluster, chịu trách nhiệm dispatch task cho worker.
- Worker: nhận task từ manager và thực thi chúng.
- Task: trong ngữ cảnh swarm, "task" nghĩa là container — đôi khi cũng gọi là "replica". Nói "manager dispatch task cho worker" tức là dispatch container workload.
- Service: cách để chạy task trên swarm — muốn chạy 1 task (container) trên swarm, bạn "bọc" nó trong 1 service rồi deploy service đó. Bản chất, service là 1 cách khai báo desired state mong muốn trên cluster: số lượng task, image dùng cho các container trong service, quy trình update lên version image mới...
💡 Hình dung: swarm giống 1 nhà hàng. Manager là quản lý nhà hàng — không tự tay nấu ăn, chỉ nhận order rồi phân công đúng đầu bếp nào làm món gì. Worker là đầu bếp — nhận phân công và thực sự nấu (chạy container). Service giống 1 mục trong thực đơn ghi rõ "món này luôn phải có sẵn 5 phần" — quản lý (manager) đảm bảo lúc nào cũng đủ 5 phần đang được chuẩn bị, đầu bếp nào nghỉ thì phân ngay cho đầu bếp khác.
Trạng thái và cấu hình của swarm được lưu trong 1 database etcd phân tán, nằm trên mọi manager, luôn cập nhật gần như real-time, host in-memory để nhanh — và quan trọng là không cần cấu hình gì cả, tự cài kèm swarm và tự vận hành. Swarm mode cũng tích hợp TLS sâu tới mức không thể dựng 1 swarm mà không có TLS — mã hóa giao tiếp, xác thực node, phân quyền role, và tự động xoay vòng key, tất cả diễn ra êm ái phía sau.
3. Dựng 1 swarm
Chạy docker swarm init trên 1 Docker host ở single-engine mode sẽ chuyển nó sang swarm mode, tạo swarm mới, và biến nó thành manager đầu tiên. Các node khác join vào swarm (làm worker hoặc manager) bằng docker swarm join.
Bước 1 — Khởi tạo swarm trên manager đầu tiên
$ docker swarm init \
--advertise-addr 10.0.0.1:2377 \
--listen-addr 10.0.0.1:2377
Swarm initialized: current node (d21lyz...c79qzkx) is now a manager.
docker swarm init: khởi tạo swarm mới, biến node hiện tại thành manager đầu tiên, đồng thời bật swarm mode trên chính node đó.--advertise-addr: IP:port mà các node khác dùng để kết nối tới manager này (có thể là IP không tồn tại trên chính node, ví dụ IP của load balancer).--listen-addr: IP:port mà node lắng nghe traffic swarm — thường trùng--advertise-addr, hữu ích khi cần giới hạn swarm chỉ dùng 1 IP cụ thể trên máy có nhiều IP.
Nên luôn chỉ định tường minh cả 2 cờ này thay vì để mặc định. Cổng mặc định của swarm mode là 2377.
Xem danh sách node trong swarm:
$ docker node ls
# Output minh họa
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
d21lyz...c79qzkx * mgr1 Ready Active Leader
(Output minh họa — mới có đúng 1 node vì chưa join thêm ai; dấu * đánh dấu node đang chạy lệnh này.)
Bước 2 — Lấy token để join worker/manager
$ docker swarm join-token worker
# Output minh họa
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-49nj1cmql0jkz5s...1qz1c 10.0.0.1:2377
$ docker swarm join-token manager
# Output minh họa
To add a manager to this swarm, run the following command:
docker swarm join --token SWMTKN-1-49nj1cmql0jkz5s...5v0j 10.0.0.1:2377
(Output minh họa — token thật dài hơn nhiều; để ý 3 phần đầu của cả 2 token giống hệt nhau, chỉ khác đúng phần cuối cùng.)
Lệnh join của worker và manager giống hệt nhau, chỉ khác token — node join làm worker hay manager hoàn toàn phụ thuộc vào token nào được dùng. Cần bảo vệ token cẩn thận, vì chỉ cần có token là join được vào swarm.
Bước 3 — Join các node còn lại
# Trên từng worker
$ docker swarm join \
--token SWMTKN-1-... \
10.0.0.1:2377 \
--advertise-addr 10.0.0.4:2377 \
--listen-addr 10.0.0.4:2377
# Output minh họa
This node joined a swarm as a worker.
# Trên các manager phụ
$ docker swarm join \
--token SWMTKN-1-... \
10.0.0.1:2377 \
--advertise-addr 10.0.0.2:2377 \
--listen-addr 10.0.0.2:2377
# Output minh họa
This node joined a swarm as a manager.
Kiểm tra lại toàn bộ swarm từ bất kỳ manager nào:
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
0g4...bl8 * mgr2 Ready Active Reachable
2xl...nyp mgr3 Ready Active Reachable
8yv...r67 wrk1 Ready Active
9mz...4m4n wrk3 Ready Active
d21...qzkx mgr1 Ready Active Leader
e62...5wt6 wrk2 Ready Active
Cột MANAGER STATUS cho biết manager nào là Leader, manager nào chỉ Reachable; node không có gì ở cột này là worker. Dấu * sau ID đánh dấu node bạn đang chạy lệnh docker node ls từ đó.
4. High availability của manager
Swarm manager có sẵn cơ chế HA (high availability) — 1 hoặc nhiều manager chết, các manager còn sống vẫn giữ swarm hoạt động. Về kỹ thuật, swarm mode hiện thực mô hình active-passive multi-manager HA: dù có nhiều manager, chỉ duy nhất 1 manager được coi là active tại 1 thời điểm — gọi là leader. Leader là manager duy nhất thực sự phát lệnh sống (live command) cho swarm; manager không phải leader nhận lệnh sẽ tự proxy lệnh đó sang leader.
Swarm dùng 1 bản hiện thực của thuật toán đồng thuận Raft để vận hành manager HA, kéo theo 2 best practice:
- Luôn triển khai số lượng manager lẻ.
- Không triển khai quá nhiều manager (khuyến nghị 3 hoặc 5).
Số manager lẻ giúp tăng khả năng đạt quorum (số phiếu tối thiểu — quá nửa tổng số manager — cần có để 1 quyết định được coi là hợp lệ) và tránh split-brain (tình huống network bị chia đôi khiến mỗi nửa cluster tưởng mình mới là "phần thật", có thể dẫn tới 2 bên cùng nhận lệnh và ghi state mâu thuẫn nhau — cực kỳ nguy hiểm với dữ liệu). Ví dụ có 4 manager, network bị chia đôi (partition) — mỗi bên còn lại 2 manager, không bên nào biết chắc bên kia còn sống hay đang giữ đa số (quorum). Nhưng nếu có 3 hoặc 5 manager, cùng 1 kiểu chia mạng như vậy sẽ không thể chia đều 2 bên bằng nhau — 1 bên chắc chắn biết mình đang nắm nhiều hơn hoặc ít hơn bên kia, dễ đạt quorum hơn hẳn.
💡 Hình dung: cũng như mọi thuật toán đồng thuận khác, càng nhiều thành viên tham gia càng mất nhiều thời gian để đạt đồng thuận — giống việc 3 người chọn quán ăn trưa luôn nhanh hơn 33 người. Vì vậy khuyến nghị chuẩn là 3 hoặc 5 manager (7 có thể chạy được, nhưng thường 3-5 là tối ưu; không nên vượt quá 7).
Vì vậy khuyến nghị chuẩn là 3 hoặc 5 manager (7 có thể chạy được, nhưng thường 3-5 là tối ưu; không nên vượt quá 7).
Lưu ý: nên trải manager qua nhiều availability zone khác nhau để tăng độ bền vững, nhưng network kết nối giữa các manager phải đủ tin cậy — network partition là vấn đề thực sự nghiêm trọng với manager HA.
5. Service — khai báo, scale, update, xóa
Service là construct mới từ Docker 1.12, chỉ tồn tại trong swarm mode — cho phép khai báo desired state cho 1 application service rồi giao cho Docker lo phần còn lại. Ví dụ: có 1 web front-end, testing cho thấy cần 5 instance để chịu tải hằng ngày — bạn khai báo 1 service dùng đúng image đó, luôn duy trì 5 task đang chạy.
Tạo service
$ docker service create --name web-fe \
-p 8080:8080 \
--replicas 5 \
myteam/hello-web
# Output minh họa
9uk4639qs6d3aekdgr6829f3f
overall progress: 5 out of 5 tasks
1/5: running
2/5: running
3/5: running
4/5: running
5/5: running
verify: Service converged
(Output minh họa — dòng đầu là service ID; các dòng sau là tiến trình dispatch 5 task, kết thúc bằng "Service converged" khi actual state đã khớp desired state.)
--name: đặt tên service.-p 8080:8080: map cổng 8080 trên mọi node của swarm vào cổng 8080 bên trong mỗi container (task) của service.--replicas 5: luôn duy trì 5 task/container — mọi task trong 1 service dùng chung 1 image và config.
Sau khi Enter, manager đang là leader phân bổ 5 task ra khắp swarm (manager cũng đóng vai trò worker), mỗi worker/manager được giao task tự pull image và chạy container. Leader cũng đảm bảo desired state được đồng bộ tới mọi manager khác.
Điều quan trọng: swarm liên tục chạy 1 reconciliation loop, so sánh actual state với desired state. Nếu khớp, không làm gì; nếu lệch (ví dụ 1 worker hỏng khiến số task chạy tụt từ 5 xuống 4), swarm tự khởi động task mới để đưa actual state trở lại khớp desired state — cơ chế tự chữa lành (self-heal) khi node gặp sự cố.
💡 Hình dung: reconciliation loop giống 1 cái nhiệt kế điều nhiệt (thermostat) — bạn đặt nhiệt độ mong muốn (desired state) là 25°C, cảm biến liên tục đo nhiệt độ thật (actual state) trong phòng, lệch bao nhiêu thì máy lạnh tự bật/tắt để kéo về đúng 25°C. Swarm làm y hệt vậy với số lượng task, chỉ khác "nhiệt độ" ở đây là "có đúng 5 container đang chạy hay không".
Xem & inspect service
$ docker service ls # liệt kê service + số replica đang chạy/mong muốn
# Output minh họa
ID NAME MODE REPLICAS IMAGE PORTS
9uk4639qs6d3 web-fe replicated 5/5 myteam/hello-web:latest *:8080->8080/tcp
$ docker service ps web-fe # chi tiết từng task, đang chạy trên node nào
# Output minh họa
NAME IMAGE NODE DESIRED STATE CURRENT STATE
web-fe.1 myteam/hello-web:latest mgr1 Running Running 2 minutes ago
web-fe.2 myteam/hello-web:latest wrk1 Running Running 2 minutes ago
web-fe.3 myteam/hello-web:latest wrk2 Running Running 2 minutes ago
$ docker service inspect --pretty web-fe # chi tiết đầy đủ cấu hình service
(Output minh họa — rút gọn; docker service inspect --pretty trả về toàn bộ config dưới dạng nhiều dòng dễ đọc, không liệt kê hết ở đây.)
Scale service
$ docker service scale web-fe=10
# Output minh họa
web-fe scaled to 10
overall progress: 10 out of 10 tasks
verify: Service converged
(Output minh họa — giống hệt cấu trúc output lúc tạo service, vì bản chất scale cũng chỉ là đổi 1 con số trong desired state rồi để reconciliation loop tự xử lý.)
Lệnh này chỉ đơn giản cập nhật desired state từ 5 lên 10 — swarm tự lo phần còn lại, cố gắng cân bằng task đều nhất có thể giữa các node (mặc định chỉ cân bằng theo số lượng task, chưa tính tới CPU load...).
Xóa service
$ docker service rm web-fe
# Output minh họa
web-fe
(Output minh họa — lệnh chỉ echo lại đúng tên service vừa xóa.)
⚠️ Lưu ý: lệnh này xóa toàn bộ task trong service ngay lập tức, không hỏi xác nhận — cẩn trọng khi dùng.
Rolling update
Ví dụ tạo 1 service mới, gắn với 1 overlay network riêng (demo-net — chi tiết cơ chế overlay network sẽ nói ở phần sau):
$ docker network create -d overlay demo-net
$ docker service create --name demo-svc \
--network demo-net \
-p 80:80 --replicas 12 \
myteam/webapp:v1
# Output minh họa
overall progress: 12 out of 12 tasks
verify: Service converged
Giả sử cần đẩy bản cập nhật image mới (v2) theo từng đợt nhỏ — 2 container 1 lần, nghỉ 20 giây giữa các đợt:
$ docker service update \
--image myteam/webapp:v2 \
--update-parallelism 2 \
--update-delay 20s demo-svc
# Output minh họa
demo-svc
overall progress: 2 out of 12 tasks
1/12: running [=================================================>]
2/12: running [=================================================>]
...
(Output minh họa — rút gọn; tiến trình rollout hiện tăng dần theo từng đợt 2 task, cách nhau 20s một lần, cho tới khi đủ 12/12.)
docker service update cập nhật desired state của service đang chạy — ở đây đổi sang tag v2, đồng thời --update-parallelism/--update-delay kiểm soát tốc độ rollout. Chạy docker service ps demo-svc trong lúc update sẽ thấy 1 số task đã chuyển sang v2, số khác vẫn ở v1 — đủ thời gian (trong ví dụ khoảng 4 phút với 12 replica), toàn bộ sẽ chuyển hết sang v2. Mở trình duyệt refresh liên tục vào bất kỳ node nào trong swarm trong lúc rollout sẽ thấy request được phục vụ xen kẽ bởi cả bản cũ lẫn bản mới, cho tới khi rollout hoàn tất.
docker service inspect --pretty sau đó sẽ cho thấy update-parallelism/update-delay đã trở thành 1 phần cấu hình mặc định của service — các lần update sau sẽ tự dùng lại đúng thiết lập này trừ khi override.
Theo kinh nghiệm vận hành thực tế, phần lớn giá trị của swarm mode không nằm ở việc "biết gõ đúng lệnh" mà ở việc hiểu đúng mô hình desired state — một khi đã quen tư duy "khai báo mình muốn gì, để hệ thống tự đưa thực tế về đúng như vậy" thay vì tự tay xử lý từng sự cố, việc chuyển sang Kubernetes sau này sẽ nhẹ nhàng hơn hẳn, vì đây chính xác là triết lý cốt lõi mà mọi hệ thống orchestration hiện đại đều dùng chung.
Một câu hỏi còn bỏ ngỏ: các task/container trong ví dụ demo-svc ở trên nằm rải trên nhiều node khác nhau — vậy chúng gọi được tới nhau bằng cách nào, qua network nào? Đó chính là chủ đề của phần tiếp theo: overlay networking.
Danh sách lệnh chính
| Lệnh | Công dụng |
|---|---|
docker swarm init | Tạo swarm mới, biến node hiện tại thành manager đầu tiên |
docker swarm join-token worker / manager | Lấy lệnh + token để join node khác vào swarm |
docker node ls | Liệt kê toàn bộ node trong swarm, ai là manager/leader |
docker service create | Khai báo (declare) 1 service mới |
docker service ls / docker service ps <service> | Xem tổng quan / chi tiết từng task của service |
docker service inspect --pretty <service> | Xem chi tiết đầy đủ cấu hình service |
docker service scale <service>=<n> | Scale số task lên/xuống |
docker service update | Cập nhật thuộc tính của service đang chạy (rolling update) |
docker service rm <service> | Xóa service — xóa toàn bộ task, không hỏi xác nhận |
Nguồn tham khảo
Nguồn gốc: Bài viết lấy cảm hứng từ sách "Docker Deep Dive" — tác giả Nigel Poulton (bản phát hành version 4, 3/10/2017), Part 2: The Technical Stuff — chapter 9 "Swarm Mode". Nội dung được viết lại theo cách hiểu và ví dụ riêng, không sao chép nguyên văn hay dịch sát nguyên bản. Muốn đọc bản đầy đủ hoặc ủng hộ tác giả, có thể mua sách tại leanpub.com/dockerdeepdive.
Đã verify qua research (Mode R) — vẫn đúng với Docker hiện tại, không cần đính chính:
- Cổng TCP mặc định cho swarm management traffic (raft sync) là 2377 — Docker Docs — docker swarm init
- Khuyến nghị số manager lẻ (3 hoặc 5, tối đa 7) vẫn là best practice hiện hành — Docker Docs — Administer and maintain a swarm