Manage AWS ECS services with docker compose

Victor Castell
Job&Talent Engineering
7 min readMay 10, 2017

--

In this post, we will show you the AWS pattern for service discovery using Load Balancers, and how to use a Docker Compose defined service to setup and run a service in ECS and associate an existing Application Load Balancer to it.

When you start using EC2 Container Service (ECS), you could face lots of new concepts: clusters, task definitions, services definitions, etc. If you are used to working with Docker and Docker Compose, you could be overwhelmed by the concept differences between what you expect in ECS, and how it actually works.

ECS CLI, is a command line tool that helps you manage an ECS cluster and services. Best of all its compatible with Docker Compose.

From the docs:

The Amazon EC2 Container Service (Amazon ECS) command line interface (CLI) provides high-level commands to simplify creating, updating, and monitoring clusters and tasks from a local development environment.

ECS CLI provides an abstraction of ECS that allows to manage Task definitions, Service definitons, ECS clusters, in a transparent way for the user.

At Jobandtalent we started using ECS to run our platform a year ago, and we’re quite happy with it.

We use Ansible for our configuration automation as well as to automate ECS tasks and services. We are now starting to manage some of our ECS services using compose through ECS CLI.

Using docker compose is a much more familiar way of managing docker services for the end user. It abstracts all the process of Task Definition creation and Service Definition creation. For example, you can have your services definition tied to your application code in the same repository, and in a format that is pretty familiar for the docker user, especially if you’re using docker and compose for development.

Until now, one thing that ECS CLI didn’t allow you to do, was to associate an Elastic Load Balancer(classic or application) with your service upon creation.

This was a real show stopper for us, as the use of the tool was limited to services that didn’t serve HTTP, for example message queues or background processes but not web services.

This is why we decided to add some support to it, contributing the necessary code that allows us to assign an Elastic Load Balancer or an Application Load Balancer to a Service on service creation. The beauty of open source software.

Pattern for HTTP services using docker containers in AWS

If you want to run your application in ECS you must first choose what method you want to use to allow these containers to be reachable. Fortunately, AWS provides you, with the necessary building blocks that you’ll need to discover your apps running inside ECS.

There are two types of Load Balancers in AWS, the Classic Load Balancer and the Application Load Balancer. One component of an ALB is the Target Group, which is used to register EC2 instances to route requests to them.

In AWS the recommended service discovery pattern, is implemented by registering containers, started in Tasks, against the Service’s Load Balancer or Target Group.

You tell AWS to associate a Service with a Load Balancer if you are using a Classic Load Balancer (ELB) or a Target Group if you are using an Application Load Balancer (ALB), and when your task starts, it automatically registers the assigned port to the Load Balancer or Target Group.

Example Service registered to a Target Group

Example Service registered to a Classic Load Balancer

This pattern is shown in the diagram bellow

This allows your HTTP request to be distributed evenly between all the containers running your app.

In this pattern, the responsibility of the service registration is delegated to ECS, making your application completely agnostic to the platform from where it’s running.

New ecs-cli ELB/ALB params

You must associate an ALB to an ECS service definition at creation time, and it cannot be changed afterwards.

ECS CLI provides some new params that allows you to assign a Load Balancer when creating the service.

To assign an ALB to the service now you can set the following params:

  • --target-group-arn: The full Amazon Resource Name (ARN) of the Elastic Load Balancing target group associated with a service.
  • --load-balancer-name: The name of the classic load balancer.
  • --container-name: The name of the container (as it appears in a container definition) to associate with the load balancer.
  • --container-port: The port on the container to associate with the load balancer. This port must correspond to a containerPort in the service's task definition. Your container instances must allow ingress traffic on the hostPort of the port mapping.
  • --role: The name or full Amazon Resource Name (ARN) of the IAM role that allows Amazon ECS to make calls to your load balancer on your behalf. This parameter is required if you are using a load balancer with your service. If you specify the role parameter, you must also specify a load balancer object with the loadBalancers parameter.

These are the new params that we added to ECS CLI compose service to allow the association of a Load Balancer.

In the following section we will show you the steps needed to create a service.

Steps needed to register your compose defined service with an ALB

The first step is to configure it to work with our AWS environment.

If you have correctly completed the setup of your AWS credentials (recommended) as described in http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html you’re ready to start using ECS CLI and the Amazon AWS command line interface.

Starting with an example compose file that models an HTTP service with a memcached instance, job processing queues and your application running in port 3000.

NOTE: All values are fake, you must indicate the correct values for the service and the AWS account.

First you need to create an Application Load Balancer (ALB) that will be used to serve your application to the outside world:

$ aws elbv2 create-load-balancer --name my-load-balancer  \ --subnets subnet-12345678 subnet-23456789 --security-groups sg-12345678arn:aws:elasticloadbalancing:eu-west-1:123456789012:loadbalancer/app/my-load-balancer/1234567890123456

Create a target group

$ aws elbv2 create-target-group --name my-targets --protocol HTTP --port 80 \ --vpc-id vpc-12345678arn:aws:elasticloadbalancing:eu-west-1:123456789012:targetgroup/my-targets/1234567890123456

Register your target group with the ALB

$ aws elbv2 register-targets --target-group-arn targetgroup-arn  \ --targets Id=i-12345678 Id=i-23456789

We’re ready to create our service in ECS.

The first step is to configure your ECS CLI environment to point to the desired region and ECS cluster.

$ ecs-cli configure --region eu-west-1 --cluster my-cluster

Then, create a service in ECS that runs your application defined in the compose file, passing the target group ARN, that you want your service to associate with.

$ ecs-cli compose --file docker-compose.yml service up \
--deployment-min-healthy-percent 0 \
--target-group-arn
arn:aws:elasticloadbalancing:eu-west-1:123456789012:targetgroup/my-targets/1234567890123456 \
--container-name app \
--container-port 3000 \
--role ecsServiceRole

Follow the output of this command and after a while you should have your service running in your configured cluster.

Log in to the AWS console, and observe if the generated task is already running in the service.

You must be able to access your service via the Load Balancer URL. Since this URL is difficult to remember, you can use Route53 to create a handy URL for your service in the form of: myservice.mydomain.com

To scale your service use:

$ ecs-cli compose service scale 6

The number of tasks running should increase and be up in your service within a few moments, and the requests to the service URL should be balanced between all running instances.

Conclusion

ECS is able to run docker containers in production and can be quite reliable, AWS offers you the building blocks needed to operate your services in production and have all the pieces required to build the complete container lifecycle.

It implements a server-side service discovery pattern. And even though there are some tradeoffs (as with everything else), we do like that it actually is quite platform agnostic.

We presented a method to setup and scale a web service in ECS that can be fully managed by using the docker compose and the ECS CLI tool and that covers any type of docker app, including HTTP services.

We hope that this information will help you get a better understanding on how ECS works and make your life easier when working with the AWS ecosystem.

Thanks to Sergio Espeja, David Gonzalez and Jorge Quintás for reviews and comments, Ximena Guzman for language corrections, and David de la Iglesia for the beautiful diagram.

We are hiring!

If you want to know more about how is work at Jobandtalent you can read the first impressions of some of our teammates on this blog post or visit our twitter.

--

--

http://dkron.io author, Ruby, Go, ops, distributed systems and crypto things. Also synths and Filipino Martial Arts