Blue/Green Deploy Với ALB và Rollback Tự Động

K
Kai··6 min read

Mọi deploy tới giờ là in-place: cập nhật ngay trên máy đang chạy, nên có một khoảng máy đó ngừng phục vụ. Với traffic thật, khoảng đó là downtime. Blue/green khử nó: thay vì sửa máy cũ, ta dựng một fleet mới (green) song song với fleet đang chạy (blue), kiểm tra green kỹ, rồi mới chuyển traffic qua bằng load balancer. Nếu green hỏng, traffic chưa từng rời blue — quay về tức thì. Bài này (khép Part IV) dựng ALB, chuyển deployment group sang blue/green, chạy thật, và bật rollback tự động.

💰 Chi phí

Blue/green tạm thời chạy gấp đôi số instance (blue + green cùng lúc), cộng một ALB (~0,0225 USD/giờ). Đây là bài tốn nhất Part IV — terminate sạch ngay sau khi xong (mục dọn dẹp).

Mục tiêu

Hiểu blue/green giải quyết gì, dựng ALB và chuyển deployment group sang blue/green, chạy một lần deploy thật và đọc các lifecycle event đặc thù, rồi cấu hình rollback tự động.

Load balancer đứng trước fleet

Blue/green cần một load balancer để chuyển traffic giữa hai fleet. Dựng ALB, target group, listener, rồi gắn ASG (bài 10) vào target group:

$ aws elbv2 create-load-balancer --name awscicd-alb --type application \
    --subnets subnet-aaa subnet-bbb --security-groups <sg-http>
$ aws elbv2 create-target-group --name awscicd-tg --protocol HTTP --port 80 \
    --vpc-id <vpc> --health-check-path / --target-type instance
$ aws elbv2 create-listener --load-balancer-arn <alb> --protocol HTTP --port 80 \
    --default-actions Type=forward,TargetGroupArn=<tg>
$ aws autoscaling attach-load-balancer-target-groups \
    --auto-scaling-group-name awscicd-asg --target-group-arns <tg>

Giờ người dùng vào qua DNS của ALB; ALB phân tới các instance khỏe trong target group.

Chuyển deployment group sang blue/green

Cập nhật deployment group: đổi deployment-style sang BLUE_GREEN, chỉ target group cho ALB, và khai cách dựng green (copy ASG hiện tại):

$ aws deploy update-deployment-group --application-name awscicd-demo \
    --current-deployment-group-name awscicd-demo-asg-dg \
    --auto-scaling-groups awscicd-asg \
    --deployment-style deploymentType=BLUE_GREEN,deploymentOption=WITH_TRAFFIC_CONTROL \
    --load-balancer-info '{"targetGroupInfoList":[{"name":"awscicd-tg"}]}' \
    --blue-green-deployment-configuration '{"terminateBlueInstancesOnDeploymentSuccess":{"action":"TERMINATE","terminationWaitTimeInMinutes":1},"deploymentReadyOption":{"actionOnTimeout":"CONTINUE_DEPLOYMENT"},"greenFleetProvisioningOption":{"action":"COPY_AUTO_SCALING_GROUP"}}' \
    --auto-rollback-configuration 'enabled=true,events=DEPLOYMENT_FAILURE,DEPLOYMENT_STOP_ON_ALARM' \
    --alarm-configuration '{"enabled":true,"alarms":[{"name":"awscicd-unhealthy-hosts"}]}'

COPY_AUTO_SCALING_GROUP bảo CodeDeploy dựng green bằng cách sao chép ASG blue; terminateBlueInstancesOnDeploymentSuccess cho phép hạ blue sau khi green tốt (chờ 1 phút trước khi terminate, để có cửa sổ kiểm tra).

Một lỗi IAM rất thực tế

Lần deploy blue/green đầu tiên của tôi fail ngay:

$ aws deploy get-deployment --deployment-id $DID --query 'deploymentInfo.errorInformation'
{
  "code": "IAM_ROLE_PERMISSIONS",
  "message": "The IAM role awscicd-codedeploy-role does not give you permission to
   perform operations in the following AWS service: AmazonAutoScaling."
}

Managed policy AWSCodeDeployRole không đủ cho blue/green khi ASG dùng launch template. Tài liệu CodeDeploy có ghi rõ điều này: khi ASG tạo từ launch template, service role cần thêm ec2:RunInstances, ec2:CreateTags, và iam:PassRole (để truyền instance role cho các máy green mới). Thêm inline policy đó (PassRole giới hạn đúng vào awscicd-ec2-role):

{
  "Effect": "Allow",
  "Action": ["ec2:RunInstances","ec2:CreateTags"],
  "Resource": "*"
},
{
  "Effect": "Allow", "Action": ["iam:PassRole"],
  "Resource": "arn:aws:iam::111122223333:role/awscicd-ec2-role"
}

Đây là loại lỗi chỉ lộ ra khi chạy thật, không thấy được khi đọc tài liệu lướt — và là lý do mỗi bài series này đều test thật. Thêm quyền xong, deploy lại thành công.

Bên trong một blue/green deploy

Phần đáng mổ nhất. Một blue/green deploy chạy hai bộ lifecycle event song song trên hai fleet. Xem event của một instance green (mới) và một instance blue (cũ):

