15

I have service that exposes multiple ports and it worked fine with kubernetes but now we move it to AWS ECS. It seems I can only expose ports via Load Balancer and I am limited to 1 port per service/tasks even when docker defines multiple ports I have to choose one port

enter image description here

Add to load balancer button allows to add one port. Once added there is no button to add second port.

Is there any nicer workarround than making second proxy service to expose second port?

UPDATE: I use fargate based service.

Mohammad Moallemi
  • 628
  • 1
  • 5
  • 13
user3130782
  • 841
  • 1
  • 6
  • 15
  • 1
    Do you want to route the requests from the same target group to this service? – mohit Sep 03 '19 at 19:46
  • I wished service to expose 80 and 443 ports and point load balancer at these ports. Otherwise I need extra service to duplicate port 80 that is redirect to 443. – user3130782 Sep 04 '19 at 11:09
  • You can do it. It doesn't actually matter what is the port of your container if you are using dynamic host ports. Also, It is required to keep both ports different because you want to do it in one ECS service. Kindly follow my answer to achieve your goal. – mohit Sep 04 '19 at 16:21

5 Answers5

15

You don't need any workaround, AWS ECS now supports multiple target groups within the same ECS service. This will be helpful for the use-cases where you wanted to expose multiple ports of the containers.

Currently, 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.

For example, A Jenkins container might expose port 8080 for the Jenkins web interface and port 50000 for the API.

Ref:

https://docs.aws.amazon.com/AmazonECS/latest/developerguide/register-multiple-targetgroups.html

https://aws.amazon.com/about-aws/whats-new/2019/07/amazon-ecs-services-now-support-multiple-load-balancer-target-groups/

mohit
  • 2,325
  • 23
  • 48
  • 1
    This does not work for ECS blue/green deployments, only rolling updates. See [here](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/register-multiple-targetgroups.html) under the "Multiple Target Group Considerations" – forrestmid May 26 '21 at 03:26
9

Update: I was able to configure target group using Terraform but did not find so far this option on AWS console.

resource "aws_ecs_service" "multiple_target_example" {
  name            = "multiple_target_example1"
  cluster         = "${aws_ecs_cluster.main.id}"
  task_definition = "${aws_ecs_task_definition.with_lb_changes.arn}"
  desired_count   = 1
  iam_role        = "${aws_iam_role.ecs_service.name}"

  load_balancer {
    target_group_arn = "${aws_lb_target_group.target2.id}"
    container_name   = "ghost"
    container_port   = "3000"
  }

  load_balancer {
    target_group_arn = "${aws_lb_target_group.target2.id}"
    container_name   = "ghost"
    container_port   = "3001"
  }

  depends_on = [
    "aws_iam_role_policy.ecs_service",
  ]
}

Version note: Multiple load_balancer configuration block support was added in Terraform AWS Provider version 2.22.0.

ecs_service_terraform

I can't say that this will be a nice workaround but I was working on a project where I need to run Ejabberd using AWS ECS but the same issue happened when its come to bind port of the service to the load balancer.

I was working with terraform and due to this limitation of AWS ECS, we agree to run one container per instance to resolve the port issue as we were supposed to expose two port.

If you do not want to assign a dynamic port to your container and you want to run one container per instance then the solution will definitely work.

  1. Create a target group and specify the second port of the container.

  2. Go to the AutoScalingGroups of your ECS cluster

  3. Edit and add the newly created target group of in the Autoscaling group of the ECS cluster

So if you scale to two containers it's mean there will be two instances so the newly launch instance will register to the second target group and Autoscaling group take care of it. This approach working fine in my case, but few things need to be consider.

Do not bind the primary port in target, better to bind primary port in ALB service. The main advantage of this approach will be that if your container failed to respond to AWS health check the container will be restart automatically. As the target groupe health check will not recreate your container.

This approach will not work when there is dynamic port expose in Docker container.

AWS should update its ECS agent to handle such scenario.

Adiii
  • 54,482
  • 7
  • 145
  • 148
6

I have faced this issue while creating more than one container per instances and second container was not coming up because it was using the same port defined in the taskdefinition.

What we did was, Created an Application Load balancer on top of these containers and removed hardcoded ports. What application load balancer does when it doesn't get predefined ports under it is, Use the functionality of dynamic port mapping. Containers will come up on random ports and reside in one target group and the load balancer will automatically send the request to these ports.

More details can be found here

Pacifist
  • 3,025
  • 2
  • 12
  • 20
1

Thanks to mohit's answer, I used AWS CLI to register multiple target groups (multiple ports) into one ECS service:

ecs-sample-service.json

{
    "serviceName": "sample-service",
    "taskDefinition": "sample-task",
    "loadBalancers":[
      {  
         "targetGroupArn":"arn:aws:elasticloadbalancing:us-west-2:0000000000:targetgroup/sample-target-group/00000000000000",
         "containerName":"faktory",
         "containerPort":7419
      },
      {  
         "targetGroupArn":"arn:aws:elasticloadbalancing:us-west-2:0000000000:targetgroup/sample-target-group-web/11111111111111",
         "containerName":"faktory",
         "containerPort":7420
      }
   ],
    "desiredCount": 1
}
aws ecs create-service --cluster sample-cluster --service-name sample-service --cli-input-json file://ecs-sample-service.json --network-configuration "awsvpcConfiguration={subnets=[subnet-0000000000000],securityGroups=[sg-00000000000000],assignPublicIp=ENABLED}" --launch-type FARGATE
  1. If the task needs internet access to pull image, make sure subnet-0000000000000 has internet access.
  2. Security group sg-00000000000000 needs to give relevant ports inbound access. (in this case, 7419 and 7420).
  3. If the traffic only comes from ALB, the task does not need public IP. Then assignPublicIp can be false.
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/32321554) – Stephen Taylor Jul 30 '22 at 18:27
  • 1
    This answers the OP's question; OP wanted to expose multiple ports with ECS service, but it's impossible with the UI. My answer shows how to do it with AWS CLI – Richard Chou Jul 31 '22 at 02:51
0

Usually, I use the AWS CLI method itself by creating task def, target groups and attaching them to the application load balancer. But the issue is that when there is multiple services to be done this is a time-consuming task so I would use terraform to create such services

terraform module link This is a multiport ECS service with Fargate deployment. currently, this supports only 2 ports. when using multiports with sockets this socket won't be sending any response so the health check might fail. so to fix that I would override the port in the target group to other ports and fix that.

hope this helps