Let’s start with a couple of statements:

  • Amazon Elastic Container Service (Amazon ECS) is a highly scalable, high-performance container orchestration service that supports Docker containers and allows you to easily run and scale containerized applications on AWS.
  • AWS Fargate is a compute engine for Amazon ECS that allows you to run containers without having to manage servers or clusters. With AWS Fargate, you no longer have to provision, configure, and scale clusters of virtual machines to run containers. This removes the need to choose server types, decide when to scale your clusters, or optimize cluster packing. AWS Fargate removes the need for you to interact with or think about servers or clusters.

If you aren’t sure when to use ECS with a Fargate or an EC2 model, then the quick rule of thumb to be applied is:

  • EC2 for large constant workloads.
  • Fargate for small, batch or occasional burst workloads.

Hopefully by now you are well on your way to refactoring any monolithic EC2 instance applications onto a new microservices architecture utilising containers on ECS and possibly Fargate.

Testing your new microservices has been going well and now you want to extend its reachability to outside your AWS account. This could be access over the internet or a Private link (Private links are great for secure SaaS connectivity) to a verified 3rd party’s AWS account.

However, you don’t want to create a new service for each load balancer, and why would you. You already have an internal load balancer connected to a target group that is registered to your ECS service within a Cluster running your tasks according to your task definition utilizing Fargate. As that was a bit of a mouthful so let’s see that in a simple diagram.

For simplicity I’ve captured the ECS Cluster, Service and Task within the “Fargate task”. The descriptions of the inner working will be a topic for another blog post

This topology allows:

  • Inbound internal traffic via your internal ALB.
  • External outbound traffic via your NAT gateway.

As per the subject of this post it does not yet allow any external inbound connectivity. To enable this, we need to:

  • Create a new external ALB
  • Associate the Target Group with the Fargate task ENI.

This will then give us a target topology as below:

Great we can now see what we need. Creating the ALB is a simple task, however it’s not possible to connect the external load balancers target group to an existing cluster, you can’t even create a new cluster and associate more than one Target Group within the AWS console. Try it, it’s just not possible.

AWS do state that your Amazon ECS service can serve traffic from multiple load balancers and expose multiple load balanced ports when you specify multiple target groups in a service definition. But…. If you want to create a service specifying multiple target groups, you must create the service using the Amazon ECS API, SDK, AWS CLI, or an AWS CloudFormation template. After the service is created, you can view the service and the target groups registered to it with the AWS Management Console. Just like this:

OK so we just jumped to the end of this story, lets rewind a little and take stock of what AWS are telling us (I’ve bolded the salient points):

  • Your Amazon ECS service can serve traffic from multiple load balancers.
  • If you want to create a service specifying multiple target groups, you must create the service using the Amazon ECS API, SDK, AWS CLI, or an AWS CloudFormation template.

I’ll assume you know how know to set up an external ALB and associate a Target Group to it. However, this time don’t add any listeners as this task is taken care of when the Target Group is associated to the service.

For my example I’m going to show you how to take the configuration from your existing ECS setup and create a new service via the Python Boto3 SDK.

Create an instance with Python 3.x installed with boto3, even better run as a Jupyter notebook and execute the following Python code to get a list of your existing clusters (replacing <region> with your region):

import boto3
session = boto3.Session(region_name="<region>")
ecs = session.client('ecs')
ecslist = ecs.list_clusters()
for cluster in ecslist['clusterArns']:
    print (cluster)

Find the existing Cluster ARN you are interested in and your existing Service Name and issue the command below:


You will now receive the JSON output of your current service which you then need for the next command. Remember you are creating a new service, so use a new name for <new-servicename>. All variables below within <> need to be updated:

            'targetGroupArn': ‘<internal-loadbalancer-arn>’,
            'containerName': '<Task definition>',
            'containerPort': <port>
            'targetGroupArn': ‘<externall-loadbalancer-arn>’,
            'containerName': '<Task definition>',
            'containerPort': <port>
        'maximumPercent': 200,
        'minimumHealthyPercent': 100
    networkConfiguration={'awsvpcConfiguration': {'subnets': ['<subnet-id1>',
     'securityGroups': ['<sg-id>'],
     'assignPublicIp': 'DISABLED'

If you have entered all your variables correctly then it should echo the full JSON of the configuration without error. The AWS console will now reflect these changes as per the earlier snip.

Now delete your old service (with just the single internal load balancer) and you’ll have a brand-new service that allows internal and external connectivity at the same time using the two load balancers.

No responses yet

Leave a Reply

Your email address will not be published. Required fields are marked *

November 2019