Home > Software design >  CDK Fargate: Map subdomain to different container port
CDK Fargate: Map subdomain to different container port

Time:10-28

Look at the following CDK stack definition:

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

    const myHostedZone = new route53.HostedZone(this, "HostedZone", {
      zoneName: domain,
    });

    const certificate = new acm.Certificate(this, "Certificate", {
      domainName: `*.${domain}`,
      validation: acm.CertificateValidation.fromDns(myHostedZone),
    });

    const image = new ecr.DockerImageAsset(this, "Image", { directory: "." });

    const vpc = new ec2.Vpc(this, "ApplicationVpc", { maxAzs: 2 });

    const cluster = new ecs.Cluster(this, "Cluster", {
      clusterName: "Cluster",
      vpc,
    });

    const taskDefinition = new ecs.FargateTaskDefinition(this, "TaskDef");
    taskDefinition.addContainer("DefaultContainer", {
      image: ecs.ContainerImage.fromDockerImageAsset(image),
      portMappings: [
        { containerPort: 3000, hostPort: 3000 },
        { containerPort: 3001, hostPort: 3001 },
      ],
    });

    const service = new ecsPatterns.ApplicationLoadBalancedFargateService(this, "Service", {
      cluster,
      publicLoadBalancer: true,
      taskDefinition,
      certificate,
    });

    service.loadBalancer.addRedirect()

    service.listener.addTargets("api", {
      priority: 10,
      conditions: [elb.ListenerCondition.hostHeaders([`api.${domain}`])],
      // what to do???
    });
  }
}

I want to map incoming traffic with api.domain to port 3001 and everything else should map to port 3000.

How can I achieve this?

CodePudding user response:

Use the port property of the AddApplicationTargetsProps:

    service.listener.addTargets("api", {
      priority: 10,
      conditions: [elb.ListenerCondition.hostHeaders([`api.${domain}`])],
      port: 3001,
      targets: [service.service]
    });
    service.listener.addTargets("default", {
      port: 3000,
      targets: [service.service]
    });

https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-elasticloadbalancingv2.AddApplicationTargetsProps.html#port

CodePudding user response:

I was able to solve it with the following

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

    const zone = new route53.HostedZone(this, "HostedZone", {
      zoneName: domain,
    });

    //const certificate = acm.Certificate.fromCertificateArn(this, "Certificate", certificateArn);

    const certificate = new acm.Certificate(this, "Certificate", {
      domainName: domain,
      subjectAlternativeNames: [`*.${domain}`],
      validation: acm.CertificateValidation.fromDns(zone),
    });

    const image = new ecr.DockerImageAsset(this, "Image", { directory: "." });

    const vpc = new ec2.Vpc(this, "ApplicationVpc", { maxAzs: 2 });

    const cluster = new ecs.Cluster(this, "Cluster", {
      clusterName: "Cluster",
      vpc,
    });

    const taskDefinition = new ecs.FargateTaskDefinition(this, "TaskDef");
    taskDefinition.addContainer("DefaultContainer", {
      image: ecs.ContainerImage.fromDockerImageAsset(image),
      portMappings: [
        { containerPort: 3000, hostPort: 3000 },
        { containerPort: 3001, hostPort: 3001 },
      ],
      logging: new ecs.AwsLogDriver({
        streamPrefix: domain,
      }),
    });

    const service = new ecs.FargateService(this, "Service", {
      cluster,
      taskDefinition,
      assignPublicIp: true,
    });

    const lb = new elb.ApplicationLoadBalancer(this, "LoadBalancer", {
      vpc,
      internetFacing: true,
    });

    const listener = lb.addListener("Listener", {
      port: 443,
      certificates: [certificate],
    });

    listener.addTargets("API", {
      priority: 10,
      conditions: [elb.ListenerCondition.hostHeaders([`api.${domain}`])],
      port: 80,
      targets: [service.loadBalancerTarget({ containerName: "DefaultContainer", containerPort: 3001 })],
      healthCheck: {
        healthyHttpCodes: "200-399",
      },
    });

    listener.addTargets("UI", {
      port: 80,
      targets: [service.loadBalancerTarget({ containerName: "DefaultContainer", containerPort: 3000 })],
      healthCheck: {
        healthyHttpCodes: "200-399",
      },
    });

    new route53.ARecord(this, "AliasRecord", {
      zone,
      target: route53.RecordTarget.fromAlias(new alias.LoadBalancerTarget(lb)),
    });

    new route53.ARecord(this, "AliasRecordAPI", {
      recordName: `api.${domain}`,
      zone,
      target: route53.RecordTarget.fromAlias(new alias.LoadBalancerTarget(lb)),
    });
  }
}

I am still wondering why listener.addTargets requires port 80.

  • Related