DEV Community

Cover image for Day 17: AWS Blue/Green with Terraform and Elastic Beanstalk
Anil KUMAR
Anil KUMAR

Posted on

Day 17: AWS Blue/Green with Terraform and Elastic Beanstalk

As part of 30-Day AWS Terraform Challenge, Today is Day 17 which will be focusing on one of the most critical topics in modern infrastructure: achieving zero-downtime updates. This deep dive covered implementing a Blue-Green Deployment strategy on AWS using Terraform and Elastic Beanstalk.

What is Blue-Green Deployment:

Blue-Green Deployment is an infrastructure strategy designed to virtually eliminate downtime during application updates. It operates on a simple, powerful premise. It is also a release technique that keeps two identical production environments - nicknamed “blue” and “green.”

Blue Environment (The Live): This is your current, live production environment, actively receiving all user traffic (e.g., Application Version 1.0).

Green Environment (The Standby): This is an exact, identical copy of the Blue environment. We deploy the new application version (e.g., Application Version 2.0) here. Since it's not receiving live traffic, we can test it thoroughly without impacting the live users.

The real magic is the Swap Process:

Once the Green environment (v2.0) is fully tested and stable, we simply swap the DNS pointer that routes traffic from the Blue environment to the Green environment.

The Green environment immediately becomes the new live "Blue" environment (v2.0).

The old Blue environment (v1.0) becomes the standby "Green," ready for instant rollback or eventual decommissioning.

Key Benefits:

  1. Zero/Minimal Downtime: The only "downtime" is the minimal DNS propagation time.
  2. Safe Testing: Changes are tested on a non-live environment.
  3. Instant Rollback: If v2.0 has an issue, you can instantly revert by swapping the DNS back to the original v1.0 environment.

This also have disadvantages as we are maintaining 2 live servers, there will be a lot of costs involved.

In this project, we will be packaging the application -> deploying the application -> uploading the zip file to S3 and then deploying that file to multiple environments using Blue/Green Environments.

Terraform Implementation:

make sure you clone the github_repo to your local and go to the folder: lessons/day-17

main.tf: Defines the AWS Provider, IAM roles (EC2 profile, Service role), and the private S3 bucket to store the application zips.

blue-environment.tf: Defines the initial production environment (Blue) using app-v1.zip.

green-environment.tf: Defines the initial production environment (Blue) using app-v1.zip.

Blue Environment Setup

We set up the Blue environment with version 1.0 in AWS Elastic Beanstalk.

  • 1. Uploads the app code to S3:
resource "aws_s3_object" "app_v1" {
  bucket = aws_s3_bucket.app_versions.id
  key    = "app-v1.zip"
  source = "${path.module}/app-v1/app-v1.zip"
  etag   = filemd5("${path.module}/app-v1/app-v1.zip")

  tags = var.tags
}
Enter fullscreen mode Exit fullscreen mode
  • Takes app-v1.zip from your local folder or from repo folder.
  • Uploads it to an S3 bucket (named app_versions), make sure bucket is created first.
  • Calculates MD5 hash to detect changes

    1. Creates an Elastic Beanstalk app version
resource "aws_elastic_beanstalk_application_version" "v1" {
  name        = "${var.app_name}-v1"
  application = aws_elastic_beanstalk_application.app.name
  description = "Application Version 1.0 - Initial Release"
  bucket      = aws_s3_bucket.app_versions.id
  key         = aws_s3_object.app_v1.id

  tags = var.tags
}
Enter fullscreen mode Exit fullscreen mode
  • Registers app-v1.zip as version your-app-name-v1
  • Links it to your main EB application
  • Stores it in S3 with the version label

    1. Launches the production environment (Blue)
