Skip to content

Modus-Logo-Long-BlackCreated with Sketch.

  • Services
  • Work
  • Blog
  • Resources

    OUR RESOURCES

    Innovation Podcast

    Explore transformative innovation with industry leaders.

    Guides & Playbooks

    Implement leading digital innovation with our strategic guides.

    Practical guide to building an effective AI strategy
  • Who we are

    Our story

    Learn about our values, vision, and commitment to client success.

    Open Source

    Discover how we contribute to and benefit from the global open source ecosystem.

    Careers

    Join our dynamic team and shape the future of digital transformation.

    How we built our unique culture
  • Let's talk
  • EN
  • FR

Elastic Container Service (ECS) is a managed AWS service that typically uses Docker, which allows developers to launch containers and ensure that container instances are isolated from each other. 

ECS sits on top of Docker, allowing you to launch, set up, and monitor your Docker containers on your ECS cluster.

You need an infrastructure to run Docker containers. There are two options for it:

  • Serverless option (with Fargate)
  • Managed option (with EC2) – This comes with EC2 instances, which we rent and pay by the hour.

ECS supports auto-scaling, which lets you handle variable volume. As your traffic rises and falls, you can set up auto-scaling on a specific metric (e.g., traffic, memory utilization, CPU utilization). Therefore, you can bring the number of containers up or down in response to fluctuations in the selected metric. This ensures your service always has enough infrastructure to serve the incoming traffic.


NEW RESEARCH: LEARN HOW DECISION-MAKERS ARE PRIORITIZING DIGITAL INITIATIVES IN 2024.

New call-to-action

ECS is great for ad hoc jobs or full-scale services that require a certain number of containers up and running. Using ECS with Docker is also very cost-effective, as you can host multiple containers on a single compute resource. 

For example, when using EC2, you can have multiple Docker tasks and containers running on that single instance. It’s cost-effective because you can better utilize the available resources and not use them on operating system overhead.

Before You Begin

Before starting, you should have an AWS account with an IAM identity and privileges to manage the following services:

  • EC2
  • ECS
  • ECR
  • VPC
  • Load balancer (EC2 feature) 
  • IAM
  • S3

Elastic Container Registry

ECR is where we will later upload the Docker images using CodeBuild. The configuration is straightforward; you need to search ECR and create a repository. Then, you can select whether the repository should be public or private and add the repository name. The repository name would be used in the buildspec file to identify where you want to upload the image.

Dockerfile and Buildspec

The first step would be to create a Dockerfile so that it can upload Docker images to Elastic Container Registry.

FROM node:12.22-alpine
WORKDIR /app
COPY package.json yarn.lock /app
RUN yarn install
COPY . /app
EXPOSE 3000
CMD npm run start:prod

We would also need a buildspec file. It will give instructions to CodeBuild on how to log in, run the code, and then upload the Docker image to ECR. The build will run whenever we commit code into a specific branch. 

version: 0.2
phases:
 install:
   runtime-versions:
     docker: 18
 pre_build:
   commands:
     - $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email)
     - REPOSITORY_URI={ECR repo URI}
     - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
     - IMAGE_TAG=${COMMIT_HASH:=latest}
 build:
   commands:
     - docker build -t $REPOSITORY_URI:latest -f Dockerfile .
     - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
 post_build:
   commands:
     - docker push $REPOSITORY_URI:latest
     - docker push $REPOSITORY_URI:$IMAGE_TAG
     - printf '[{"name":"nestjs-graphql","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
artifacts:
 files: imagedefinitions.json

Add both Dockerfile and buildspec files to the root of the directory. 

CodeBuild

Go to CodeBuild and select Create a project

1. Project Configuration

In project configuration, add the Project name.

2. Source

Define the source of the repository. In our case, the source provider is GitHub. Also, add the Repository URL and name of the branch in the source version as shown below.

3. Environment

We will use Managed Image with Ubuntu Operating System for the environment image.

We also need to enable the Privileged Flag for building Docker images. If this flag is not enabled, we will get the following error.

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

Choose New service role and add a role name for now. We will add a few more permissions to the newly created role later.

We will also require a few Additional configurations like setting compute and Environment variables. For the compute option, we will choose 3 GB memory, 2 vCPUs. You can choose higher RAM and CPU based on your needs.

We can add Environment variables in AWS Secrets Manager and use them in the build.

4. Buildspec

Choose the Use a buildspec file option and specify a name if you have multiple buildspec for staging and production.

5. Batch Configuration

We will not use batch configuration.

6. Artifacts

We will not add any artifact but can use Encryption Key, which is in additional configuration. Go to Key Management service and add arn link so that the build can access configurations in the S3 bucket.

7. Logs

We are only enabling cloud watch logs. After all the configurations, click Create build project.

8. Permissions 

After creating a new service role in the CodeBuild environment, add:

  1. SecretsManagerReadWrite to access environment variables and other secrets
  2. AmazonS3ReadOnlyAccess, which stores project configuration
  3. CodeBuildAccessToECR to upload build images to Elastic Container Register
  4. AmazonEC2ContainerRegisteryFullAccess to deploy the image to EC2 instance using Elastic Container Service

Elastic Container Service Configuration

Go to Elastic Container Service and create a new cluster. We will create relevant services and tasks in the cluster.

1. Task Definition

A Task Definition defines which containers are present in the task and how they will communicate with each other. Create a new Task Definition. We will be selecting Fargate as a launch type because it’s an AWS-managed infrastructure and has no EC2 instance to manage.

Configure task and container definitions:

  • Add the definition name.
  • Task role, an optional IAM role that tasks can use to make API requests to other AWS services.
  • Network mode would be by default awsvpc for ECS Fargate.

