Skip to content

AWS ECS: UDP-only service not allowed to attach to NetworkTargetGroup #23026

@ssko1

Description

@ssko1

Describe the bug

I cannot attach a UDP-only EC2 Service to a NetworkTargetGroup via the function attachToNetworkTargetGroup.

When I define a UDP and TCP container, defining the UDP port mapping first, I cannot attach the EC2 Service to a NetworkTargetGroup.

Expected Behavior

I am able to attach a UDP-only Ec2Service to a NetworkTargetGroup.

Current Behavior

CDK fails with the following error:

Error: Container 'HelloCdkStack/TaskDefinition/Container' has no mapping for port undefined and protocol tcp. Did you call "container.addPortMappings()"?

Reproduction Steps

Using the sample application from the cdk CLI:

  1. Create the sample application
mkdir hello-cdk
cd hello-cdk
cdk init sample-app --language=typescript
  1. Replace the code in lib/hello-cdk-stack.ts with the code below
  2. npm run build && cdk synth, you should expect to see an error. Please test with various other use cases commented out in the code.
import { aws_ecs, Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { NetworkTargetGroup, Protocol, TargetType } from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { Cluster, Compatibility, ContainerImage, Ec2Service, NetworkMode, TaskDefinition } from 'aws-cdk-lib/aws-ecs';
import { Repository } from 'aws-cdk-lib/aws-ecr';
import { InstanceClass, InstanceSize, InstanceType, Vpc } from 'aws-cdk-lib/aws-ec2';

export class HelloCdkStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const vpc = new Vpc(this, 'Vpc', {})

    const tg = new NetworkTargetGroup(this, 'TargetGroup', {
      port: 8125,
      protocol: Protocol.UDP,
      vpc: vpc,
      targetType: TargetType.INSTANCE,
    })

    const taskDefinition = new TaskDefinition(this, 'TaskDefinition', {
      compatibility: Compatibility.EC2,
      networkMode: NetworkMode.BRIDGE,
    })

    const cluster = new Cluster(this, 'Cluster', {})
    cluster.addCapacity('Cap', {
      instanceType: InstanceType.of(InstanceClass.M5, InstanceSize.SMALL)

    })

    const image = ContainerImage.fromEcrRepository(Repository.fromRepositoryName(this, 'Rep', 'Foobar'), 'Foobar')

    /* This task definition is our "base case": a TaskDefinition container that does not use UDP and passes `cdk synth` */
    // taskDefinition.addContainer('Container', {
    //   portMappings: [
    //     {
    //       containerPort: 8125,
    //       protocol: aws_ecs.Protocol.TCP,
    //     }
    //   ],
    //   memoryReservationMiB: 123,
    //   image: image
    // })

    /*
      This task definition container produces the following error:

    Error: Container 'HelloCdkStack/TaskDefinition/Container' has no mapping for port undefined and protocol tcp. Did you call "container.addPortMappings()"?
     */
    taskDefinition.addContainer('Container', {
      portMappings: [
        {
          containerPort: 8125,
          protocol: aws_ecs.Protocol.UDP,
        }
      ],
      memoryReservationMiB: 123,
      image: image
    })

    /*
    * This TaskDefinition defines both UDP and TCP port mappings, but with the UDP port defined first. This fails for the same
    * reason above.
    */
    // taskDefinition.addContainer('Container', {
    //   portMappings: [
    //     {
    //       containerPort: 8125,
    //       protocol: aws_ecs.Protocol.UDP,
    //     },
    //     {
    //       containerPort: 8080,
    //       protocol: aws_ecs.Protocol.TCP
    //     }
    //   ],
    //   memoryReservationMiB: 123,
    //   image: image
    // })

    /* This TaskDefinition defines both UDP and TCP port mappings, but with the TCP port defined first. This passes `cdk synth` */
    // taskDefinition.addContainer('Container', {
    //   portMappings: [
    //     {
    //       containerPort: 8080,
    //       protocol: aws_ecs.Protocol.TCP
    //     },
    //     {
    //       containerPort: 8125,
    //       protocol: aws_ecs.Protocol.UDP,
    //     }
    //   ],
    //   memoryReservationMiB: 123,
    //   image: image
    // })

    const service = new Ec2Service(this, 'Service', {
      cluster: cluster, taskDefinition: taskDefinition
    })

    service.attachToNetworkTargetGroup(tg)
  }
}

Possible Solution

No response

Additional Information/Context

There is a workaround for this.

const lbTarget = service.loadBalancerTarget({
  containerPort: 8125,
  protocol: Protocol.UDP,
  containerName: 'Container',
});

tg.addTarget(lbTarget);

CDK CLI Version

2.51.1 (build 3d30cdb)

Framework Version

No response

Node.js Version

v18.11.0

OS

MacOS Monterey

Language

Typescript

Language Version

Typescript 3.9.7

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    @aws-cdk/aws-ecsRelated to Amazon Elastic ContainerbugThis issue is a bug.effort/mediumMedium work item – several days of effortp2

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions