Deploy web application revisions on ECS.

Ankan-Devops
codelogicx
Published in
5 min readJul 13, 2022

Setting up the ECS in AWS console.

ECS in AWS console

Creating ECS Task definition :

Task definition is used to run docker containers in ECS. Specifications like memory & CPU usage can also be provided.

  1. Create a repository in private ECR.
  2. Now, let’s start creating a new task definition :
    - Select the launch type you want. Fargate for instances managed by AWS itself while EC2 for instances managed by you (more control).
    - The network mode is preferably set to default (bridge/NAT) for EC2 type and AWSVPC for fargate type.
    - Set the CPU and memory task size. This the maximum amount specified for all the containers specified in the task definition.
    - Under container : Enter the container name you like & the image path
    given in the ECR.
    - The Hard Limits specifies the max memory a container can use. The Soft Limit is the memory initially reserved for a container but can be surpassed to the hard limit. (Hard limit > Soft limit).
    - Port mapping is needed to serve content. For dynamic port mapping, enter 0 as the host port.
    - In dynamic port mapping, we can run multiple tasks in the same instance as different ports are provided for each container. Though, we need to have the network mode as bridge (in linux ec2) for that.
    - Optional settings like health check commands, CPU & memory limits can be added.
Container setup in Task definition of ECS

Creating ECS Cluster.

The ECS cluster compromises of tasks and services and handles the scheduling of the number of tasks. Cluster also provides metrics for monitoring.

  1. Select EC2 linux + Networking for configuring VPC, subnets, EC2 instances and auto scaling group.
  2. Enter the instance type (preferably t3.medium or more). Provide the other details.
ECS cluster creation

Creating Services.

The ECS service specifies the no of tasks running simultaneously in AWS ECS cluster. It maintains the value by creating a new task if any of them fails. Load balancing and auto scaling can also be configured.

  1. Select launch type as EC2 and the proper task definition.
  2. Enter the no of tasks. For non-dynamic port mapping, no of tasks ≤ no of instances.
  3. For non-dynamic port mapping the minimum healthy percentage is to be kept below 100%.

4. In the next step, we will setup load balancing (skip, if load balancing is not needed) :

  • Create a target group.
    - Choose target type as ‘Instance’.
    - Select the VPC where the ECS has been created.
    - Do not add any target group
  • Create Application load balancer.
    - Select the proper VPC and attach the listener to the target group.
  • Add the loadbalancer’s sg to the inbound rule of EC2 instance sg for all traffic.
  • Put the details in the ECS service.
  • Enter the ‘Health check grace period’ of more than > 100 seconds. The health check will therefore wait before the EC2 insance changes to the running state.

5. Opt for Auto-scaling policy and select ‘CPU Utilization’ as the metric for scaling.

Auto scaling setup in ECS service.
ECS — EC2 instance security group configuration

Setting up the Bit-Bucket Pipeline.

The bitbucket pipeline is used for deploying a new version of the application to the existing ECS service. The bitbucket-pipelines.yml is used for creating a new docker image of the project and using the new image version to create a new version of the task- definition.

Creating IAM User in AWS for Bitbucket Pipeline.

  1. Create an IAM user with Programmatic Access only.
  2. Attach the following permissions :
    - AmazonECS_FullAccess (for pushing docker image to ECR)
    - AmazonEC2ContainerRegistryPowerUser (for creating a new revision of task-definition & updating the ECS service)
Permissions for IAM users

3. Save the AWS Access ID & Secret Key which needs to be added as secret in the next step. Also note the AWS region where the ECS & ECR setup is done.

Storing secrets in Bitbucket

  1. Store these secrets in the repository variables.
    - AWS_ACCESS_KEY_ID
    - AWS_SECRET_ACCESS_KEY
    - AWS_DEFAULT_REGION
    - AWS_REGISTRY_URL (Refers to : AWS ECR repository)
    - CLUSTER (Refers to : ECS cluster name)
    - SERVICE (Refers to : ECS service name)
    -
    TASKDEF (Refers to : Task-definition name)
    -
    CONTAINER (Refers to : container name in task-definition. Can be multiple)
    -
    AWS_ID (Refers to : AWS account ID)

Creating ‘task-definition.sample.json’

  1. A task-definition.json is needed to create a new revision of the existing task definition. The json file contains the name of the new version of the docker image. This new revision of the task-definition.json can be pushed through bitbucket pipeline.

    A sample task-definition.sample.json is given below :

    {
    “executionRoleArn”: “arn:aws:iam::${AWS_ID}:role/ecsTaskExecutionRole”,
    “containerDefinitions”: [
    {
    “portMappings”: [
    {
    “hostPort”: 0,
    “protocol”: “tcp”,
    “containerPort”: 80
    }
    ],
    “cpu”: 0,
    “memory”: 300,
    “image”: “${AWS_REGISTRY_URL}:$BUILD_ID”,
    “name”: “sample-ecs3”,
    “essential”: true

    }
    ],
    “memory”: “1024”,
    “taskRoleArn”: “arn:aws:iam::${AWS_ID}:role/ecsTaskExecutionRole”,
    “family”: “sample-ecs3”,
    “requiresCompatibilities”: [
    “EC2”
    ],
    “networkMode”: “bridge”,
    “cpu”: “1024”
    }

Creating ‘bitbucket-pipelines.yml’

  1. The bitbucket-pipelines.yml build a docker image and uploads as a new version to the ECR. The task-definition.json is updated through the yml and deployed as a new revision of service.

2. A sample bitbucket-pipelines.yml is given below :

pipelines:
branches:
master:
- step:
services:
- docker
name: Build and Push Docker Image
image: atlassian/pipelines-awscli
script:
- eval $(aws ecr get-login --region ${AWS_DEFAULT_REGION} --no-include-email)
# docker
- export BUILD_ID=$BITBUCKET_BRANCH_$BITBUCKET_COMMIT_$BITBUCKET_BUILD_NUMBER
- docker build -t ${AWS_REGISTRY_URL}:$BUILD_ID .
- docker push ${AWS_REGISTRY_URL}:$BUILD_ID

- step:
name: update task-definition
image: atlassian/default-image:2
script:
- export BUILD_ID=$BITBUCKET_BRANCH_$BITBUCKET_COMMIT_$BITBUCKET_BUILD_NUMBER
- envsubst <task-definition.sample.json> task-definition.json
artifacts:
- task-definition.json

- step:
name: Deploy to ECS
image: atlassian/pipelines-awscli
script:
- pipe: atlassian/aws-ecs-deploy:1.1.0
variables:
CLUSTER_NAME: ${CLUSTER}
SERVICE_NAME: ${SERVICE}
TASK_DEFINITION: "task-definition.json"

--

--