Giới thiệu
Như một người lãnh đạo DevOps, bạn có thể đã chứng kiến sự hoảng loạn khi dịch vụ gặp sự cố. Tin tốt là, với Docker, Nginx và quy trình làm việc blue-green có kỷ luật, bạn có thể cập nhật mà không bao giờ làm gián đoạn trải nghiệm của người dùng. Bài hướng dẫn này sẽ dẫn bạn qua một thiết lập thực tế, từ đầu đến cuối, có thể tích hợp vào bất kỳ quy trình CI/CD nào.
Các yêu cầu cần có
- Docker Engine ≥ 20.10 trên máy chủ xây dựng và sản xuất của bạn
- Docker Compose để kiểm tra cục bộ
- Nginx hoạt động như một reverse proxy trước các container của bạn
- Một repository Git kích hoạt hệ thống CI của bạn (GitHub Actions, GitLab CI, v.v.)
- Kiến thức cơ bản về Bash và YAML
Nếu bất kỳ điều gì trong số này còn thiếu, hãy khởi động chúng trước; các bước dưới đây giả định rằng chúng đã có sẵn.
1. Cấu trúc Repository cho Blue-Green
Tạo một bố cục thư mục tách biệt hai môi trường:
my-app/
├─ docker-compose.yml # dịch vụ chung (db, redis, …)
├─ nginx/
│ └─ nginx.conf # cấu hình proxy với các nhóm upstream
├─ blue/
│ └─ Dockerfile # hình ảnh cho phiên bản "blue"
├─ green/
│ └─ Dockerfile # hình ảnh cho phiên bản "green"
└─ .github/workflows/
└─ ci.yml # định nghĩa quy trình CI
Cả blue và green có thể có Dockerfile giống nhau; sự khác biệt duy nhất là thẻ bạn đẩy lên registry của mình (ví dụ: my-app:blue-v123). Việc giữ chúng trong các thư mục riêng giúp dễ dàng tham chiếu đến ngữ cảnh xây dựng đúng trong CI.
2. Cấu hình Nginx cho Upstream Động
Sự kỳ diệu nằm trong khối upstream của Nginx. Bằng cách sử dụng resolver và biến, bạn có thể hoán đổi upstream đang hoạt động mà không cần tải lại Nginx.
http {
upstream app_upstream {
# Biến $upstream_name sẽ được thiết lập bởi một script kiểm tra sức khỏe
server unix:/var/run/${upstream_name}.sock;
}
server {
listen 80;
location / {
proxy_pass http://app_upstream;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
Khi bạn muốn nâng cấp green lên hoạt động, chỉ cần cập nhật symlink /var/run/green.sock để trỏ đến socket của container mới và thay đổi biến $upstream_name thông qua lệnh nginx -s reload hoặc, tốt hơn, một lệnh zero-downtime nginx -s reload chỉ hoán đổi tham chiếu upstream.
3. Quy trình CI/CD – Nhịp đập chính
Dưới đây là một quy trình GitHub Actions tối thiểu xây dựng cả hai hình ảnh, đẩy chúng lên Docker Hub và sau đó kích hoạt một script nâng cấp trên máy chủ sản xuất.
name: CI
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Cài đặt Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Đăng nhập vào Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DH_USERNAME }}
password: ${{ secrets.DH_PASSWORD }}
- name: Xây dựng & đẩy hình ảnh blue
run: |
docker build -t myorg/my-app:blue-${{ github.sha }} ./blue
docker push myorg/my-app:blue-${{ github.sha }}
- name: Xây dựng & đẩy hình ảnh green
run: |
docker build -t myorg/my-app:green-${{ github.sha }} ./green
docker push myorg/my-app:green-${{ github.sha }}
- name: Triển khai green (không gián đoạn)
env:
SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
run: |
ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no user@prod-host \
"./deploy_green.sh ${{ github.sha }}"
Script deploy_green.sh là nơi hoán đổi diễn ra. Hãy giữ nó idempotent và an toàn.
4. Script nâng cấp (deploy_green.sh)
#!/usr/bin/env bash
set -euo pipefail
SHA=$1
APP_NAME="my-app"
GREEN_TAG="green-${SHA}"
# Kéo hình ảnh mới
docker pull myorg/${APP_NAME}:${GREEN_TAG}
# Dừng bất kỳ container green cũ nào
docker rm -f ${APP_NAME}_green || true
# Bắt đầu container green mới liên kết với một Unix socket
docker run -d \
--name ${APP_NAME}_green \
-v /var/run/${APP_NAME}_green.sock:/tmp/app.sock \
myorg/${APP_NAME}:${GREEN_TAG}
# Kiểm tra điểm sức khỏe
if curl -sSf http://localhost:8080/health; then
echo "✅ Container green khỏe mạnh"
else
echo "❌ Kiểm tra sức khỏe thất bại, hủy bỏ"
exit 1
fi
# Hoán đổi upstream Nginx bằng cách cập nhật symlink
ln -sffn /var/run/${APP_NAME}_green.sock /var/run/${APP_NAME}.sock
# Tải lại Nginx (không gián đoạn)
nginx -s reload
# Tùy chọn: dọn dẹp container blue cũ
docker rm -f ${APP_NAME}_blue || true
echo "🚀 Triển khai ${GREEN_TAG} hoàn tất"
Điểm chính:
- Kiểm tra sức khỏe trước khi hoán đổi ngăn chặn các bản phát hành kém đến với lưu lượng truy cập.
- Hoán đổi symlink là nguyên tử trên Unix, đảm bảo chuyển đổi ngay lập tức.
nginx -s reloadchỉ tải lại cấu hình, không phải các tiến trình worker, do đó các kết nối hiện tại vẫn sống.
5. Quan sát & Ghi log
Các triển khai không gián đoạn chỉ tốt như mức độ hiển thị bạn có. Kết nối những điều sau vào ngăn xếp của bạn:
- Prometheus quét
/metricstừ cả hai container. Gán các chỉ số vớienvironment=blue|green. - Biểu đồ Grafana cho thấy độ trễ yêu cầu theo phiên bản, cho phép bạn phát hiện sự thoái lui ngay lập tức.
- ELK stack (hoặc Loki) thu thập log Docker. Sử dụng định dạng log JSON nhất quán để bạn có thể lọc theo
container_name.
Một lệnh nhanh để theo dõi log cho việc xử lý sự cố:
docker logs -f my-app_green --tail 100
6. Chiến lược Rút lui
Nếu phiên bản green mới cho thấy sự gia tăng tỷ lệ lỗi, hãy quay lại với một lệnh duy nhất:
# Chuyển lại socket về blue
ln -sffn /var/run/${APP_NAME}_blue.sock /var/run/${APP_NAME}.sock
nginx -s reload
Bởi vì container blue vẫn đang chạy (bạn không docker rm -f nó cho đến khi kiểm tra sức khỏe của green vượt qua), việc hoán đổi là tức thì. Chỉ sau một khoảng thời gian thành công, bạn nên dọn dẹp phiên bản cũ.
7. Bonus: Blue-Green với Kubernetes (Tùy chọn)
Nếu nhóm của bạn chuyển sang K8s, các nguyên tắc tương tự áp dụng sử dụng Deployments và Services với strategy.type: RollingUpdate được thiết lập thành maxSurge: 0 và maxUnavailable: 0. Tuy nhiên, phương pháp Docker-Nginx vẫn nhẹ nhàng cho các sản phẩm SaaS nhỏ và vừa.
Kết luận
Các triển khai không gián đoạn không còn là lý tưởng xa vời; chúng là một mô hình thực tế mà bạn có thể thực hiện ngay hôm nay với Docker, Nginx và một quy trình CI kỷ luật. Bằng cách tách biệt các bản dựng blue và green, sử dụng hoán đổi socket nguyên tử và kết hợp kiểm tra sức khỏe với khả năng quan sát, bạn bảo vệ người dùng trong khi vẫn di chuyển nhanh.
Nếu bạn cần hỗ trợ trong việc triển khai điều này, đội ngũ tại ramerlabs.com có thể giúp bạn.