ALB, Amazon aws, ECS

AWS Application Load Balancer and Amazon ECS using dynamic port mapping

This week I want to talk about ALB and ECS integration. As you know, recently AWS announced their new load balancing service, Application Load Balancer (ALB). ALB supports more advanced features than ELB with a lower cost. I won’t explain each of these features but, you can refer to this documentation to get more details about it. The new features are basically about:

  • Content-Based routing
  • Container-based Application Support ( Today I’ll give an example about this )
  • HTTP/2 Support
  • Websockets Support
  • Sticky Sessions
  • Better CloudWatch Metrics

As I mentioned, I want to show how we can use our dockerized applications with ALB. We will use following architecture that is shown below. As you see there are our webpage and blog page. These two applications will listen on different ports and will run on a ECS cluster. Our docker images will be stored in AWS ECS Registry. Also our ALB will use port 80 and will forward our request to backend using dynamic port mapping feature.

alb-arch

Our step for this demo:

  1. Create Docker images
  2. Create registry and push our images to it. (I’ll use AWS ECS Registry)
  3. Create our task definitions
  4. Create ALB
  5. Run services

Let’s start by creating our images.

1 – Create Docker images:

As you see, our blog container will run a basic flask app which listens on port 8080 and the application will be reached by using “/blog” path. I’ll use this Dockerfile and create my image. Also we’ll have webpage container as well ( It has another Dockerfile. Only differences will be the port number (5000) and the path (“/”) )
Dockerfile:

FROM centos

MAINTAINER salk.onur@gmail.com

RUN rpm -Uvh http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-8.noarch.rpm \
      && yum update -y \
      && yum install -y python-pip \
      && pip install flask

COPY . /src

EXPOSE 8080

CMD cd /src && python blog.py

Application code, blog.py:

from flask import Flask
from flask import render_template

app = Flask(__name__)

@app.route('/blog')
def blog():
    return render_template('blog.html',title='blog')


if __name__ == '__main__':
    app.run(threaded=True,host='0.0.0.0',port=8080)

Now I can create my images using the commands below:

docker build -t osalkk-alb-demo-blog .
docker build -t osalkk-alb-demo-web .

2 – Create registry and push our images to it:

Now I switch to AWS console and create my ECS registry as seen in the screenshot. ( This is only for blog image, for the web image the steps are the same )
osalkk-alb-demo-blog

 

In the next step, I get help from “push commands” that AWS console shows us. First, I retrieve “docker login” output by using the command below. This will show a long command that will help us login to the registry.

aws ecr get-login --region eu-central-1

I use the “docker login” command:

docker login -u AWS -p AQECAHh3zYOdtpBBSVw/.... -e none https://130575395405.dkr.ecr.eu-central-1.amazonaws.com

I tag my image:

docker tag osalkk-alb-demo-blog:latest 130575395405.dkr.ecr.eu-central-1.amazonaws.com/osalkk-alb-demo-blog:latest

Finally, I push my image to AWS ECS Registry

docker push 130575395405.dkr.ecr.eu-central-1.amazonaws.com/osalkk-alb-demo-blog:latest

As we see, our images are stored in our repository.alb-image

3 – Create our task definitions:

Now it’s time to create our tasks and services. In ECS console, I click “Create task definition” and proceed.

blog-task

I give “Blog-task” name for my task and click “Add Container”. I complete the form as below. I leave the host port empty since we want it to be dynamically mapped. For the blog container I use 8080 and for the web  I use 5000 as port number. Then I click “Add” and “Create” to complete the task creation.

add-container

Before creating our services, we need to create our ALB.

Bion Consulting

4- Create ALB:

We are ready to create our ALB now. Let’s start by choosing Application Load Balancer

create-alb

 

I name it as “ALB-Test” and choose my available subnets.

 

configure-loadbalancer

I select my security group

alb-sec

Now I have to configure the routings for my ALB. Here I add a new targeting group.  Remember that,  I use the port number as 8080 and the path as “/blog”.

alb-route

Since ECS will register targets, we don’t need to register instances manually. After that, we can review and finish creating our ALB.