Task execution to the IAM role that authorizes Amazon ECS to pull private images and publish logs for your task. This takes the place of the EC2 Instance role when running tasks.

For the task size, we will choose 2GB RAM and 0.5 vCPU. The memory and CPU should be subject to the needs of the application.

Add Container, the container name (specified in our buildspec file), and get the image URL from ECR.

Port mappings allow containers to access ports on the host container instance to send or receive traffic. This should be the port we exposed in the dockerfile.

We don’t need other configuration options for this setup. After this, create the task definition.

2. Create Service

Go to the created cluster in ECS and create a new service. Service helps configure copies of the task definition we want to run and maintain in a cluster.

Step 1: Configure service

  • Select Fargate as the launch type for running the task
  • Specify the task definition created in the previous step
  • Choose the cluster 
  • Add the service name
  • The number of tasks would be 1 for this project

The rest of the configurations should be default for step 1.

Step 2: Configure network

Our containers will need external access to communicate with ECS external endpoint. We would also want to run our service and task definition in a private network. Therefore, we will configure Virtual Private Cloud using AWS documentation on Creating a VPC with Public and Private Subnets for your cluster and then create:

  • Virtual Private Cloud
  • Public subnets in VPC that task scheduler should consider for placement
  • Security group, a VPC security group, is by default created with port 80 open to the internet, but we will have to add Custom TCP with Port 3000 because our container is exposed to port 3000.

The Elastic load balancing will help distribute all the incoming traffic between the running tasks. We can configure the load balancer and its target groups in EC2 load balancing options.

We will create a target group because load balancers routes will request the target group and perform health checks on the targets.

Go to Load Balancers > Target Groups > Create target group

Next, specify group details:

  • The target Type should be IP because it helps with routing to multiple network interfaces and IP addresses on the same instance.
  • Add a target group name, protocol, and port as shown below:

  • Select the created VPC that will host the load balancer. We will configure the load balance after creating the target group.

To register targets, choose a network, specify IPs and defined ports, and create the target group.

We will create the Network Load Balancer because it distributes incoming TCP and UDP traffic across multiple targets such as Amazon EC2 instances, microservices, and containers. When the load balancer receives a connection request, it selects a target based on the protocol and port that are specified in the listener configuration and the routing rule specified as the default action.

  • Add load balancer name.
  • Select internet-facing scheme because it routes requests from clients over the internet to targets.
  • Select IP address which our subnets use, i.e., IPv4
  • Select the Virtual Private Cloud(VPC) for our targets. We will select the same VPC added to our target group.
  • Select at least two Availability Zones and one subnet per zone, i.e., eu-central-1a and eu-central-1b. The load balancer routes traffic to targets in these Availability Zones only.
  • Add Listener with TCP protocol, port 3000, which should forward to the target group we created. The listeners in your load balancer receive matching protocol and port requests and route these requests based on the default action you specify. You can use a TLS listener to offload the work of encryption and decryption to your load balancer.

This completes the ECS service and task definition configuration. The last step would be to create a CodePipeline.

CodePipeline

CodePipeline will help automate the software release process. We will add source, CodeBuild, and ECS deployment stages to our CodePipeline.

1. Choose Pipeline Settings

  • Add pipeline name
  • New Service role

2. Add Source Stage

  • Select GitHub (version 2) as a source provider
  • Connect to GitHub account
  • Add Repository and branch name, which we want to trigger when new code is committed into that branch
  • Enable Start the pipeline on source code change option

3. Add Build Stage

  • Select AWS CodeBuild as Build provider because we configured our builds using CodeBuild
  • Add Region
  • Select the Build project which we created using CodeBuild

4. Add Deploy Stage

  • Select Amazon ECS as Deploy provider
  • Add the cluster name where we created the service
  • Select the service name which has the task definitions we created for the current project

5. Review

Review the configuration and create a Pipeline. After creating the CodePipeline, push some changes into the branch we selected, and the project should automatically build, upload images to ECR, and then deploy to ECS. After successful deployment, navigate to the load balancer, copy and paste the DNS name to the browser, and test if the application is deployed correctly or not. You should be able to see the application running.

This post was published under the JavaScript Community of Experts. Communities of Experts are specialized groups at Modus that consolidate knowledge, document standards, reduce delivery times for clients, and open up growth opportunities for team members. Learn more about the Modus Community of Experts program here. 

Posted in Application Development, DevOps
Share this

Modus Create

Modus Create is a digital transformation consulting firm dedicated to helping clients build competitive advantage through digital innovation. We specialize in strategic consulting, full lifecycle product development, platform modernization, and digital operations.
Follow

Related Posts

  • Hybrid Application Testing with Protractor and Appium
    Hybrid Application Testing with Protractor and Appium

    Testing hybrid projects can be challenging. The number of mobile devices the product has to…

  • Azure and Web Application Firewall
    How to Protect Your Azure App with a Web Application Firewall

    Protect your web applications in Microsoft Azure using Application Gateway, Front Door, and Web Application…

Want more insights to fuel your innovation efforts?

Sign up to receive our monthly newsletter and exclusive content about digital transformation and product development.

What we do

Our services
AI and data
Product development
Design and UX
IT modernization
Platform and MLOps
Developer experience
Security

Our partners
Atlassian
AWS
GitHub
Other partners

Who we are

Our story
Careers
Open source

Our work

Our case studies

Our resources

Blog
Innovation podcast
Guides & playbooks

Connect with us

Get monthly insights on AI adoption

© 2025 Modus Create, LLC

Privacy PolicySitemap
Scroll To Top
  • Services
  • Work
  • Blog
  • Resources
    • Innovation Podcast
    • Guides & Playbooks
  • Who we are
    • Careers
  • Let’s talk
  • EN
  • FR