ECS's level of indirection, console magic and naming overloads ("service is valid for ECS and ALBs) can often be difficult to understand.
Ultimately, the configuration I think you're looking for is here in the ECS service definition.
When you define your ECS definition, you can the target group you wish to use,
like so:
const svcA = new aws.ecs.Service("example-A", {
cluster: cluster.arn,
desiredCount: 1,
launchType: "FARGATE",
taskDefinition: taskDefinition.arn,
networkConfiguration: {
assignPublicIp: true,
subnets: subnets.ids,
securityGroups: [ securityGroup.id ]
},
loadBalancers: [{
targetGroupArn: targetGroupA.arn,
containerName: "my-app",
containerPort: 80,
}]
})
Note the loadBalancers
object defined there.
You can then define multiple services and point them at whichever target group you like. Here, we can define a loadbalancer with two listeners and target groups:
// define a loadbalancer
const lb = new aws.lb.LoadBalancer("example", {
securityGroups: [securityGroup.id],
subnets: subnets.ids,
});
// target group for port 80
const targetGroupA = new aws.lb.TargetGroup("example-A", {
port: 80,
protocol: "HTTP",
targetType: "ip",
vpcId: vpc.id,
});
// listener for port 80
const listenerA = new aws.lb.Listener("example-A", {
loadBalancerArn: lb.arn,
port: 80,
defaultActions: [
{
type: "forward",
targetGroupArn: targetGroupA.arn,
},
],
});
// target group for port 8080
const targetGroupB = new aws.lb.TargetGroup("example-B", {
port: 8080,
protocol: "HTTP",
targetType: "ip",
vpcId: vpc.id,
});
// listener for port 8080
const listenerB = new aws.lb.Listener("example-B", {
loadBalancerArn: lb.arn,
port: 8080,
defaultActions: [
{
type: "forward",
targetGroupArn: targetGroupB.arn,
},
],
});
And then define two distinct services that point to different target groups:
// service listening on port 80
const svcA = new aws.ecs.Service("example-A", {
cluster: cluster.arn,
desiredCount: 1,
launchType: "FARGATE",
taskDefinition: taskDefinition.arn,
networkConfiguration: {
assignPublicIp: true,
subnets: subnets.ids,
securityGroups: [securityGroup.id],
},
loadBalancers: [
{
targetGroupArn: targetGroupA.arn,
containerName: "my-app",
containerPort: 80,
},
],
});
// service listening on port 8080
const svcB = new aws.ecs.Service("example-B", {
cluster: cluster.arn,
desiredCount: 1,
launchType: "FARGATE",
taskDefinition: taskDefinition.arn,
networkConfiguration: {
assignPublicIp: true,
subnets: subnets.ids,
securityGroups: [securityGroup.id],
},
loadBalancers: [
{
targetGroupArn: targetGroupB.arn,
containerName: "my-app",
containerPort: 80,
},
],
});
You can find a full end to end example of how this looks here