alb-register

Our next step is creating a new target group for web and adding a rule for it. Here I select 5000 as port number and  “/” as the path.

alb-web-targetThen I select my ALB and edit the rules.   I add another rule and enter “/blog” as path pattern and “Blog-TG” as target group name( Previously, I had configured the “Blog-TG” so it was default. I edited it as “Web-TG”, don’t be confused with that ).

alb-add-rule

We can proceed with running our services and test our applications.

5 – Run Services:

We can now jump to the ECS console and configure our cluster and services.

I create a new cluster as “ALB-Demo”.

create-cluster

 

We need to launch instances for our ECS cluster. Here I won’t explain how to create autoscaling group and launching ECS instances ( If you need, you can refer here). I have already had an auto scaling group and a launch configuration. I copy it and change the user-data so it can register instances with my ECS Cluster.

alb-lc

Then I edit my autoscaling group and select my new launch configuration, set the desired to 2 and save.

autoscale

After a while, my instances are registered in my cluster. Now let’s configure the services. Here I select my task definition, set the number of tasks to 2 and click “Configure ELB”.

create-service

At ELB screen, I select “ALB-Test” as ELB and select “Web-TG” as target group name ( all other fields are populated as I select ). Then I finish creating the service. Also I make the same steps for blog service.

service-elb

As soon as the tasks are running, I can test my ALB and the applications.

service-running

You can also view the dynamic port mapping if you check a task detail. As seen below, port number “32769” is assigned as host port for a web task.

 

dynamicport

Finally let’s see if our applications are running. Here are the results both for “/” and “/blog” paths.

routepathblogpath

 

As you can see, configuring ALB with container-based applications is easy. I hope you find this post useful. If you have any questions or comments, please feel free to write and don’t forget to share this post please.

 

Onur SALK

AWS Cloud & DevOps Consultant, AWS Certified Solutions Architect, AWS Community Hero

More Posts - Website

Follow Me:
TwitterFacebookLinkedIn

20 thoughts on “AWS Application Load Balancer and Amazon ECS using dynamic port mapping

  1. Hi. I have a question. Is it possible to configure ALB and auto scaling the next way: there is a web application and it’s components organized like microservices, each of them is on different port. For example, we have 3 components: c1, c2 and c3. c1, c2 and c3 are in different target group and on different ports, with different path(like you have in your example). At first we have only one EC2 with all components running on it, but we need to add more if one of the components overloaded and instance run out of memory/cpu. How should i configure autoscale to scale them correctly? i mean, can i alert when c1 overloaded end EC2 run out of cpu and add one more EC2 instance? perhaps maybe, some how. Now we have two EC2 instances running: on first all containers and on second only c1. But when c2 is also overloaded, we don’t need to add another EC2 instance, we should run c2 on second EC2 instance(if c1 is not using all instance’s resources).
    I don’t now how should i configure ALB and autoscaling to have behaviour i’ve described: not to launch new EC2 instance for every overloaded microservice, but use existing one. Is it possible?

  2. Best tutorial, even better than aws official tutorial. Thank you for your effort. the default path / worked for me but not the /blog path. i used only one instance. i ran two services. one container in the service use port 80 as container port and one container in another service use port 443 as container port. the services are running but when i checked the target in its group, it says no instance are healthy. it keeps failing and dynamic host port is continuosly alloted to it. help me please.

    1. Hi Karthik,

      Thanks for your good feedback!
      Can it be a security group issue? Or an issue with target group routing? Did you configure your routing and selected HTTPS for your protocol?

      1. instances are healthy. the default path is working absolutely fine. hitting the load balancer url can route the request to default path(the first container can run) but the rule created as /blog doesnt route to the second service(the container can run). i get 404 error.

  3. Great blog btw, this was really useful. Let me ask one question however around dynamic port allocation.ALB supports only HTTP and HTTPs, However if we want access to the containers via SSH (TCP 22) then we are stuck with an ephermeral port issue that the load balancer cant mitigate for us. Have you face similar challenges and can you suggest a good work around ?

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.