Using Amazon EC2 Container Service
Amazon ECS, or EC2 Container Service is a Container Management Service for Docker containers. Similar to Kubernetes in intent, the service allows users to provision Docker containers in a fully managed cluster of EC2s. This post is a quick summary of how to get up and running with your own ECS cluster.
The motivation behind containers is to optimize the usage of underlying resources like CPU and Memory. Containerized infrastructure provides a dense compute environment, allowing us to pack more usage without having to spend $$ for idle/underutilized resources.
Setup
Make sure you have an AWS Account, and the Default VPC. The purpose of this post is a quick start with ECS, and not to suggest a production deployment. Things like VPCs, Security Groups, AMIs, IAM roles, etc. will be completely different in the real world. We will use the default VPC (which has all public subnets), and wide open default Security Groups for Load Balancers and Instances. I am using us-east-1
as reflected by many URLs in this post.
Good familiarity with Docker will be helpful as well.
Terminology
-
Docker is a container platform, which contains a process in a Docker Image. They’re lightweight in terms of provisioning, are ephemeral, and an ideal platform for microservices. Imagine 10 microservices modeled as 10 container images, each hosted under Tomcat. Each container does 1 job, and 1 job only.
-
These containers form the building blocks for tasks. So, 5 running tasks for the same Docker Image would translate to 5 JVMs running the same service on 5 EC2s in the non-docker world. Typical
ASG=EC2+ELB
scenario for a highly available deployment. Often times tasks and containers are used interchangeably. -
A cluster is a collection of EC2 instances. These instances run ECS optimized AMIs, and I like to call them hosts to avoid confusion. An instance is a very overloaded term - it could mean an EC2 in a cluster, or a task in the EC2, or an EC2 by itself. The number and type of instances is defined during creation of the cluster. A cluster has the exact same EC2 Instance Type. In other words, we cannot have a ECS cluster with an
m3.medium
and ar4.xlarge
. A cluster can spread across multiple AZs, and for high availability, it should. However, it cannot span across VPCs. -
A task can be wrapped in a service. A service is a configuration over the task - how many tasks, how to distribute the various tasks within the cluster, autoscaling, and an ALB association. So, a microservice can be instantiated N times in a cluster, creating N containers, where some of those containers can run on the host in
us-east-1a
, some on the one inus-east-1b
. A service looks like an ASG configuration. -
An ALB is needed for the service, as the task can shift within the hosts in a cluster. Also, based on autoscaling settings on the service, new containers for this service can be spun up. A classic ELB will not work as it has hardwired mapping to the back-end EC2 instances. Imagine 5 completely different tasks running on the same host, each listening to port 8080. In a classic ELB it’d be impossible to port-map dynamically. However, an ALB is associated with a target group, and ECS automatically manages the ALB registry/de-registry of containers.
-
An ECR is EC2 Container Registry, think of it as a private Dockerhub. It works exactly the same way. You build a docker image with
docker build
, tag it, and push it to a repo in ECR. The repository URI is used to refer the container in the task configuration.
Steps
Push Docker Image
-
First off, we create a Docker image. I have one ready, which runs Tomcat. In the real world, it’d be a
war
deployed in Tomcat, or a python or node server.We can just use the one here -
$ docker pull lobster1234/tomcat:8.5.20
-
Create a repository in ECR by going to https://console.aws.amazon.com/ecs/home?region=us-east-1#/repositories and clicking Create Repository.
-
Push this image onto ECR by creating a new repository, and following the steps on the AWS ECR Console.
-
Once this image is pushed (could take a while to upload 200+ MB), you’ll notice the image show up on ECR. Note the Repository URI as we’ll need it.
Cluster Creation
-
Go to https://console.aws.amazon.com/ecs/home?region=us-east-1#/clusters and click Clusters -> Create Cluster
-
Cluster name =
my-first-cluster
, Model =On-Demand Instance
, Instance Type =m3.medium
, Number of instances =2
, VPC =Default VPC
, Subnets =us-east-1a, us-east-1b
, Security Group =Default
. Leave other settings as-is. Click Create. -
View the cluster here - https://console.aws.amazon.com/ecs/home?region=us-east-1#/clusters/my-first-cluster/services. Check out the ECS Instances tab and you’ll notice the 2 EC2 instances running in there in different AZs. They’re m3.mediums - do not get shocked seeing 1024 CPU. They are running AWS ECS agent as well as the Docker agent, as you can tell from the Agent Version and Docker Version columns.
Task Definition
-
Next, we will create a task definition - this is where the container image we pushed comes in. From the left menu, click Task Definitions, and then click Create new Task Definition.
-
Task Definition Name =
my-first-task-definition
, leave the rest, and click Add Container. -
Container Name =
my-first-tomcat-container
, Image = enter theECR Repository URI
(NOT ARN), Hard Limit =128
, Port Mappings = host0
container8080
, Protocol =tcp
. -
Click Advanced Container Configuration - CPU Units =
1
, Essential =true
, and leave the rest of the settings as-is. Click Add. On the Task Definition page, click Create after verifying the newly added container shows up. Notice there can be multiple, different containers per task. -
Now you should see https://console.aws.amazon.com/ecs/home?region=us-east-1#/taskDefinitions/my-first-task-definition/1 where there is an option to create a new revision, and an Actions drop down.
Service and ALB Creation
-
Next we will create a service using this task definition. Imagine the container image was indeed hosting a real service instead of a just a tomcat installation. We would want this service available across multiple AZs, and also multiple instances of this service within each of the host. So we will do just that. Let us create a service by clicking Create Service from the Actions dropdown.
-
Service Name =
my-first-service
, Number of Tasks =5
. Leave everything else as-is. In the Task Placement section, pickAZ Balanced Spread
(this would mean the tasks, or containers for this service will get spread out across the AZs the hosts are running in). -
Now we will associate this service with a Load Balancer. Like I mentioned earlier, Classic Load Balancer will not work, so we have to create an Application Load Balancer.
-
Leave the service tab we’re in. Open up a new tab, and point to the EC2 Console https://console.aws.amazon.com/ec2/v2/home?region=us-east-1#LoadBalancers
-
Click Create Load Balancer and pick Application Load Balancer.
-
Name =
my-first-ecs-lb
, Scheme =Internet Facing
, IP Address Type =ipv4
, Listeners =HTTP
, Port80
, Availability Zones =us-east-1a
,us-east-1b
, and click Configure Security Settings. -
Click Next: Configure Security Groups. Select the
default
security group. Click Next: Configure Routing. -
Target Group =
New target group
, Name =my-first-ecs-tg
, leave everything else as-is. Click Register Targets. This is where we will pick the EC2s running our containers. Select the 2 EC2 instances which are the part of our cluster, and click Add to Registered. Leave the port as80
. Once the selected Instances show up under Registered Targets, click Next: Review. -
On the review page, click Create. Click Close on the next screen, and give it a minute to provision the ALB.
-
At this point we go back to the Create Service tab, and click Configure ELB.
-
Select
ecsServiceRole
for IAM Role for Service. The ALB we just created should show up under the ELB Name. If it does not, click the little button to refresh the drop down. Once the ALB shows up, select it. Then, In the Select a Container, pick the containermy-first-tomcat-container:0:8080
and click Add to ELB. -
This opens up a new section. In the Target Group Name section, select
my-first-ecs-tg
. Click Save. -
Review settings, and click Create Service. You’ll see a page showing the Launch Status. Click View Service when it is enabled.
-
On the View Service page, it should show 5 running tasks. Refresh the page if you do not see all 5, as it does take a few seconds for containers to launch.
Verification
-
To view the cluster, go to this URL - https://console.aws.amazon.com/ecs/home?region=us-east-1#/clusters/my-first-cluster/services. You’ll be able to click the ECS Instances Tab to check how the containers are distributed across the cluster (2 and 3).
-
To verify, go to the ALB https://us-east-1.console.aws.amazon.com/ec2/v2/home?region=us-east-1#LoadBalancers and click on
my-first-ecs-lb
. From the description tab, copy the DNS Name, and paste it in the browser. You should see the Tomcat welcome page. -
Feel free to play around with this setup, including setting up autoscaling for the service. The service console can be found here https://console.aws.amazon.com/ecs/home?region=us-east-1#/clusters/my-first-cluster/services/my-first-service/tasks
Now we have a fully functional ECS Cluster with a service running across all nodes of the cluster, available via an ALB.
Teardown
The fast and easy way is to click Delete Cluster from the Cluster Details page. However, I’ll walk you through the steps that will need some tinkering around and help better understand what goes under the hood.
-
To stop all containers and remove this service, click Update, and change the number of tasks from
5
to0
. Click Update Service. You’ll immediately notice that the Tomcat Welcome Page no longer works. In fact, this update process deregisters the containers from the ALB and then begins to drain connections. So although the tasks will show up as running, the ALB DNS URL will return a 503. All of this action can be seen Under Events tab in the Service Detail page. The default draining time is300 seconds
, so expect to wait that long. -
Next, we delete the ALB. From the LB page, https://us-east-1.console.aws.amazon.com/ec2/v2/home?region=us-east-1#LoadBalancers, select the LB and select Delete from the Actions drop down.
-
Now we delete the target group we had created. On the target groups page at https://us-east-1.console.aws.amazon.com/ec2/v2/home?region=us-east-1#TargetGroups, select
my-first-ecs-tg
and pick Delete from the Actions dropdown. -
Next, we delete the service. Come back to the service page at https://console.aws.amazon.com/ecs/home?region=us-east-1#/clusters/my-first-cluster/services/my-first-service/tasks and click Delete
-
Finally, we delete the cluster. Go to cluster page at https://console.aws.amazon.com/ecs/home?region=us-east-1#/clusters/my-first-cluster/services and click Delete Cluster. Verify by going to EC2 Console that the EC2 hosts are terminated.
Summary
In this post, we learnt how to -
- Create an ECR Repository, and push a Tomcat Docker image to it
- Create an muti-AZ ECS Cluster
- Create a Task Definition using this image
- Create a Service using this Task Definition
- Create a Target Group and ALB for this service
- Launch this service in the ECS Cluster using the Balanced Placement Policy
- Tear down the ECS Cluster
Thoughts, feedback, ideas? Please let me know in the comments below.