VITALIFY.ASIA logo

Giảm thiểu downtime khi release với Blue-Green Deployment

Blue-Green Deployment vận hành song song hai môi trường để triển khai và kiểm thử phiên bản mới trước khi chuyển traffic. Bài viết hướng dẫn Nginx, Compute Engine, Cloud Build, rollback nhanh, migration database, session, background worker, chi phí và so sánh với Rolling, Canary.

Dat Chu Tien
Giảm thiểu downtime khi release với Blue-Green Deployment
Nội dung bài viết

Phương pháp release truyền thống với mode maintenance (màn hình bảo trì) gây downtime ở mọi phiên release, đẩy lịch release ra ngoài giờ, và khi có lỗi thì rollback đồng nghĩa với việc chạy lại quy trình.

Bài viết giới thiệu blue-green deployment: chạy song song hai môi trường, deploy và test phiên bản mới trên môi trường đang idle, rồi chuyển traffic chỉ bằng một lệnh. Bạn sẽ thấy:

  • Vì sao cách dùng màn hình bảo trì không còn phù hợp
  • Blue-green giải quyết từng vấn đề đó như thế nào
  • Cách triển khai với Nginx reverse proxy trên Compute Engine và Cloud Build
  • Một số điểm cần lưu ý: database migration, background consumer, session, chi phí

1.Màn hình maintenance

Khi mới bắt đầu công việc kỹ sư phần mềm, tôi được tham gia một dự án xây dựng một webtool rất mới lạ hỗ trợ các nhà môi giới bất động sản với tính năng dự báo những bất động sản có nhu cầu cao bằng machine learning model. Khi đó, mỗi lần release phiên bản mới, team chúng tôi sử dụng một quy trình cũ có nhiều bất cập:

  1. Thông báo với các đối tác và người dùng về lịch release.
  2. Engineer phụ trách phiên release cập nhật flag isMaintenance = true trong database, khi đó app sẽ hiển thị màn hình bảo trì.
  3. Engineer push vào nhánh release, Cloud Build chạy deploy pipeline, engineer tiếp tục theo dõi quá trình deploy.
  4. Khi pipeline chạy thành công, team dùng một account có quyền truy cập trong lúc bảo trì để kiểm tra tính năng.
  5. Khi mọi checklist test hoàn thành, engineer cập nhật lại flag isMaintenance = false để người dùng có thể tiếp tục sử dụng.
Quy trình release cũ
Quy trình release với maintenance mode
Màn hình bảo trì người dùng nhìn thấy
Màn hình bảo trì người dùng nhìn thấy

Quy trình đó đơn giản, hoạt động tốt hầu hết thời gian. Nhưng không một engineer nào trong team có thể đảm bảo mọi phiên release trong tương lai sẽ luôn luôn rơi vào “happy case” như vậy.

2.Vấn đề của phương pháp release cũ

2.1 Những điểm yếu

  • Mọi phiên release đều là downtime. Màn hình bảo trì chặn người dùng trong suốt phiên release, cho dù đó là một tính năng mới hay chỉ là một thay đổi rất nhỏ.
  • Lịch release bị đẩy sang ngoài giờ làm việc. Để hạn chế ảnh hưởng của downtime, các bản cập nhật được gom lại và release vào một khung giờ cố định, đồng nghĩa với việc mỗi phiên release lớn hơn và rủi ro cao hơn. Hơn nữa, các đối tác của team làm việc ở nhiều múi giờ khác nhau nên việc phối hợp cũng kém thuận tiện.
  • Rollback là phải chạy lại toàn bộ quy trình. Khi version mới gặp lỗi, không có cách nào để hoàn tác ngay. Team phải giữ nguyên màn hình bảo trì, revert code trên nhánh release rồi chạy lại Cloud Build pipeline. Mỗi phiên release thất bại đồng nghĩa với việc người dùng phải chờ lâu hơn.
Khi release thất bại
Khi release thất bại

2.2 Những gì chúng ta cần

Từ những vấn đề trên, danh sách những gì chúng tôi mong muốn cải thiện gồm:

  • Zero downtime. Người dùng không bị chặn bởi trang bảo trì trong khi team release.
  • Test trên môi trường thật trước khi người dùng cuối sử dụng.
  • Rollback nhanh nhất có thể, không phải chạy lại toàn bộ pipeline.

