Giới thiệu
Là một lãnh đạo DevOps, bạn biết rằng mỗi giây ngừng hoạt động đều có thể chuyển thành doanh thu bị mất, người dùng thất vọng và danh tiếng thương hiệu bị tổn hại. Các kiến trúc micro-service hiện đại cho phép cập nhật mà không cần đưa toàn bộ hệ thống offline, nhưng quy trình này vẫn đòi hỏi một cách tiếp cận có kỷ luật. Danh sách kiểm tra này sẽ hướng dẫn bạn quy trình triển khai không gián đoạn thực tế, từ đầu đến cuối, sử dụng Docker containers phía sau một reverse proxy Nginx. Nó được viết dành cho các đội ngũ đã có sẵn CI/CD pipeline và muốn thắt chặt mạng lưới an toàn quanh các bản phát hành sản xuất.
1. Chuẩn bị Docker Image có thể tái tạo
- Ghi lại base images – Sử dụng tag cụ thể (ví dụ:
python:3.11-slim) thay vìlatest. - Multi-stage builds – Loại bỏ các phụ thuộc thời gian xây dựng để giữ cho image runtime gọn gàng.
- Health checks – Khai báo một lệnh
HEALTHCHECKđể Docker có thể báo cáo tình trạng container tới orchestrator.
dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci && npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm ci --production
HEALTHCHECK --interval=30s --timeout=5s \
CMD curl -f http://localhost:3000/health || exit 1
Lý do tại sao điều này quan trọng: Một image có thể điều chỉnh giúp loại bỏ lỗi “nó hoạt động trên máy của tôi”, và các health checks cung cấp cho Nginx một cách đáng tin cậy để định tuyến lưu lượng chỉ tới các container khỏe mạnh.
2. Phiên bản cho các bản phát hành
- Tag phiên bản Semantic – Gán tag cho Docker images với định dạng
vMAJOR.MINOR.PATCH(ví dụ:myapp:1.4.2). - Bản phát hành không thể thay đổi – Không bao giờ ghi đè một tag đã tồn tại; đẩy một image mới cho mỗi thay đổi.
- Thăng cấp registry – Chỉ thăng cấp images từ kho
staginglênproductionsau khi các bài kiểm tra tự động vượt qua.
bash
# Xây dựng và đẩy một image có phiên bản
docker build -t registry.example.com/myapp:1.4.2 .
docker push registry.example.com/myapp:1.4.2
Việc phiên bản hóa cho bạn một con đường quay lại rõ ràng và giúp dễ dàng hơn trong việc kiểm tra lịch sử.
3. Kiến trúc Blue-Green với Nginx
Mô hình blue-green cổ điển chạy hai môi trường giống hệt nhau (blue = hiện tại, green = tiếp theo). Nginx đóng vai trò là công tắc lưu lượng.
3.1 Cấu hình Upstream Nginx
nginx
upstream myapp {
# Blue (current) pool
server 10.0.1.10:3000 max_fails=3 fail_timeout=30s;
server 10.0.1.11:3000 max_fails=3 fail_timeout=30s;
# Green (new) pool – bình luận ra cho đến khi sẵn sàng
# server 10.0.2.10:3000 max_fails=3 fail_timeout=30s;
# server 10.0.2.11:3000 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
location / {
proxy_pass http://myapp;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
3.2 Chuyển đổi lưu lượng
- Triển khai image Docker mới đến các máy chủ green.
- Xác minh các endpoint tình trạng (
/health) trả về200. - Bỏ bình luận các máy chủ green trong block upstream và tải lại Nginx:
bash
sudo nginx -s reload
- Khi lưu lượng chuyển tiếp một cách suôn sẻ, hủy hoạt động các máy chủ blue hoặc giữ chúng như một phương án dự phòng.
4. Tích hợp CI/CD Pipeline
Một pipeline đáng tin cậy tự động hóa các bước trên và ngăn ngừa lỗi do con người.
yaml
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
tags:
- 'v*.*.*'
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Log in to registry
uses: docker/login-action@v2
with:
registry: registry.example.com
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASS }}
- name: Build & push image
run: |
IMAGE=registry.example.com/myapp:${{ github.ref_name }}
docker build -t $IMAGE .
docker push $IMAGE
- name: Deploy green fleet
run: |
ssh devops@green-host 'docker pull $IMAGE && docker run -d --name myapp $IMAGE'
- name: Run health checks
run: |
curl -f http://green-host:3000/health
- name: Switch Nginx upstream
run: |
ssh devops@nginx-host 'sed -i "s/# server 10.0.2.10/server 10.0.2.10/" /etc/nginx/conf.d/myapp.conf && sudo nginx -s reload'
Quy trình này đảm bảo:
- Bản phát hành theo tag (không có việc tăng phiên bản thủ công).
- Xác thực tình trạng tự động trước khi chuyển đổi lưu lượng.
- Tải lại Nginx nguyên tử, đây là một thao tác không gián đoạn.
5. Quan sát và Ghi nhật ký
Ngay cả với các health checks, bạn cần cái nhìn thời gian thực.
- Ghi nhật ký có cấu trúc – Xuất ra JSON tới
stdout; Docker tự động ghi nhận chúng. - Metrics – Xuất các metrics Prometheus từ ứng dụng của bạn (
/metrics). - Tracing – Sử dụng OpenTelemetry để truyền tải ID yêu cầu qua Nginx (
proxy_set_header X-Trace-ID $request_id). - Cảnh báo – Thiết lập cảnh báo trên:
- Trạng thái container không khỏe mạnh.
- Tăng đột biến 5xx của Nginx.
- Độ trễ > 200 ms cho endpoint
/health.
6. Chiến lược Quay lại
Không bao giờ giả định rằng một bản phát hành sẽ thành công.
- Giữ pool blue chạy cho đến khi pool green đã xử lý ít nhất một yêu cầu thành công.
- Nếu bất kỳ health check nào thất bại sau khi chuyển đổi, hãy bình luận các máy chủ green, tải lại Nginx và điều tra.
- Tùy chọn, sử dụng cờ
--rollbackcủa Docker với Swarm hoặc lệnhrollbackcủa Helm cho Kubernetes.
7. Tăng cường An ninh
- Containers với quyền tối thiểu – Chạy dưới quyền không phải root (
USER appuser). - Kết thúc TLS – Chuyển giao TLS cho Nginx và áp dụng cipher mạnh.
- Tiêm bí mật – Sử dụng Docker secrets hoặc một vault; không bao giờ nhúng khóa vào images.
- CSP headers – Thêm
Content-Security-Policytrong Nginx để giảm thiểu XSS.
nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.jsdelivr.net";
8. Danh sách kiểm tra sau khi triển khai
- [ ] Xác minh
/healthtrả về200trên tất cả các nút green. - [ ] Xác nhận nhật ký Nginx không hiển thị phản hồi 5xx nào.
- [ ] Kiểm tra bảng điều khiển Prometheus về tỷ lệ lỗi và độ trễ.
- [ ] Đảm bảo các bí mật vẫn được mã hóa khi nghỉ.
- [ ] Tài liệu tag image mới trong ghi chú phát hành.
Kết luận
Các bản phát hành không gián đoạn không chỉ là phép thuật mà còn là các bước có kỷ luật có thể lặp lại. Bằng cách phiên bản hóa các Docker images, tận dụng việc chuyển đổi upstream của Nginx, và kết nối các health checks vào CI/CD pipeline của bạn, bạn có thể triển khai các tính năng nhiều lần trong một ngày mà không bao giờ làm tổn thương người dùng của mình. Hãy nhớ giữ cho khả năng quan sát là trung tâm và luôn có một kế hoạch quay lại sẵn sàng.
Nếu bạn cần hỗ trợ trong việc triển khai này, đội ngũ tại https://ramerlabs.com có thể giúp.