Blue-green deployment with Amazon ECS
Blue-green deployment is a powerful technique for minimizing downtime and risks during software updates. This method involves maintaining two identical environments, referred to as “blue” and “green.” Only one of these environments is live, serving all production traffic at any given time. It involves deploying a new version of your application in an environment that is not currently live, allowing for a seamless transition and minimal disruption to users. After testing and verifying the new version in this environment, you switch the router or load balancer to direct traffic to it, making it the new production environment.
Amazon Elastic Container Service (ECS) offers an excellent platform for implementing blue-green deployments. By utilizing ECS along with other AWS services, you can establish a strong, automated deployment pipeline. In this blog, I’ll guide you through the entire process of creating a blue-green deployment pipeline using Amazon ECS, from GitHub to production deployment.
Prerequisites of blue-green deployment with Amazon ECS
Before we begin, ensure you have the following:
- An AWS account with appropriate permissions
- AWS CLI installed and configured on your local machine
- Basic understanding of Docker and containerization
- Familiarity with Git for version control
- Private Subnet for CodeBuild with NAT Gateway attached.
- ECR repo if you don’t have, create a ECR repo using below command
aws ecr create-repository --repository-name ecs-demo-app --region us-east-1
Steps to implement blue-green deployment
Step 1: Create ECS cluster and Task Definition
aws ecs create-cluster --cluster-name ECS-BlueGreenCluster --region us-east-1
Before creating a task definition, you need to create an execution role and a task IAM role. Both roles need to be placed in the taskdef.json file. You can refer to the links below for instructions on creating these roles
- https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_execution_IAM_role.html
- https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html
{
"family": "ecs-bg-task-def-v1",
"networkMode": "awsvpc",
"executionRoleArn": "arn:aws:iam:: <account-id>:role/ecsTaskExecutionRole-v1",
"taskRoleArn": "arn:aws:iam::<account-id>:role/ecsTaskRole",
"containerDefinitions": [
{
"name": "php-app",
"image": " <account-id>.dkr.ecr.us-east-1.amazonaws.com/ecs-demo-app:v1",
"essential": true,
"portMappings": [
{
"hostPort": 80,
"protocol": "tcp",
"containerPort": 80
}
]
}
],
"requiresCompatibilities": [
"FARGATE"
],
"cpu": "256",
"memory": "512"
}
Step 2: Register the task definition for ECS
aws ecs register-task-definition --cli-input-json file://taskdef.json
Step 3: Set up the code build for container image building
The first step in the blue-green deployment process is establishing a robust code pipeline. We will utilize AWS CodeBuild and CodePipeline to create an end-to-end CI/CD pipeline.
First, create a CodeBuild role to communicate with ECR and S3 bucket over CodePipeline. Refer to the official documentation for detailed instructions: https://docs.aws.amazon.com/codebuild/latest/userguide/setting-up-service-role.html
Next, set up a CodeBuild project to build the Docker image. Then, create a file named buildspec.yml in your repository root with the specified content.
version: 0.2
phases:
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com
build:
commands:
- echo Build started on `date`
- echo Building the Docker image...
- docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
- docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
post_build:
commands:
- echo Build completed on `date`
- echo Pushing the Docker image...
- docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
- REPOSITORY_URI=$(echo $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG)
- printf '{"ImageURI":"%s"}' $REPOSITORY_URI > imageDetail.json
- cat imageDetail.json
- echo Build completed on `date`artifacts:
files:
- image*.json
- 'appspec.yaml'
- 'task-def.json'
secondary-artifacts:
DefinitionArtifact:
files:
- appspec.yaml
- task-def.json
ImageArtifact:
files:
- imageDetail.json
Step 4: Create a CodeBuild project:
aws codebuild create-project --cli-input-json file://codebuild-project.json
You’ll need to create a codebuild-project.json file with the appropriate configuration. Here’s a basic example:
{
"name": "my-ecs-app-build",
"source": {
"type": "GITHUB",
"location": "https://github.com/rajburnwal07/ecs-demo-php-simple-app.git",
"buildspec": "buildspec.yaml",
"gitCloneDepth": 1
},
"sourceVersion": "master",
"artifacts": {
"type": "NO_ARTIFACTS"
},
"environment": {
"type": "LINUX_CONTAINER",
"image": "aws/codebuild/amazonlinux2-x86_64-standard:3.0",
"computeType": "BUILD_GENERAL1_SMALL",
"privilegedMode": true,
"environmentVariables": [
{
"name": "AWS_REGION",
"value": "us-east-1"
},
{
"name": "AWS_ACCOUNT_ID",
"value": "<ACCOUNT-ID>"
},
{
"name": "IMAGE_REPO_NAME",
"value": "ecs-demo-app"
},
{
"name": "IMAGE_TAG",
"value": "v1"
},
{
"name": "CONTAINER_NAME",
"value": "php-app"
}
]
},
"serviceRole": "arn:aws:iam::<account-id>:role/codebuild-service-role",
"timeoutInMinutes": 60,
"queuedTimeoutInMinutes": 480,
"vpcConfig": {
"securityGroupIds": [
"sg-f699b1a8"
],
"subnets": [
"<private-subnet-natgw-attached>"
],
"vpcId": "vpc-0f0a4c75"
},
"logsConfig": {
"cloudWatchLogs": {
"status": "ENABLED"
},
"s3Logs": {
"status": "DISABLED",
"encryptionDisabled": false
}
}
}
Step 5: Set up a VPC and subnets for your ECS services.
You can use an existing VPC or create a new one.
Create the application (read more..)