3.Giới thiệu Blue-Green Deployment

Với cách hệ thống ví dụ trên được triển khai và các yêu cầu cần đạt được, Blue-green deployment chính là một trong những giải pháp tốt nhất.

Khi release phiên bản mới, thay vì thay thế trực tiếp phiên bản đang chạy, bạn duy trì hai môi trường riêng biệt:

Blue là phiên bản hiện tại mà người dùng cuối đang sử dụng.
Green là phiên bản mới, chưa có người dùng.

Một router (load balancer, reverse proxy, …) đứng phía trước cả hai và quyết định request sẽ đi đâu. Router chính là cái “switch” điều hướng traffic.

Trước khi chuyển: Blue đang live, Green đang được test
Trước khi chuyển: Blue đang live, Green đang được test
Sau khi chuyển: Green live, Blue standby
Sau khi chuyển: Green live, Blue standby
Rollback: traffic quay về Blue
Rollback: traffic quay về Blue

Khi đó, một phiên release sẽ trông như sau:

  1. Deploy v2 lên Green trong khi Blue vẫn phục vụ người dùng.
  2. Test Green trực tiếp qua URL riêng của nó.
  3. Chuyển router để toàn bộ traffic đi vào Green.
  4. Giữ Blue chạy như một bản rollback tức thời.
  5. Nếu có sự cố do phiên bản mới gây ra, chỉ cần switch lại ở router. Nếu ổn định, Blue sẽ trở thành môi trường nhận bản release tiếp theo.

So sánh kết quả với danh sách mong muốn bên trên:

Thứ team cần

Blue-green đáp ứng thế nào

Không downtime

Green đã chạy hoàn chỉnh trước khi có người dùng nào vào

Test trước khi người dùng thấy

Green có địa chỉ riêng để test trực tiếp

Rollback trong vài giây

Blue vẫn đang chạy, chỉ cần chuyển traffic về Blue

4.Cách triển khai Blue-Green Deployment

Ý tưởng này áp dụng được trên bất kỳ hệ thống nào có router đứng trước app. Ở dự án mà tôi đã đề cập ở đầu bài viết này, app chạy trên các VM Compute Engine phía sau một reverse proxy Nginx:

  • Blue và Green là hai VM (app-blue và app-green), mỗi VM chạy app trên cổng 8080.
  • Router là Nginx trên VM proxy. Nó vốn đã đứng trước app, nên nó trở thành cái switch của team.
  • Switch là một file cấu hình Nginx nhỏ, quy định VM nào nhận traffic live. Đổi file đó và reload Nginx chính là thao tác chuyển traffic.
Hạ tầng: Nginx proxy và hai VM
Hạ tầng: Nginx proxy và hai VM
Switch chỉ là hai file cấu hình
Switch chỉ là hai file cấu hình

Bước 1: Tạo hai upstream và một switch

Trên VM proxy, khai báo cả hai môi trường và hai lối vào: một lối public đi theo switch, và một lối test nội bộ luôn trỏ vào màu đang idle.

# /etc/nginx/conf.d/app.conf
upstream app_blue  { server 10.148.0.10:8080; }  # app-blue
upstream app_green { server 10.148.0.11:8080; }  # app-green
# Public traffic: follows the switch
server {
    listen 80;
    server_name api.example.com;
    location / {
        include /etc/nginx/live-upstream.conf;
    }
}
# Internal test entrance: always points at the idle color
server {
    listen 8081;
    location / {
        include /etc/nginx/idle-upstream.conf;
    }
}

Lưu ý quan trọng: cổng 8081 chỉ dành cho team. Sử dụng VPC firewall rule để chỉ IP nội bộ (hoặc CI) truy cập được.

# /etc/nginx/live-upstream.conf
proxy_pass http://app_blue;
# /etc/nginx/idle-upstream.conf
proxy_pass http://app_green;

Bước 2: Viết switch thành một script

Đưa logic chuyển traffic vào một script nhỏ trên VM proxy:

