1. Answers
  2. Blue/Green Deployment for Zero-Downtime Releases

How Do I Perform a Blue/Green Deployment for Zero-Downtime Releases?

Introduction:

Blue/green deployment is a strategy designed to minimize downtime and risk by running two identical production environments, referred to as Blue and Green. During a deployment, one environment serves live traffic while the other is updated. This method ensures that end users experience no downtime during the release of new application versions. In this guide, we will demonstrate how to implement a blue/green deployment model using AWS services such as EC2, Elastic Load Balancer (ALB), and ECS (Elastic Container Service).

Overview:

  1. EC2 Instances - Host two separate environments (Blue and Green).
  2. Application Load Balancer (ALB) - Routes traffic to either the Blue or Green environment.
  3. ECS Services - Deploy versions of the application to different target groups associated with the ALB.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as std from "@pulumi/std";

const main = new aws.ec2.Vpc("main", {cidrBlock: "10.0.0.0/16"});
const mainSubnet: aws.ec2.Subnet[] = [];
for (const range = {value: 0}; range.value < 2; range.value++) {
    mainSubnet.push(new aws.ec2.Subnet(`main-${range.value}`, {
        vpcId: main.id,
        cidrBlock: std.cidrsubnetOutput({
            input: main.cidrBlock,
            newbits: 8,
            netnum: range.value,
        }).apply(invoke => invoke.result),
        availabilityZone: [
            "us-west-2a",
            "us-west-2b",
        ][range.value],
    }));
}
const albSg = new aws.ec2.SecurityGroup("alb_sg", {
    vpcId: main.id,
    ingress: [{
        fromPort: 80,
        toPort: 80,
        protocol: "tcp",
        cidrBlocks: ["0.0.0.0/0"],
    }],
    egress: [{
        fromPort: 0,
        toPort: 0,
        protocol: "-1",
        cidrBlocks: ["0.0.0.0/0"],
    }],
});
const mainLoadBalancer = new aws.lb.LoadBalancer("main", {
    name: "blue-green-alb",
    internal: false,
    loadBalancerType: "application",
    securityGroups: [albSg.id],
    subnets: mainSubnet.map(__item => __item.id),
});
const blue = new aws.lb.TargetGroup("blue", {
    name: "blue-target-group",
    port: 80,
    protocol: "HTTP",
    vpcId: main.id,
    healthCheck: {
        path: "/",
        interval: 30,
        timeout: 5,
        unhealthyThreshold: 2,
        healthyThreshold: 2,
    },
});
const green = new aws.lb.TargetGroup("green", {
    name: "green-target-group",
    port: 80,
    protocol: "HTTP",
    vpcId: main.id,
    healthCheck: {
        path: "/",
        interval: 30,
        timeout: 5,
        unhealthyThreshold: 2,
        healthyThreshold: 2,
    },
});
const http = new aws.lb.Listener("http", {
    loadBalancerArn: mainLoadBalancer.arn,
    port: 80,
    protocol: "HTTP",
    defaultActions: [{
        type: "forward",
        targetGroupArn: blue.arn,
    }],
});
const mainCluster = new aws.ecs.Cluster("main", {name: "blue-green-cluster"});
const mainTaskDefinition = new aws.ecs.TaskDefinition("main", {
    family: "my-task-def",
    containerDefinitions: JSON.stringify([{
        name: "my-app",
        image: "nginx",
        cpu: 256,
        memory: 512,
        essential: true,
        portMappings: [{
            containerPort: 80,
            hostPort: 80,
            protocol: "tcp",
        }],
    }]),
});
const blueService = new aws.ecs.Service("blue", {
    name: "blue-service",
    cluster: mainCluster.id,
    taskDefinition: mainTaskDefinition.arn,
    desiredCount: 1,
    launchType: "EC2",
    loadBalancers: [{
        targetGroupArn: blue.arn,
        containerName: "my-app",
        containerPort: 80,
    }],
});
const greenService = new aws.ecs.Service("green", {
    name: "green-service",
    cluster: mainCluster.id,
    taskDefinition: mainTaskDefinition.arn,
    desiredCount: 1,
    launchType: "EC2",
    loadBalancers: [{
        targetGroupArn: green.arn,
        containerName: "my-app",
        containerPort: 80,
    }],
});
export const loadBalancerDns = mainLoadBalancer.dnsName;

Step-by-Step Deployment Process:

  1. Set Up VPC and Subnets: Create a VPC to provide network resources and divide it into two subnets for high availability.
  2. Configure Security Group: Set up a security group to allow HTTP traffic.
  3. Deploy Application Load Balancer (ALB): Use ALB to distribute traffic between the Blue and Green environments based on target groups.
  4. Define Target Groups: Create blue and green target groups to manage two separate versions of the application.
  5. Set Up ECS Cluster and Services: Establish an ECS cluster with services pointing to the respective target groups.
  6. Switch Traffic: By changing the default target group of the ALB, direct traffic to the desired environment (Blue or Green) to perform the deployment.

Summary:

In this guide, we established a blue/green deployment model using AWS services, enabling zero-downtime releases. By leveraging EC2, ALB, and ECS, we can efficiently switch between the blue and green environments. This setup allows for seamless deployments, easy rollbacks, and independent testing of new features, ensuring a robust and reliable application delivery process.

Deploy this code

Want to deploy this code? Sign up for a free Pulumi account to deploy in a few clicks.

Sign up

New to Pulumi?

Want to deploy this code? Sign up with Pulumi to deploy in a few clicks.

Sign up