Skip to content

Instantly share code, notes, and snippets.

@nathanpeck
Last active July 22, 2020 19:01
Show Gist options
  • Save nathanpeck/a8537e21627b3a0f3e735eecbe6f6384 to your computer and use it in GitHub Desktop.
Save nathanpeck/a8537e21627b3a0f3e735eecbe6f6384 to your computer and use it in GitHub Desktop.

The information below was written in Oct 2017. In August 2019 AWS launched official support for multiple target groups per AWS ECS service. Please use that feature instead!


Unfortunately as of writing this (Oct 18, 2017) there is no built in integration for multiple target groups per AWS ECS service. Here are a few things you can try:

  1. If your application just serves port 80 (HTTP) & port 443 (HTTPS) then you should consider using the application load balancer and terminating SSL at the load balancer. This will allow your application to function using just port 80.

  2. If your application serves different ports that are backed by different components, perhaps speaking different protocols then you should consider splitting the application into multiple ECS services. This has the benefit of allowing the different components to independently scale in addition to allowing each of them to have their own ports.

  3. You can still use the Classic load balancer with ECS. This load balancer functions at the instance level, and can have multiple listener ports per instance, so when a service is put on an instance ECS will register the instance in the classic load balancer, and the classic load balancer will have multiple listeners directing traffic to multiple ports. This has the downside of not supporting dynamic ports though, only static port numbers. This means you will only be able to run a single task per instance, because only one task will be able to bind to the static port.

  4. You can build your own target group functionality for your application's ancillary ports using the CloudWatch Event Stream for your service's task state change events. You can subscribe to the task state change events for your service, and link the subscription to a Lambda function. When the event for a task start happens you can register your tasks ancillary ports in any ancillary target groups, and when the task stop event happens you can deregister these ancillary ports. Obviouslly this is a very complex, and difficult solution to implement however, so I'd only use it as a method of last resort.

  5. You can use Weaveworks, or LinkerD to implement a mesh network that runs alongside ECS. This can allow you to build a "gateway" that sends traffic to your ECS services on multiple ports without using the built in target group functionality.

@deepanprabhu
Copy link

deepanprabhu commented Jun 19, 2018

Thank you, this was a blocker for us and your valuable comments really saved us hours of research !

@broglep-work
Copy link

broglep-work commented Nov 9, 2018

@mattdttusa
Copy link

mattdttusa commented Jan 31, 2019

import json
import boto3

def lambda_handler(event, context):
    TARGET_GROUP_ARN = 'arngoeshere'
    DEST_TARGET_GROUP_ARN = 'arngoeshere'
    client = boto3.client('elbv2')
    #remove all targets from the destination target group
    targets = client.describe_target_health(TargetGroupArn=DEST_TARGET_GROUP_ARN)
    for id in targets['TargetHealthDescriptions']:
        identity =  id['Target']['Id']
        response = `client.deregister_targets(TargetGroupArn=DEST_TARGET_GROUP_ARN,Targets=[{'Id':` identity}])
    

    #add them back into the second  by ip from the first target group
    targets = client.describe_target_health(TargetGroupArn=TARGET_GROUP_ARN)
    for id in targets['TargetHealthDescriptions']:
        identity =  id['Target']['Id']
        response = client.register_targets(TargetGroupArn=DEST_TARGET_GROUP_ARN,Targets=[{'Id': identity}])
    
    
    return {
        'statusCode': 200,
        'body': json.dumps(targets)
    }

@karlschriek
Copy link

This probably wasn't the case when you originally posted this, but (at least when using Fargate, not sure if this would work for EC2) it seems this can now be configured quite easily. See https://aws.amazon.com/blogs/compute/task-networking-in-aws-fargate/.

If you wish to expose multiple ports, just add multiple port mappings to the container definition, e.g:

...
"portMappings": [
        {
          "containerPort": 80
        },
        {
          "containerPort": 443 
        }
      ],
...

@philmath-pea
Copy link

You may expose as many ports as you like via portMappings but that still doesn't solve the problem of using "multiple target groups per AWS ECS service" when you have a load balancer in front of your services. So, it's still an issue.

I have a container than needs to have many different ports open. I think I have to spin up a new service for every different port I plan to forward from the ALB.

@isuftin
Copy link

isuftin commented Mar 4, 2019

I have the same issue. I am trying to cluster Hashicorp Vault behind a Network Load Balancer. I need my cluster to be available via ports 8200 and 8201. This is currently not workable for me.

@maradwan
Copy link

maradwan commented Apr 5, 2019

you need to remove two -> in this line response =client.deregister_targets(TargetGroupArn=DEST_TARGET_GROUP_ARN,Targets=[{'Id':` identity}])
Thanks Mattdttusa

@paul-cureton
Copy link

This will create a lambda that replicates changes from one target group to another. It will only work with awsvpc containers and ip target groups: https://gist.github.com/arpaulnet/b523e8388397ce1b2a900389c48263a7

@Yanzilla
Copy link

Yanzilla commented Aug 1, 2019

@nathanpeck
Copy link
Author

Thanks @Yanzilla. I forgot about this old gist! I updated the content to add a reference to the new feature :)

@iamsaurabhrai
Copy link

How we can implement blue/green deployment with this approach, Because codeDeploy still not supports multiple target groups.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment