Container has no mapping for port undefined and protocol tcp. Did you call "container.addPortMappings()"?

Viewed 126

I'm working on a CDK deployment of a DNS server using a pair of FargateServices behind a NetworkLoadBalancer. Since Fargate can't expose the same port as both TCP and UDP, this requires two separate services, one for tcp/53 and one for udp/53.

Defining and deploying the TCP service works just fine:

        const taskDefTCP = new TaskDefinition(this, 'TaskDefTCP', {
          compatibility: Compatibility.FARGATE,
          cpu: '256',
          memoryMiB: '512',
        });
    
        taskDefTCP.addToTaskRolePolicy(new PolicyStatement({
          actions: [
            'ssmmessages:CreateControlChannel',
            'ssmmessages:CreateDataChannel',
            'ssmmessages:OpenControlChannel',
            'ssmmessages:OpenDataChannel'
          ],
          resources: ['*'],
        }));
    
        taskDefTCP.taskRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'));
    
        const containerTCP = taskDefTCP.addContainer('ContainerTCP', {
          image: ContainerImage.fromEcrRepository(repository),
          portMappings: [{
            containerPort: 53,
            hostPort: 53,
            protocol: ecsProtocol.TCP,
          }],
          environment: {
            "AWS_ENVIRONMENT": 'DEV',
          },
          logging: LogDrivers.awsLogs({
            logGroup: assets.dnsLogGroup,
            streamPrefix: 'dns',
          })
        });
    
        this.serviceSecurityGroup = new SecurityGroup(this, 'ServiceSecurityGroup', {
          vpc: assets.vpc,
          allowAllOutbound: true, // TODO: Lock this down.
        });
        this.serviceSecurityGroup.addIngressRule(Peer.anyIpv4(), Port.tcp(53), "TCP Queries");
        this.serviceSecurityGroup.addIngressRule(Peer.anyIpv4(), Port.udp(53), "UDP Queries");
    
        this.dnsServiceTCP = new FargateService(this, 'ServiceTCP', {
          cluster: cluster,
          enableExecuteCommand: true,
          assignPublicIp: false,
          taskDefinition: taskDefTCP,
          securityGroups: [this.serviceSecurityGroup],
          vpcSubnets: {
            subnets: assets.mycorpNetworkResources.getSubnets(NetworkEnvironment.DEV, SubnetType.DNS),
          }
        });
    
         const autoScaleTCP = this.dnsServiceTCP.autoScaleTaskCount({maxCapacity: 2, minCapacity: 1});

If I add the same code copy/pasted from the code above that works, just with TCP changed to UDP, I get an error:

    Container 'AuthDNSApplicationStack/TaskDefUDP/ContainerUDP' has no mapping for port undefined and protocol tcp. Did you call "container.addPortMappings()"?

Of course it has no mapping for TCP. It's a UDP container! Here's the code that, when added, produces the above error:

    const taskDefUDP = new TaskDefinition(this, 'TaskDefUDP', {
      compatibility: Compatibility.FARGATE,
      cpu: '256',
      memoryMiB: '512',
    });
    
    taskDefUDP.addToTaskRolePolicy(new PolicyStatement({
      actions: [
        'ssmmessages:CreateControlChannel',
        'ssmmessages:CreateDataChannel',
        'ssmmessages:OpenControlChannel',
        'ssmmessages:OpenDataChannel'
      ],
      resources: ['*'],
    }));
    taskDefUDP.taskRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName('AmazonSSMManagedInstanceCore'));
    
    const containerUDP = taskDefUDP.addContainer('ContainerUDP', {
      image: ContainerImage.fromEcrRepository(repository),
      portMappings: [{
        containerPort: 53,
        hostPort: 53,
        protocol: ecsProtocol.UDP,
      }],
      environment: {
        "AWS_ENVIRONMENT": 'DEV',
      },
      logging: LogDrivers.awsLogs({
        logGroup: assets.dnsLogGroup,
        streamPrefix: 'dns',
      })
    });
    
    this.dnsServiceUDP = new FargateService(this, 'ServiceUDP', {
      cluster: cluster,
      enableExecuteCommand: true,
      assignPublicIp: true,
      taskDefinition: taskDefUDP,
      securityGroups: [this.serviceSecurityGroup],
      vpcSubnets: {
        subnets: assets.mycorpNetworkResources.getSubnets(NetworkEnvironment.DEV, SubnetType.DNS),
      }
    });
    
    const autoScaleUDP = this.dnsServiceUDP.autoScaleTaskCount({maxCapacity: 2, minCapacity: 1});

Anyone know where I'm going wrong here?

1 Answers

When adding the dnsServiceUDP service to the NLB with addTarget, explicitly pass protocol: elbv2.Protocol.UDP in the AddNetworkTargetsProps.

The target protocol defaults to TCP if not explicitly provided.

Related