Vấn đề thực tế: Khi app chết theo server
Hồi đó mình đang deploy một dự án e-commerce nhỏ, chạy hoàn toàn bằng Docker trên một VPS duy nhất. Mọi thứ ổn cho đến khi server bị quá tải RAM — app bỗng dưng sập giữa đêm, không có gì tự restart. Tệ hơn là khi chuyển sang microservices, mình gặp memory leak trong container mà debug mất gần 2 ngày. Một phần vì không có cái nhìn tổng quan nào — không biết container nào đang ngốn tài nguyên bất thường trên host.
Thêm vào đó, mỗi lần traffic tăng đột biến, mình phải SSH vào server thủ công, docker run thêm container, rồi cấu hình lại nginx. Vừa tốn thời gian, vừa dễ nhầm lẫn.
Nghe quen không? Một server, scaling tay, không failover. Đó chính xác là lúc cần nghĩ đến container orchestration.
Phân tích nguyên nhân: Tại sao chỉ dùng Docker không đủ?
Docker rất tốt để đóng gói và chạy ứng dụng, nhưng nó không giải quyết được ba bài toán cốt lõi khi production:
- Single point of failure: Một server chết, toàn bộ container chết theo.
- Scaling thủ công: Muốn chạy 5 replica của một service, bạn phải tự
docker runnăm lần. - Không có load balancing tự động: Không có gì phân phối traffic giữa các container khi bạn chạy nhiều instance.
Bản chất của Docker là quản lý container trên một host duy nhất. Muốn nhiều máy làm việc cùng nhau — cần thêm một tầng orchestration ở trên.
Các cách giải quyết: Nên chọn gì?
Nhắc đến container orchestration, ba cái tên sẽ xuất hiện ngay:
- Docker Swarm: Built-in trong Docker Engine, setup đơn giản, cú pháp quen thuộc, phù hợp team nhỏ hoặc dự án vừa.
- Kubernetes (K8s): Mạnh mẽ nhất, nhưng learning curve cao và cần nhiều tài nguyên hơn để vận hành.
- Nomad (HashiCorp): Linh hoạt, hỗ trợ cả workload non-container, nhưng ít phổ biến hơn hai cái kia.
Mới tiếp cận orchestration? Swarm là điểm khởi đầu hợp lý nhất: không cần cài thêm gì, vẫn dùng file docker-compose quen thuộc, và xử lý được 90% use case của dự án vừa và nhỏ.
Cách tốt nhất: Bắt đầu với Docker Swarm từng bước
Khái niệm cơ bản cần hiểu trước
Ba khái niệm bạn sẽ gặp xuyên suốt:
- Node: Một máy chủ tham gia vào cluster. Có hai loại: manager (điều phối, ra quyết định) và worker (thực thi, chạy container).
- Service: Một ứng dụng được deploy lên Swarm, định nghĩa image, số replica, port, resource limits…
- Task: Một container đang thực tế chạy trên node. Mỗi replica của service là một task.
Bước 1: Khởi tạo Swarm cluster
Trên máy manager (server chính), chạy lệnh sau, thay 192.168.1.100 bằng IP thực của máy:
# Khởi tạo Swarm
docker swarm init --advertise-addr 192.168.1.100
Bạn sẽ thấy ngay lệnh để thêm worker vào cluster:
docker swarm join --token SWMTKN-1-xxxxx... 192.168.1.100:2377
Chạy lệnh đó trên máy worker là xong — node tự tham gia cluster ngay. Muốn lấy lại token sau này:
docker swarm join-token worker
Bước 2: Kiểm tra trạng thái cluster
# Xem danh sách node
docker node ls
# Kết quả mẫu:
# ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
# abc123 * manager01 Ready Active Leader
# def456 worker01 Ready Active
Bước 3: Deploy service đầu tiên
Thay vì docker run, bạn dùng docker service create:
# Deploy nginx với 3 replica, expose port 80
docker service create \
--name my-nginx \
--replicas 3 \
--publish published=80,target=80 \
nginx:alpine
# Xem service đang chạy
docker service ls
docker service ps my-nginx
Swarm tự động phân phối 3 container ra các node trong cluster và cân bằng tải giữa chúng.
Bước 4: Scale service chỉ với một lệnh
# Tăng từ 3 lên 5 replica
docker service scale my-nginx=5
# Hoặc dùng update
docker service update --replicas 5 my-nginx
Swarm tự động tìm node còn tài nguyên và spawn thêm container. Không cần tay, không cần SSH vào từng máy.
Bước 5: Deploy bằng Docker Stack (cách làm thực tế)
Trong production, bạn sẽ dùng Docker Stack — tương đương docker-compose nhưng chạy trên Swarm. Tạo file docker-stack.yml:
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "80:80"
deploy:
replicas: 3
restart_policy:
condition: on-failure
update_config:
parallelism: 1
delay: 10s
api:
image: my-api:latest
deploy:
replicas: 2
resources:
limits:
memory: 512M
# Deploy stack lên Swarm
docker stack deploy -c docker-stack.yml my-app
# Xem các service trong stack
docker stack services my-app
# Xem log của service
docker service logs my-app_web
Bước 6: Rolling update không downtime
Đây là thứ mình dùng nhiều nhất trong production: update service mà không cần dừng app. Swarm update từng container một, đảm bảo luôn có instance đang chạy serve traffic:
docker service update \
--image nginx:1.25-alpine \
--update-parallelism 1 \
--update-delay 10s \
my-nginx
Bảo trì node không ảnh hưởng production
Trước khi bảo trì một worker, drain nó để Swarm chuyển task sang node khác:
# Chuyển node sang trạng thái drain (không nhận task mới, task cũ bị di chuyển)
docker node update --availability drain worker01
# Sau khi bảo trì xong, đưa node về active
docker node update --availability active worker01
Tips từ kinh nghiệm thực tế
Quay lại câu chuyện memory leak mình kể ở đầu — sau khi chuyển sang Swarm, mình tìm ra nguyên nhân nhanh hơn nhiều nhờ lệnh docker service ps my-app_api. Thấy ngay task nào bị restart liên tục, từ đó trace log container cụ thể đó. Nếu vẫn dùng Docker đơn lẻ, mình đã không có cái nhìn tổng quan như vậy.
Vài thứ mình học được — phần lớn từ sai lầm — khi vận hành Swarm thực tế:
- Luôn set resource limits:
resources.limits.memorytrong stack file để tránh một service ăn hết RAM của cả node. - Manager node tối thiểu 3 cho production: Để đảm bảo quorum khi 1 manager bị lỗi (Swarm dùng Raft consensus).
- Overlay network tự động: Các service trong cùng stack giao tiếp với nhau qua tên service, không cần cấu hình thêm gì.
- Dùng Docker Secrets thay vì env plain text:
# Tạo secret
echo "my_db_password" | docker secret create db_password -
# Trong stack file:
# secrets:
# db_password:
# external: true
Tổng kết
Docker Swarm giải quyết được bài toán mà single-host Docker không làm được: high availability, auto-scaling và rolling update với downtime gần như bằng 0. Setup chỉ mất vài phút, và nếu bạn đã quen với docker-compose thì không cần học thêm nhiều.
Khi nào thì cần Kubernetes? Khi bạn thực sự cần autoscaling theo metrics, RBAC chi tiết, hay GitOps workflow phức tạp. Trước ngưỡng đó, Swarm đủ dùng — và đơn giản hơn nhiều.
