Nỗi ám ảnh mang tên “502 Bad Gateway” mỗi khi deploy
Anh em làm Dev chắc không lạ gì cảm giác tim đập chân run khi gõ lệnh deploy lên production vào lúc 2 giờ sáng. Với cách deploy truyền thống, việc dừng container cũ để khởi động bản mới thường tạo ra một khoảng trống “downtime”. Dù chỉ mất 30 giây, nhưng nếu hệ thống đang có 100 người dùng thanh toán cùng lúc, lỗi Connection Refused sẽ biến thành thảm họa trải nghiệm. Với các dự án thực tế, sự gián đoạn này là dấu hiệu của sự thiếu chuyên nghiệp.
Blue-Green Deployment chính là liều thuốc giải. Hãy tưởng tượng thay vì gỡ biển hiệu cửa hàng cũ để treo cái mới (làm khách đứng ngoài chờ), bạn xây hẳn một cửa hàng mới y hệt ngay sát vách. Khi mọi thứ bên trong đã sẵn sàng, bạn chỉ việc mời dòng khách chuyển sang cửa hàng mới. Khách hàng vẫn vào mua sắm bình thường, không hề hay biết có sự thay đổi lớn vừa diễn ra.
Dù Docker Compose không có sẵn các tính năng điều phối xịn như Kubernetes, chúng ta vẫn hoàn toàn tự tay thiết lập được một hệ thống Zero-Downtime cực kỳ ổn định nhờ Nginx làm Reverse Proxy.
Chuẩn bị cấu trúc thư mục
Trước tiên, server của bạn cần có sẵn Docker và Docker Compose. Để quản lý không bị rối, mình thường tổ chức thư mục theo cấu trúc sau:
/my-app/
├── docker-compose.yml
├── nginx/
│ └── default.conf
└── app/
└── (mã nguồn ứng dụng)
Mấu chốt của chiến lược này là duy trì song song hai môi trường: Blue (phiên bản đang chạy ổn định) và Green (phiên bản mới nhất sắp lên sóng).
Cấu hình Docker Compose và Nginx
1. Thiết lập file docker-compose.yml
Chúng ta sẽ định nghĩa hai service gần như sinh đôi, chỉ khác nhau về tên gọi. Lưu ý quan trọng: không map trực tiếp port của ứng dụng ra ngoài host để tránh xung đột cổng. Mọi traffic sẽ phải đi qua “cổng bảo vệ” Nginx.
version: '3.8'
services:
app_blue:
image: my-app:v1
networks:
- app_network
app_green:
image: my-app:v2
networks:
- app_network
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app_blue
- app_green
networks:
- app_network
networks:
app_network:
driver: bridge
2. Dùng Nginx để điều phối dòng traffic
File default.conf đóng vai trò như một người gác cổng thông minh. Thay vì trỏ cứng vào một container, mình sẽ dùng block upstream để dễ dàng đảo chiều traffic khi cần.
upstream my_app {
server app_blue:8080; # Traffic hiện tại đang vào Blue
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://my_app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Các bước “lên sàn” thực tế
Mỗi khi có code mới, quy trình diễn ra cực kỳ mượt mà:
- Build Docker image mới nhất cho bản Green.
- Khởi động container Green (lúc này khách vẫn đang dùng bản Blue cũ).
- Dùng
curlkiểm tra xem bản Green đã sẵn sàng chưa (Health check). - Sửa file Nginx: thay
app_blue:8080bằngapp_green:8080. - Ra lệnh cho Nginx reload:
docker exec nginx nginx -s reload.
Quá trình reload của Nginx diễn ra trong tích tắc, các kết nối cũ vẫn được xử lý nốt trong khi khách mới sẽ được dẫn thẳng vào bản Green. Nếu bản Green gặp lỗi bất ngờ? Chỉ cần một thao tác đổi ngược lại cấu hình Nginx và reload là xong. Cực kỳ an toàn.
Khi cần debug phản hồi JSON từ container mới để xem dữ liệu trả về có đúng chuẩn không, mình hay dùng formatter tại toolcraft.app/vi/tools/developer/json-formatter. Nó nhanh và nhẹ hơn việc cài extension hay mở mấy IDE nặng nề.
Kiểm soát và Tối ưu
Đừng vội tắt bản Blue ngay sau khi switch traffic. Hãy dành khoảng 5-10 phút quan sát log qua lệnh docker logs -f app_green. Nếu lượng Request tăng đều và không xuất hiện lỗi 5xx, lúc đó mới nên dọn dẹp container cũ.
Một mẹo nhỏ cho anh em: hãy tạo một endpoint /health trả về trạng thái của Database và Redis. Trước khi sửa cấu hình Nginx, hãy chạy lệnh này để chắc chắn mọi thứ đã “warm up”:
docker exec nginx curl http://app_green:8080/health
Nếu nhận về HTTP 200, bạn có thể tự tin nhấn nút switch. Cách làm này tuy thủ công nhưng lại cực kỳ ổn định cho các dự án vừa và nhỏ, tránh việc phải setup những hệ thống CI/CD cồng kềnh gây lãng phí tài nguyên server.
Đôi khi, sự đơn giản chính là chìa khóa của sự ổn định. Docker Compose phối hợp nhịp nhàng với Nginx là quá đủ để anh em có một hệ thống Zero-Downtime chuẩn chỉ mà không cần phải là chuyên gia DevOps gạo cội.

