# Achieving Zero-Downtime Blue-Green Deployments with AWS CodeDeploy

## **Introduction**

In production, **you can't afford downtime** during deployments. Blue-Green deployment lets you deploy a new version alongside the old one, then switch traffic instantly—zero downtime, instant rollback if something breaks.

**What You'll Learn:**

*   ✅ What is Blue-Green deployment (and why it's better than rolling updates)
    
*   ✅ Configure AWS CodeDeploy for ECS Fargate
    
*   ✅ Create deployment group with ALB integration
    
*   ✅ Set up deployment preferences (traffic shifting, alarms)
    
*   ✅ Deploy new version with zero downtime
    
*   ✅ Instant rollback if health checks fail
    

**Prerequisites:**

*   Part 3 completed (ECS Fargate cluster running)
    
*   App with `/health` endpoint
    

* * *

## **1\. What is Blue-Green Deployment?**

**Traditional Rolling Update:**

```bash
Old: [Task A] [Task B] → New Task C replaces Task A → Task D replaces Task B
      ↓ Downtime during replacement ↓
```

**Blue-Green Deployment:**

```bash
Blue (Old): [Task A v1] [Task B v1] ← Live traffic
Green (New): [Task C v2] [Task D v2] ← Deployed in parallel
             ↓
             Switch ALB from Blue → Green (instant, zero downtime)
             ↓
             If v2 fails: Rollback to Blue (instant)
             ↓
             If v2 succeeds: Delete Blue, keep Green
```

**Why Blue-Green is Better:**

| **Feature** | **Rolling Update** | **Blue-Green** |
| --- | --- | --- |
| Downtime | 30-60 seconds during replacement | Zero |
| Rollback speed | 2-3 minutes | Instant (<10 seconds) |
| Testing before traffic | No | Yes (test Green before switching) |
| Complexity | Low | Medium |

* * *

## **2\. Set Up CodeDeploy Application**

**Terraform Code:**

```bash
# codedeploy.tf
resource "aws_codedeploy_app" "ecs" {
  name             = "ecs-blue-green-app"
  compute_platform = "ECS"

  tags = {
    Name        = "ecs-codedeploy-app"
    Environment = "production"
  }
}

# Deployment Group
resource "aws_codedeploy_group" "ecs" {
  name        = "ecs-blue-green-deployment-group"
  application = aws_codedeploy_app.ecs.name

  deployment_config_name = "CodeDeployDefault.ECSAllAtOnce" # Or "ECSHalfRollout"

  deployment_group_style {
    deployment_option = "WITH_TRAFFIC_CONTROL"
    deployment_type   = "BLUE_GREEN"
  }

  # ECS Service
  ecs_service {
    name        = aws_ecs_service.app.name
    cluster     = aws_ecs_cluster.main.name
  }

  # Load Balancer (for traffic routing)
  load_balancer_info {
    target_group_pair_info {
      prod_traffic_route {
        listener_arns = [aws_lb_listener.http.arn]
      }

      target_group {
        name = aws_lb_target_group.app.name
      }

      # Additional target group for Green (CodeDeploy creates this)
      additional_target_group {
        name = aws_lb_target_group.green.name
      }
    }
  }

  # Auto-scaling for Green environment
  auto_scaling_group {
    name                  = aws_autoscaling_group.green.name
    deployment_termination_strategy = "IN_PLACE"
  }

  tags = {
    Name        = "ecs-blue-green-deployment-group"
    Environment = "production"
  }
}
```

**Deployment Configurations:**

| **Config** | **Description** | **Use Case** |
| --- | --- | --- |
| `CodeDeployDefault.ECSAllAtOnce` | Instant traffic switch | Fastest, risky if bugs |
| `CodeDeployDefault.ECSHalfRollout` | 50% traffic first, then rest | Balanced (recommended) |
| `CodeDeployDefault.ECSSlowRollout` | Gradual traffic shift (10% → 50% → 100%) | Safest, slower |

* * *

## **3\. Create Green Target Group**

CodeDeploy creates a **second target group** for the Green environment:

```bash
# Green target group (for new version)
resource "aws_lb_target_group" "green" {
  name        = "ecs-app-tg-green"
  port        = 8080
  protocol    = "HTTP"
  vpc_id      = aws_vpc.main.id
  target_type = "ip"

  health_check {
    enabled             = true
    healthy_threshold   = 2
    unhealthy_threshold = 10
    timeout             = 5
    interval            = 30
    path                = "/health"
    matcher             = "200-299"
  }

  tags = {
    Name = "ecs-app-green-target-group"
  }
}
```

* * *

## **4\. Configure AppSpec File (appspec.yaml)**

The **appSpec file** tells CodeDeploy how to deploy:

```bash
# appspec.yaml
version: 0.0
Resources:
  - MyEcsService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: "arn:aws:ecs:ap-south-1:123456789012:task-definition/ecs-app-task:2"
        LoadBalancerInfo:
          ContainerName: "ecs-app"
          ContainerPort: 8080
        PlatformVersion: "LATEST"
        LaunchType: "FARGATE"
        NetworkConfiguration:
          AwsvpcConfiguration:
            Subnets:
              - "subnet-0abc123def456"
              - "subnet-0abc123def789"
            SecurityGroups:
              - "sg-0abc123def456"
            AssignPublicIp: DISABLED
```

**Important:** Update `TaskDefinition` ARN to the **new version** (e.g., `:2` instead of `:1`).

* * *

## **5\. Create CodeDeploy Deployment**

**Using AWS CLI:**

```bash
# Create deployment
aws codedeploy create-deployment \
  --application-name ecs-blue-green-app \
  --deployment-group-name ecs-blue-green-deployment-group \
  --deployment-config-name CodeDeployDefault.ECSHalfRollout \
  --app-spec-location file://appspec.yaml \
  --description "Deploying v2 with Blue-Green"
```

**Expected Output:**

```bash
{
  "deploymentId": "d-abc123def456"
}
```

**Monitor Deployment:**

```bash
# Check deployment status
aws codedeploy get-deployment --deployment-id d-abc123def456

# Expected stages:
# 1. CreateRevolution (Green environment provisioning)
# 2. WaitUntilInstanceIsReady (Green tasks healthy)
# 3. AllowTraffic (switch ALB from Blue → Green)
# 4. ValidateService (health checks pass)
# 5. Finish (Blue deleted, Green becomes production)
```

* * *

## **6\. Deployment Timeline (Visual)**

```bash
Minute 0:   Start deployment (Blue = v1, Green = v2)
Minute 2:   Green tasks launching (Fargate provisioning)
Minute 5:   Green tasks healthy (health checks pass)
Minute 6:   ALB switches 50% traffic to Green (HalfRollout)
Minute 8:   ALB switches 100% traffic to Green
Minute 10:  Blue tasks terminated (deployment complete)

Total: ~10 minutes (zero downtime)
```

* * *

## **7\. Instant Rollback (If Something Breaks)**

If Green fails health checks:

```bash
# Manual rollback
aws codedeploy stop-deployment --deployment-id d-abc123def456 --reason "Bug in v2"

# ALB instantly switches back to Blue (v1)
# Users experience <10 seconds interruption
```

**Auto-Rollback (Add Alarms):**

```bash
# Add CloudWatch alarms for auto-rollback
resource "aws_cloudwatch_metric_alarm" "ecs_error_rate" {
  alarm_name          = "ecs-error-rate-alarm"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 2
  metric_name         = "TargetResponseTime"
  namespace           = "AWS/ECS"
  period              = 120
  statistic           = "Average"
  threshold           = 500 # ms

  dimensions = {
    ClusterName = aws_ecs_cluster.main.name
    ServiceName = aws_ecs_service.app.name
  }

  alarm_actions = [aws_sns_topic.deployments.arn]
}

# Auto-rollback in CodeDeploy
resource "aws_codedeploy_group" "ecs" {
  # ... (previous config)

  rollback_configuration {
    rollback_enabled = true
    rollback_events  = ["DEPLOYMENT_FAILURE", "ALARM_TRIGGERED"]
  }
}
```

* * *

## **8\. Testing Blue-Green Locally**

Before deploying to production, test locally:

```bash
# Create both target groups
terraform apply

# Deploy v1 (Blue)
aws ecs update-service --cluster ecs-production-cluster --service ecs-app-service --task-definition ecs-app-task:1

# Deploy v2 (Green)
aws codedeploy create-deployment --deployment-group-name ecs-blue-green-deployment-group --app-spec-location file://appspec.yaml

# Test Green before switching
curl http://<green-target-group-dns>/health

# If healthy, proceed with traffic switch
```

* * *

## **9\. Common Errors & Troubleshooting**

| **Error** | **Cause** | **Solution** |
| --- | --- | --- |
| `Green environment failed to create` | Fargate quota exceeded | Request quota increase |
| `Health check failed` | App not responding on `/health` | Add endpoint or change path |
| `Deployment stuck at "WaitUntilInstanceIsReady"` | Green tasks not healthy | Check CloudWatch logs |
| `ALB not routing traffic` | Target group not registered | Verify ALB listener configuration |
| `Rollback failed` | Blue environment deleted | Keep Blue for 24 hours |

* * *

## **10\. Total Cost (Blue-Green)**

| **Resource** | **Cost/Month** |
| --- | --- |
| Blue-Green (2x tasks during deployment) | ~$120 (temporary) |
| CodeDeploy | $0.10/deployment (~$5/month for 50 deployments) |
| **Total** | **~$125/month** |

* * *

## **Summary**

You now have **zero-downtime deployments**:

*   ✅ Blue-Green deployment configured
    
*   ✅ CodeDeploy application + deployment group
    
*   ✅ ALB traffic switching (50% → 100%)
    
*   ✅ Instant rollback capability
    
*   ✅ Auto-rollback with CloudWatch alarms
    

**Next Step:** Part 5 will add **monitoring and logging with CloudWatch**.
