I have multiple Docker containers that I’d like to put behind a single Application Load Balancer in AWS. The containers run in EC2 ECS, not Fargate, for cost. I’m able to do this in CloudFormation, but so far I can’t figure out the secret incantation to have CDK do what I’m trying to do.
Each service has a Target Group and a Listener Rule, the Rule looks for a specific sub-domain to do the routing appropriately.
Here’s what works in CloudFormation:
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
TargetType: "instance"
VpcId: !Ref VpcId
Port: !Ref DashboardContainerPort
Protocol: HTTP
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: "10"
Matcher:
HttpCode: 200-499
Name: !Ref DashboardServiceName
HealthCheckPath: /
HealthCheckProtocol: HTTP
HealthCheckIntervalSeconds: 130
HealthCheckTimeoutSeconds: 120
HealthyThresholdCount: 2
UnhealthyThresholdCount: 3
Service:
Type: AWS::ECS::Service
DependsOn: HttpsListenerRule
Properties:
ServiceName: !Ref DashboardServiceName
Cluster: !Ref Cluster
DesiredCount: !Ref DesiredCount
TaskDefinition: !Ref TaskDefinition
LaunchType: "EC2"
LoadBalancers:
- ContainerName: !Ref DashboardServiceName
ContainerPort: !Ref DashboardContainerPort
TargetGroupArn: !Ref TargetGroup
Tags:
- Key: Service
Value: !Ref DashboardServiceName
The Target Group is mapped to a Listener on the ALB with a Listener rule.
Here’s what’s not working in CDK:
service = ecs.Ec2Service(
self,
f"ECS-Service-{dash_name}",
cluster=cluster,
task_definition=task_definition,
)
self._add_autoscaling(service)
service.connections.allow_from(load_balancer, ec2.Port.tcp(3838))
load_balancer.connections.allow_to(service, ec2.Port.tcp(3838))
target_group = elbv2.ApplicationTargetGroup(
self,
f"{dash_name}-targetgroup",
port=3838,
protocol=elbv2.ApplicationProtocol.HTTP,
vpc=cluster.vpc,
)
listener443.add_target_groups(
f"{dash_name}-listener-rule",
target_groups=[target_group],
conditions=[
elbv2.ListenerCondition.host_headers(
[f"{dash_name}.dashboards.targetsmart.com"]
),
],
priority=x,
)
service.attach_to_application_target_group(target_group)
The CDK documentation says not to use service.attach_to_application_target_group
, so, ok, but how can I cajole CDK to do what I’m trying to get it to do?
Right now, I can see the tasks register themselves as targets in the Target Group, but no matter what I do in the Console with the Security Group or the Health Checks, the Tasks fail the health check and are terminated in a loop till the entire deployment fails. I’ve downloaded and run the containers locally and they seem fine.
I feel like I’m very close to finishing this project. If I can work out this last bit, I think I’ll have it. What’s the right way to do this? Any pointers in the right direction are appreciated.
2
Answers
You know, every time I think "oh it can't be the security group", it's the security group. In the code above I was attempting to add a security group to the service, which is wrong for EC2 ECS clusters. I needed to add the security group to the autoscaling group.
Also, my application takes a while to start, so I also needed to update the load balancer's health checks:
I hope this helps if anyone else has the same problem down the road. Or, just as likely, if I have the same problem down the road.
Here’s how I did it on my project.
In your case, you can try this:
service.load_balancer_target
return anIEcsLoadBalancerTarget
which is anIApplicationLoadBalancerTarget