BoltOps
Published in

BoltOps

Gentle Introduction to How AWS ECS Works with Example Tutorial

Summary of the ECS Terms

  • Task Definition — This a blueprint that describes how a docker container should launch. If you are already familiar with AWS, it is like a LaunchConfig except instead it is for a docker container instead of a instance. It contains settings like exposed port, docker image, cpu shares, memory requirement, command to run and environmental variables.
  • Task — This is a running container with the settings defined in the Task Definition. It can be thought of as an “instance” of a Task Definition.
  • Service — Defines long running tasks of the same Task Definition. This can be 1 running container or multiple running containers all using the same Task Definition.
  • Cluster — A logic group of EC2 instances. When an instance launches the ecs-agent software on the server registers the instance to an ECS Cluster. This is easily configurable by setting the ECS_CLUSTER variable in /etc/ecs/ecs.config described here.
  • Container Instance — This is just an EC2 instance that is part of an ECS Cluster and has docker and the ecs-agent running on it.
ECS Terms

Tutorial Example

  1. Create ECS Cluster with 1 Container Instance
  2. Create a Task Definition
  3. Create an ELB and Target Group to later associate with the ECS Service
  4. Create a Service that runs the Task Definition
  5. Confirm Everything is Working
  6. Scale Up the Service to 4 Tasks.
  7. Clean It All Up
aws ec2 create-security-group --group-name my-ecs-sg --description my-ecs-sg
$ docker run -d -p 4567:4567 --name hi tongueroo/sinatra
6df556e1df02e93b05aa46425fc539121f5e50afee630e1cd918b337c3b6c202
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6df556e1df02 tongueroo/sinatra "ruby hi.rb" 2 seconds ago Up 1 seconds 0.0.0.0:4567->4567/tcp hi
$ curl localhost:4567 ; echo
42
$ docker stop hi ; docker rm hi
$
{
"family": "sinatra-hi",
"containerDefinitions": [
{
"name": "web",
"image": "tongueroo/sinatra:latest",
"cpu": 128,
"memoryReservation": 128,
"portMappings": [
{
"containerPort": 4567,
"protocol": "tcp"
}
],
"command": [
"ruby", "hi.rb"
],
"essential": true
}
]
}
$ aws ecs register-task-definition --cli-input-json file://task-definition.json
  • Name it my-elb and select internet-facing.
  • Use the default Listener with a HTTP protocol and Port 80.
  • Under Availability Zone, chose a VPC and choose the subnets you would like. I chose all 4 subnets in the default VPC just like step 1. It is very important to chose the same subnets that was chosen when you created the cluster in step 1. If the subnets are not the same the ELB health check can fail and the containers will keep getting destroyed and recreated in an infinite loop if the instance is launched in an AZ that the ELB is not configured to see.
  • There will be a warning about using a secure listener, but for the purpose of this exercise we can skip using SSL.
  • Create a new security group named my-elb-sg and open up port 80 and source 0.0.0.0/0 so anything from the outside world can access the ELB port 80.
  • Create a new target group name my-target-group with port 80.
  • This step is a little odd for ECS. We do actually not register any targets here because ECS will automatically register the targets for us when new tasks are launched. So simply skip and click next.
  • Review and click create.
$ aws ec2 authorize-security-group-ingress --group-name my-ecs-sg --protocol tcp --port 1-65535 --source-group my-elb-sg
{
"cluster": "my-cluster",
"serviceName": "my-service",
"taskDefinition": "sinatra-hi",
"loadBalancers": [
{
"targetGroupArn": "FILL-IN-YOUR-TARGET-GROUP",
"containerName": "web",
"containerPort": 4567
}
],
"desiredCount": 1,
"role": "ecsServiceRole"
}
$ aws ecs create-service --cli-input-json file://ecs-service.json
  • Check that the my-ecs-sg security group is allowing all traffic from the my-elb-sg security group. This was done in Step 4 with the authorized-security-group-ingress command after you created the ELB.
  • Check that the security groups for the ELB, in step 3, is set to the same security groups that you use when you created the ECS Cluster and Container Instance in step 1. Remember the ELB can only detect healthy instances in AZs that it is configure to use.
$ ssh ec2-user@ec2-52-3-252-86.compute-1.amazonaws.com
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9e9a55399589 tongueroo/sinatra:latest "ruby hi.rb" 16 minutes ago Up 16 minutes 8080/tcp, 0.0.0.0:32773->4567/tcp ecs-sinatra-hi-1-web-d8efaad38dd7c3c63a00
4fea55231363 amazon/amazon-ecs-agent:latest "/agent" 41 minutes ago Up 41 minutes ecs-agent
$ curl 0.0.0.0:32773 ; echo
42
$
$ curl my-elb-1693572386.us-east-1.elb.amazonaws.com ; echo
42
$
  • ELB: my-elb
  • ECS Service: my-service Task Definition: sinatra-hi Cluster: my-cluster
  • Security group: my-elb-sg and my-ecs-sg.

Summary

Thanks for reading this far. If you found this post useful, I’d really appreciate it if you recommend this post (by clicking the clap button) so others can find it too! Also, connect with me on LinkedIn.

P.S. Be sure to join the BoltOps newsletter to receive free DevOps tips and updates.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store