#!/usr/bin/env bash
# /usr/local/bin/switch-live.sh — usage: switch-live.sh blue|green
set -euo pipefail
TARGET="${1:?usage: switch-live.sh blue|green}"
case "$TARGET" in
  blue)  IDLE=green ;;
  green) IDLE=blue  ;;
  *) echo "target must be blue or green" >&2; exit 1 ;;
esac
echo "proxy_pass http://app_${TARGET};" | sudo tee /etc/nginx/live-upstream.conf >/dev/null
echo "proxy_pass http://app_${IDLE};"   | sudo tee /etc/nginx/idle-upstream.conf >/dev/null
# Validate first, then reload gracefully
sudo nginx -t && sudo nginx -s reload
echo "Live: ${TARGET} | Idle: ${IDLE}"
  • nginx -t để kiểm tra cấu hình trước khi thay đổi. Nếu thất bại, lệnh reload sẽ không chạy và cấu hình cũ vẫn tiếp tục chạy.
  • nginx -s reload là graceful reload. Các worker process mới nhận cấu hình mới, còn các worker cũ xử lý nốt những request đang dở. Không có request nào bị mất trong khi switch.
Graceful reload: worker cũ xử lý nốt, worker mới nhận request mới
Graceful reload: worker cũ xử lý nốt, worker mới nhận request mới

Bước 3: Deploy lên VM đang idle

Cloud Build deploy lên VM đang idle, trong khi VM live vẫn phục vụ người dùng

steps:
  - name: gcr.io/cloud-builders/docker
    args: ["build", "-t", "$_IMAGE", "."]
  - name: gcr.io/cloud-builders/docker
    args: ["push", "$_IMAGE"]
  - name: gcr.io/google.com/cloudsdktool/cloud-sdk
    entrypoint: bash
    args:
      - -c
      - |
        gcloud compute ssh app-${_TARGET} \
          --zone=asia-southeast1-b \
          --tunnel-through-iap \
          --command="docker pull $_IMAGE && (docker rm -f app || true) && docker run -d --name app --restart=always -p 8080:8080 $_IMAGE"

Ở đây _TARGET là màu đang idle (green trong lần release này).

Bước 4: Test Green

Gọi vào URL test nội bộ, nơi đang trỏ vào Green:

curl -i http://<proxy-internal-ip>:8081/health

Chạy smoke test, kiểm tra thủ công nhanh, hoặc một bộ test tự động vào đó. Đây chính là bước mà cách làm với trang bảo trì chưa bao giờ có: chạy thử phiên bản mới trên VM thật, phía sau proxy thật, trước khi bất kỳ người dùng nào nhìn thấy nó.

Bước 5: Chuyển traffic

sudo /usr/local/bin/switch-live.sh green

Từ giờ mọi request mới sẽ đi vào app-green, và app-blue trở thành phía idle. Và từ lần release tiếp theo, hai môi trường này sẽ đổi vai trò cho nhau.

Bước 6: Rollback nếu cần

sudo /usr/local/bin/switch-live.sh blue

Do Blue vẫn luôn chạy nên nó có thể nhận traffic ngay lập tức.

Quy trình release mới
Quy trình release mới

Blue-green deployment giải quyết được gì

Giờ hãy quay lại từng vấn đề của cách làm cũ:

Vấn đề cũ (trang bảo trì)

Với blue-green

Người dùng bị chặn suốt mỗi lần Cloud Build chạy

Green được build và deploy ở phía sau trong khi Blue vẫn phục vụ

Release bị đẩy sang tối muộn hoặc cuối tuần

Việc chuyển diễn ra tức thì, nên có thể release ngay trong giờ làm việc

Rollback = chạy lại toàn bộ pipeline, trang bảo trì vẫn treo

Trỏ traffic về Blue trong vài giây

Flag isMaintenance trong DB

Không cần flag; router quyết định traffic đi đâu

Người dùng thật là người test đầu tiên

Smoke test Green qua URL riêng trước khi chuyển

Trước và sau: thời gian người dùng bị chặn
Trước và sau: thời gian người dùng bị chặn

5.Một số lưu ý khi triển khai

5.1 Database migration

