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.

Nội dung bài viết
- 1.Màn hình maintenance
- 2.Vấn đề của phương pháp release cũ
- 2.1 Những điểm yếu
- 2.2 Những gì chúng ta cần
- 3.Giới thiệu Blue-Green Deployment
- 4.Cách triển khai Blue-Green Deployment
- Bước 1: Tạo hai upstream và một switch
- Bước 2: Viết switch thành một script
- Bước 3: Deploy lên VM đang idle
- Bước 4: Test Green
- Bước 5: Chuyển traffic
- Bước 6: Rollback nếu cần
- Blue-green deployment giải quyết được gì
- 5.Một số lưu ý khi triển khai
- 6.Các phương pháp tương tự: Rolling và Canary deployment
- 6.3 Phương pháp phù hợp với dự án của bạn
- 7.Kết luận
- Nguồn tham khảo
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:
- Thông báo với các đối tác và người dùng về lịch release.
- 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ì.
- 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.
- 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.
- 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 đó đơ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.

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.



Khi đó, một phiên release sẽ trông như sau:
- Deploy v2 lên Green trong khi Blue vẫn phục vụ người dùng.
- Test Green trực tiếp qua URL riêng của nó.
- Chuyển router để toàn bộ traffic đi vào Green.
- Giữ Blue chạy như một bản rollback tức thời.
- 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:
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.


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.

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/healthChạ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 greenTừ 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 blueDo Blue vẫn luôn chạy nên nó có thể nhận traffic ngay lập tức.

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ũ:

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:
- 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.
- Release v2 và kiểm tra sự ổn định.
- 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.

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.


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ụ:
- 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ọ.
- 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
- 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
- Netflix TechBlog – Global Continuous Delivery with Spinnaker (Netflix dùng blue-green (red/black) trong Spinnaker)
- Spinnaker Summit – How (and Why) Waze and Netflix Use Spinnaker to Breeze Through Deployments (Waze dùng blue/green trong pipeline)
- Kubernetes Documentation – Deployments (Rolling Update là chiến lược mặc định)
- Google Cloud Documentation – Apply new VM configurations in a MIG (rolling update cho managed instance group)
- Google Cloud Blog – Introducing Kayenta: An open automated canary analysis tool from Google and Netflix (canary analysis tại Netflix và Google)
- Engineering at Meta – Rapid release at massive scale (quy trình release theo tầng của Meta)
- nginx documentation – Controlling nginx (cơ chế graceful reload)
- Martin Fowler – Parallel Change (pattern expand/contract)
- Martin Fowler – BlueGreenDeployment (khái niệm blue-green deployment)
Đừ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á.