# Green (instance mới): cài app rồi nhận traffic
ApplicationStop → DownloadBundle → BeforeInstall → Install → AfterInstall
  → ApplicationStart → ValidateService → BeforeAllowTraffic → AllowTraffic → AfterAllowTraffic

# Blue (instance cũ): bị cắt traffic
BeforeBlockTraffic → BlockTraffic → AfterBlockTraffic

Đọc kỹ: green đi qua toàn bộ chuỗi cài đặt (như in-place) rồi mới có ba event traffic (BeforeAllowTrafficAllowTrafficAfterAllowTraffic) — đăng ký green vào ALB target group. Đồng thời blue đi qua BlockTraffic — gỡ khỏi target group. Điểm cốt lõi: AllowTraffic (đưa green vào) chỉ chạy sau khi ValidateService trên green đã pass. Nghĩa là traffic chỉ chuyển khi green đã được xác nhận khỏe — nếu green fail validation, traffic không bao giờ rời blue.

   blue ASG (đang phục vụ)          ALB
   ┌──────────────┐                 │
   │ instance v1  │◀────traffic──────┤   1. CodeDeploy COPY ASG → green
   │ instance v1  │                 │   2. deploy v_new lên green, ValidateService
   └──────────────┘                 │   3. AllowTraffic: đăng ký green vào TG
   ┌──────────────┐                 │   4. BlockTraffic: gỡ blue khỏi TG
   │ instance vN  │◀────traffic──────┤   5. chờ 1 phút → terminate blue
   │ instance vN  │ (green)         │
   └──────────────┘                 ▼
   ALB không bao giờ trỏ tới fleet chưa validate → zero-downtime

Sau deploy, CodeDeploy đã tạo một ASG green mới (CodeDeploy_awscicd-demo-asg-dg_d-...) chạy phiên bản mới, và đặt ASG blue về desired 0. ALB phục vụ liên tục suốt quá trình:

$ curl http://awscicd-alb-...elb.amazonaws.com/
... awscicd demo app — v2 ...

Rollback tự động

Đây là phần làm blue/green thực sự an toàn. Trong cấu hình deployment group ở trên có hai mảnh rollback:

--auto-rollback-configuration events=DEPLOYMENT_FAILURE,DEPLOYMENT_STOP_ON_ALARM bật rollback khi deploy fail hoặc khi một alarm chuyển sang trạng thái ALARM. --alarm-configuration gắn CloudWatch alarm awscicd-unhealthy-hosts (giám sát UnHealthyHostCount của target group). Cơ chế: trong lúc deploy, nếu alarm này kêu (ví dụ green sinh host unhealthy), CodeDeploy dừng và rollback. Vì blue vẫn còn nguyên (chưa terminate trong cửa sổ chờ), rollback chỉ là trỏ ALB về lại blue — gần như tức thì, không downtime. Khác hẳn in-place: ở in-place, rollback nghĩa là deploy lại bản cũ (mất thời gian); ở blue/green, bản cũ vẫn đang chạy, chỉ cần chuyển traffic.

Ghép ValidateService (chốt trên máy) + alarm (giám sát hệ thống) + blue còn sống = một bản deploy hỏng bị chặn trước khi tới người dùng, và quay về trong vài giây.

🧹 Dọn dẹp

Part IV xong — dọn toàn bộ tài nguyên tốn tiền (cả hai ASG, ALB, target group, launch template, alarm):

$ aws autoscaling delete-auto-scaling-group --auto-scaling-group-name awscicd-asg --force-delete
$ aws autoscaling delete-auto-scaling-group --auto-scaling-group-name CodeDeploy_awscicd-demo-asg-dg_d-... --force-delete
$ aws elbv2 delete-load-balancer --load-balancer-arn <alb>
$ aws elbv2 delete-target-group --target-group-arn <tg>
$ aws ec2 delete-launch-template --launch-template-name awscicd-lt
$ aws cloudwatch delete-alarms --alarm-names awscicd-unhealthy-hosts

Blue/green để lại hai ASG (blue gốc + green do CodeDeploy tạo) nên nhớ xóa cả hai. ALB tính tiền theo giờ — đừng quên.

Tổng kết

Blue/green dựng một fleet green song song, deploy và validate nó, rồi chuyển traffic qua ALB — blue giữ nguyên để quay về. Chuyển deployment group bằng deployment-style=BLUE_GREEN + loadBalancerInfo + COPY_AUTO_SCALING_GROUP. Lưu ý thật: ASG dùng launch template cần service role có thêm ec2:RunInstances/ec2:CreateTags/iam:PassRole (lỗi IAM_ROLE_PERMISSIONS nếu thiếu). Green chạy đủ lifecycle rồi mới AllowTraffic sau ValidateService, blue đi qua BlockTraffic — traffic chỉ chuyển khi green đã khỏe. Rollback tự động (DEPLOYMENT_FAILURE + alarm) chỉ cần trỏ ALB về blue đang sống, nên gần như tức thì và không downtime.

Part IV khép lại: ta đã deploy in-place, mổ hook, lên ASG, và blue/green với rollback. Nhưng tất cả vẫn là gõ create-deployment bằng tay. Part V nối mọi mảnh lại: CodePipeline tự động chạy Source → Build → Deploy mỗi khi có commit. Bài tới dựng pipeline đầu tiên ghép CodeCommit, CodeBuild và CodeDeploy.