Blue và Green thường dùng chung một database, và trong một khoảng thời gian cả hai phiên bản cùng chạy trên đó. Một migration xoá hoặc đổi tên cột sẽ làm hỏng Blue, và kéo theo hỏng luôn đường rollback của bạn. Cách giải quyết là pattern expand/contract:

  1. Expand: thêm cột hoặc bảng mới theo cách tương thích ngược, để cả v1 và v2 đều chạy được.
  2. Release v2 và kiểm tra sự ổn định.
  3. Contract: xoá các cột cũ ở một lần release sau, khi không còn phiên bản nào đang chạy cần đến chúng.
Migration theo pattern expand/contract
Migration theo pattern expand/contract

5.2 Background consumer

Nginx chỉ điều khiển traffic HTTP. Nếu app trên mỗi VM còn chạy Pub/Sub pull subscriber, cron job hay các worker khác, VM idle vẫn tiếp tục làm những việc đó, có khi bằng code chưa được test, và cả hai VM cùng pull từ một subscription. Hãy chỉ bật worker trên VM đang live (ví dụ bật chúng như một phần của script chuyển), hoặc đảm bảo cả hai phiên bản đều xử lý an toàn cùng một loại message.

Vấn đề: VM idle vẫn pull message
Vấn đề: VM idle vẫn pull message
Cách xử lý: chỉ VM live pull message
Cách xử lý: chỉ VM live pull message

5.3 Session và state

Nếu session của người dùng được lưu trong bộ nhớ của app, việc chuyển môi trường sẽ khiến họ bị đăng xuất. Hãy lưu state ở một nơi dùng chung (database, Redis, Firestore) để phiên bản nào cũng phục vụ được bất kỳ người dùng nào.

5.4 Kết nối dài hạn (persistent connection)

Reload graceful không cắt các kết nối đang mở: WebSocket và gRPC stream vẫn nằm trên các worker Nginx cũ, vẫn giao tiếp với Blue, cho đến khi chúng đóng lại. Hãy tính đến việc chúng rút dần, cân nhắc đặt worker_shutdown_timeout để chúng không treo mãi, và đừng tắt Blue ngay lập tức sau khi chuyển.

5.5 Chi phí

Vì bạn phải chạy song song hai môi trường nên chi phí có thể sẽ gấp đôi. Bạn có thể tắt VM idle giữa các lần release và chỉ bật lại khi deploy, tuy nhiên điều đó cũng đồng nghĩa bạn mất khả năng rollback tức thì. Theo kinh nghiệm của tôi, bạn nên giữ VM idle một thời gian sau khi chuyển traffic để đảm bảo khả năng rollback tức thì trong giai đoạn rủi ro nhất của phiên release. Khi phiên bản mới đã ổn định, bạn có thể tắt VM idle để tiết kiệm chi phí và chỉ bật lại trước lần deploy tiếp theo.

5.6 Khi nào blue-green không phải lựa chọn phù hợp?

  • Hệ thống thay đổi schema database thường xuyên và khó giữ tương thích ngược.
  • Ngân sách không thể duy trì hai môi trường.
  • Ứng dụng phụ thuộc nhiều vào state trong bộ nhớ hoặc kết nối dài hạn.
  • Cần kiểm chứng phiên bản mới với traffic thật trước khi mở cho tất cả người dùng. Lúc này canary phù hợp hơn.

Các ví dụ thực tế:

  • Netflix dùng blue-green trong Spinnaker, nền tảng continuous delivery do chính họ xây dựng và open-source. Netflix gọi chiến lược này là "red/black": theo Netflix TechBlog, các team có thể deploy server group mới "using strategies like Blue-Green (or Red-Black as we call it at Netflix)".
  • Waze (thuộc Google) đưa bản release lên môi trường staging bằng chiến lược blue/green trong pipeline Spinnaker của họ.

6.Các phương pháp tương tự: Rolling và Canary deployment

Blue-green không phải cách duy nhất để release mà không cần màn hình bảo trì. Hai phương pháp thường được nhắc đến cùng với nó là rolling deployment và canary deployment.

6.1 Rolling deployment