resource "aws_elastic_beanstalk_environment" "blue" {
  name                = "${var.app_name}-blue"
  application         = aws_elastic_beanstalk_application.app.name
  solution_stack_name = var.solution_stack_name
  tier                = "WebServer"
  version_label       = aws_elastic_beanstalk_application_version.v1.name

  # IAM Settings
  setting {
    ....
}
Enter fullscreen mode Exit fullscreen mode
  • Creates an environment called your-app-name-blue
  • Deploys version 1.0 to it
  • Uses your specified platform (solution_stack_name)
  • Sets it as a WebServer tier (production-ready)

In simple terms: It bundles the app → uploads to S3 → registers as EB version 1.0 → deploys to production (blue environment).

Green Environment Setup:

We will use the same above setup for green environment too with just change in names of the environment from blue to green.

# Application Version 2.0 (Green Environment - Staging)
resource "aws_s3_object" "app_v2" {
  bucket = aws_s3_bucket.app_versions.id
  key    = "app-v2.zip"
  source = "${path.module}/app-v2/app-v2.zip"
  etag   = filemd5("${path.module}/app-v2/app-v2.zip")

  tags = var.tags
}

resource "aws_elastic_beanstalk_application_version" "v2" {
  name        = "${var.app_name}-v2"
  application = aws_elastic_beanstalk_application.app.name
  description = "Application Version 2.0 - New Feature Release"
  bucket      = aws_s3_bucket.app_versions.id
  key         = aws_s3_object.app_v2.id

  tags = var.tags
}

# Green Environment (Staging/Pre-production)
resource "aws_elastic_beanstalk_environment" "green" {
  name                = "${var.app_name}-green"
  application         = aws_elastic_beanstalk_application.app.name
  solution_stack_name = var.solution_stack_name
  tier                = "WebServer"
  version_label       = aws_elastic_beanstalk_application_version.v2.name

  # IAM Settings
  ...
}
Enter fullscreen mode Exit fullscreen mode

EC2 Instance Role Creation:

We will be creating EC2 Instance Roles for our app servers.

# IAM Role for Elastic Beanstalk EC2 instances
resource "aws_iam_role" "eb_ec2_role" {
  name = "${var.app_name}-eb-ec2-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      }
    ]
  })

  tags = var.tags
}
Enter fullscreen mode Exit fullscreen mode
  • Creates an IAM role ${your-app}-eb-ec2-role
  • Allows EC2 instances to "assume" this role
  • Gives your running app permissions to access AWS services (databases, S3, etc.), Currently we gave only permissions to access EC2 service for this project.

Elastic Beanstalk Service Role:

We will also create Elastic Beanstalk Service Role for AWS control plane.

# IAM Role for Elastic Beanstalk Service
resource "aws_iam_role" "eb_service_role" {
  name = "${var.app_name}-eb-service-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "elasticbeanstalk.amazonaws.com"
        }
      }
    ]
  })

  tags = var.tags
}
Enter fullscreen mode Exit fullscreen mode
  • Creates an IAM role ${your-app}-eb-service-role
  • Allows the Elastic Beanstalk service itself to manage your environments
  • AWS needs this to deploy, scale, and monitor your app and all required permissions of Elastic BeanStalk.

Locks down S3 bucket security:

# Block public access to S3 bucket
resource "aws_s3_bucket_public_access_block" "app_versions" {
  bucket = aws_s3_bucket.app_versions.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}
Enter fullscreen mode Exit fullscreen mode
  • Blocks all public access to your app_versions S3 bucket as we will be making the bucket private without having access to public Internet.
  • Prevents accidental public exposure of app-v1.zip as it shoudld not delete accidentally.
  • All 4 public access settings = maximum security

Final Deployment:

sudo chmod 755 package-apps.sh
./package-apps.sh 
terraform init
terraform plan
terraform apply
Enter fullscreen mode Exit fullscreen mode

Once the deployment was complete, Terraform will provide us the URLs for both environments as outputs:

Blue URL (Production): Showed "Welcome to blue-green demo v1.0"

Green URL (Staging): Showed "New features in v2.0"

The next step was the actual, zero-downtime Blue-Green swap.
You could also get the URL in AWS console of Elastic BeanStack.

Doing SWAP:

While the process can be scripted using the AWS CLI or advanced Terraform modules, the simplest way is via the AWS Console:

  • Navigate to the Elastic Beanstalk service.
  • Select the Actions dropdown for the environment (e.g., the Blue one).
  • Click "Swap Environment Domains."
  • Select the Green environment as the target for the swap.
  • Similarly go to the Green service of Elastic BeanStalk and do the swap selecting the Blue Environment.

The DNS swap took effect quickly. After the propagation time:

The Blue app URL now showed the new content: "New features in v2.0" (It became the new production site).

The Green app URL now showed the old content: "Welcome to blue-green demo v1.0" (It became the standby environment).

Conclusion:

Today blog will be a bit complex compared to the previous ones because we have now moved from noob stage, We also need to have knowledge about Blue-Green Deployment and Elastic BeanStalk. We have understood the key-benefits of Blue-Green Deployment and how it will be preferred in the Production of all the companies utilizing key benefits of Zero-Downtime and Instant Rollback.

Top comments (0)