Thay vì switch toàn bộ traffic như với Blue-green deployment, rolling deployment thay thế dần dần các instance v1 của app bằng instance v2 cho đến khi v2 thay thế toàn bộ.

  • Ưu điểm: không downtime, không cần gấp đôi chi phí hạ tầng.
  • Nhược điểm: trong lúc rollout, v1 và v2 cùng phục vụ người dùng, nên API và dữ liệu phải có tính tương thích ngược. Rollback cũng là một lần rollout các v2 thành v1 ngược lại, không tức thì như blue-green.

Ví dụ: Rolling update là chiến lược mặc định của Deployment trong Kubernetes. Trên Google Cloud, managed instance group của Compute Engine cũng hỗ trợ rolling update sẵn.

6.2 Canary deployment

Canary chỉ đưa một phần nhỏ traffic (ví dụ 1–5%) sang phiên bản mới, theo dõi các chỉ số (error rate, latency…), rồi mới tăng dần lên 100%. Nếu có bất thường, chỉ một nhóm nhỏ người dùng bị ảnh hưởng.

  • Ưu điểm: phát hiện lỗi với rủi ro nhỏ nhất, dựa trên traffic thật.
  • Nhược điểm: cần hệ thống monitoring để biết khi nào an toàn để tăng traffic, và quá trình release sẽ kéo dài hơn.

Ví dụ:

  1. Netflix và Google cùng phát triển và open-source Kayenta, công cụ phân tích canary tự động. Theo Netflix, automated canary analysis là "một phần thiết yếu" trong quy trình deploy production của họ.
  2. Meta (Facebook) release theo từng tầng: đầu tiên cho nhân viên nội bộ, sau đó 2% production, rồi mới lên 100%.

6.3 Phương pháp phù hợp với dự án của bạn

Mỗi phương pháp release đều có những ưu điểm và đánh đổi riêng tùy thuộc vào quy mô và kiến trúc hệ thống:

So sánh nhanh


Blue-green

Rolling

Canary

Downtime

Không

Không

Không

Test trước khi đến tay người dùng cuối

Có (môi trường idle)

Không

Một phần (nhóm nhỏ người dùng)

Tốc độ rollback

Tức thì

Trung bình

Nhanh (chỉ cần rút phần traffic nhỏ)

Nhiều phiên bản chạy cùng lúc

Không

Có

Có

Hạ tầng bổ sung

Một môi trường thứ hai

Ít

Ít

Độ phức tạp

Trung bình

Thấp

Cao (cần monitoring)

  • Nên dùng Blue-Green khi: Cần khả năng rollback ngay lập tức, muốn kiểm tra/smoke test toàn bộ phiên bản mới trên môi trường thật trước khi public, và ứng dụng không duy trì nhiều kết nối dài hạn hoặc state trong bộ nhớ.
  • Nên dùng Rolling Deployment khi: Ứng dụng đã chạy trên Container/Kubernetes hoặc Cloud Instance Groups, muốn tiết kiệm chi phí hạ tầng và chấp nhận thời gian rollback lâu hơn một chút.
  • Nên dùng Canary Deployment khi: Hệ thống có lượng người dùng rất lớn, cần giảm thiểu rủi ro bằng cách test trên traffic thực tế của một nhóm nhỏ người dùng, và đã có hệ thống monitoring/alerting đủ mạnh để tự động đánh giá chỉ số.

7.Kết luận

Release bằng phương pháp truyền thống với lịch release và màn hình bảo trì không phải là không tốt. Nó đơn giản và hoạt động được, nhưng cái giá phải trả là trải nghiệm của chính những người dùng đã trả tiền cho sản phẩm.

Blue-green deployment có thể cải thiện điều đó. Phiên bản mới được deploy song song trên Green, được kiểm tra trên môi trường thật, rồi traffic được chuyển sang chỉ bằng một lệnh. Nếu có lỗi, một lệnh nữa là traffic quay về Blue, và người dùng không cần biết đã từng có một phiên release.

Nguồn tham khảo

Đừng để ý tưởng chỉ nằm trên giấy. Với tốc độ và sự linh hoạt đã được chứng minh qua 1.000+ dự án, chúng tôi sẽ giúp doanh nghiệp của bạn bứt phá.

Quay lại Blog
I'm Duper, ask me anything!