Add Cloud Map service to Application Load Balancer created by ApplicationLoadBalancedFargateService - amazon-web-services

I've got the following Fargate service created by an ecs pattern. The CloudMap I create here only points to the underlying task which is a private IP and runs on port 8080 (Tomcat). The ALB forwards properly from 80->8080. How can I get the DNS to properly route to the task? Can I get the DNS service to route directly to the ALB?
const service = new ecs_patterns.ApplicationLoadBalancedFargateService(this, 'MyAppWebstartFargateService', {
serviceName: "myapp-service",
cluster: cluster,
cpu: 512,
memoryLimitMiB: 2048,
cloudMapOptions: {
name: "myapp",
containerPort: 8080,
cloudMapNamespace: namespace,
dnsRecordType: svc_dsc.DnsRecordType.A,
dnsTtl: Duration.seconds(300),
},
desiredCount: 1,
publicLoadBalancer: false,
securityGroups: [sg],
listenerPort: 80,
openListener: true,
healthCheckGracePeriod: Duration.seconds(300),
targetProtocol: elbv2.ApplicationProtocol.HTTP,
protocol: elbv2.ApplicationProtocol.HTTP,
enableExecuteCommand: true,
taskImageOptions: {
containerName: "myapp-container",
containerPort: 8080,
enableLogging: true,
image: ecs.ContainerImage.fromEcrRepository(repository, "latest"),
},
});

I figured it out! I needed to call registerLoadBalancer on the Cloud Map service and give it the resulting LB from the Fargate pattern. Hope this helps someone down the road b/c I could not find any solution to this exact use case.
const namespace = svc_dsc.PrivateDnsNamespace.fromPrivateDnsNamespaceAttributes(this, "MyAppCloudMapNamespace", {
namespaceArn: "*****************",
namespaceId: "999999999999999",
namespaceName: "mydomain.com"
});
const mapService = new svc_dsc.Service(this, 'MyAppCloudMapService', {
namespace: namespace,
dnsRecordType: svc_dsc.DnsRecordType.A,
dnsTtl: Duration.seconds(300),
name: "myapp",
routingPolicy: svc_dsc.RoutingPolicy.WEIGHTED,
loadBalancer: true // Important! If you choose WEIGHTED but don't set this, the routing policy will default to MULTIVALUE instead
});
const service = new ecs_patterns.ApplicationLoadBalancedFargateService(this, 'MyAppWebstartFargateService', {
serviceName: "myapp-service",
cluster: cluster,
cpu: 512,
memoryLimitMiB: 2048,
desiredCount: 1,
publicLoadBalancer: false,
securityGroups: [sg],
listenerPort: 80,
openListener: true,
healthCheckGracePeriod: Duration.seconds(300),
targetProtocol: elbv2.ApplicationProtocol.HTTP,
protocol: elbv2.ApplicationProtocol.HTTP,
enableExecuteCommand: true,
taskImageOptions: {
containerName: "myapp-container",
containerPort: 8080,
enableLogging: true,
image: ecs.ContainerImage.fromEcrRepository(repository, "latest"),
},
});
mapService.registerLoadBalancer("MyAppLoadBalancer", service.loadBalancer);

Related

How do I enable deletion protection for load balancer using ApplicationLoadBalancedFargateService cdk construct

I have created a Fargate service running on an ECS cluster fronted by an application load balancer using the ApplicationLoadBalancedFargateService CDK construct.
cluster,
memoryLimitMiB: 1024,
desiredCount: 1,
cpu: 512,
taskImageOptions: {
image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"),
},
});
There are no Props for enabling deletion protection. Can anyone tell from his experience?
CDK offers the Escape Hatches feature to use Clouformation Props if any High-level construct does not have parameters.
// Create a load-balanced Fargate service and make it public
var loadBalancedService = new ecs_patterns.ApplicationLoadBalancedFargateService(this, `${ENV_NAME}-pgadmin4`, {
cluster: cluster, // Required
cpu: 512, // Default is 256
desiredCount: 1, // Default is 1
taskImageOptions: {
image: ecs.ContainerImage.fromRegistry('image'),
environment: {}
},
memoryLimitMiB: 1024, // Default is 512
assignPublicIp: true
});
// Get the CloudFormation resource
const cfnLB = loadBalancedService.loadBalancer.node.defaultChild as elbv2.CfnLoadBalancer;
cfnLB.loadBalancerAttributes = [{
key: 'deletion_protection.enabled',
value: 'true',
},
];

Using existing loadbalancer for adding targetgroup

I want to make the targetGroup by cdk and use the ALB already existed.
This error happens.
Error: .listeners can only be accessed if the class was constructed as an owned, not looked up, load balancer
at LookedUpApplicationLoadBalancer.get listeners [as listeners]
I can't access the listeners of ALB
What I want to do is use one load balancer for two ECS and two domain.
www.exampleA.com -> port 80 -> ALB -> fargate A
www.exampleB.com -> port 80 -> ALB -> fargate B
These are my code below.
const lb = elb.ApplicationLoadBalancer.fromLookup(this, 'ALB', {
loadBalancerArn: 'arn:aws:elasticloadbalancing:ap-northeast-1:678100228232:loadbalancer/app/app-load-balancer/1a97159fcaf4d6c0',
});
const listener = lb.listeners[0];
const targetGroup = listener.addTargets("ECS", {
protocol: elb.ApplicationProtocol.HTTP,
port: 80,
targets: [ecsAdminService]
});
targetGroup.configureHealthCheck({
path: "/",
port: "8080"
})
Or if it is impossible, I want to make targetgroup without ALB
(then I can attach targetgroup to ALB manually)
So, I tried this
const targetGroup = new elb.ApplicationTargetGroup(this,"ECS", {
protocol: elb.ApplicationProtocol.HTTP,
port: 80,
targets: [ecsAdminService],
vpc: cluster.vpc,
});
targetGroup.configureHealthCheck({
path: "/",
port: "8080"
})
However this error comes
"Invalid request provided: UpdateService error: The target group with targetGroupArn arn:aws:elasticloadbalancing:ap-northeast-1:678100228133:targetgroup/CdkTr-ECSD2-S1ROICFY9661/f1f3e3b280c2a008 does not have an associated load balancer
I can use existing ALB like this below
Actually, what I need is only securityGroup of ALB and listener.
const securityGroup = ec2.SecurityGroup.fromSecurityGroupId(this, "MyAlbSecGroup", "sg-0ea7a62badcc673a3")
const listenerArn = "arn:aws:elasticloadbalancing:ap-northeast-1:67810022242:listener/app/my-alb-id-listener/1a97159fcaf4d6c0/09a32815415beae6";
const existingListener = elb.ApplicationListener.fromApplicationListenerAttributes(this, "SharedListener", {
listenerArn,
securityGroup
});
const targetGroup = new elb.ApplicationTargetGroup(this,"ECS", {
port: 80,
targets: [ecsAdminService],
vpc: cluster.vpc,
});
existingListener.addTargetGroups("tg",{
priority:1,
conditions:[
elb.ListenerCondition.hostHeaders(['my.example.com'])
],
targetGroups:[targetGroup]
})

AWS-CDK ECS Fargate LoadBalancer listening on port 80 with target group mapping to container port

I've been trying to build a simple ECS Fargate infrastructure using the CDK to learn ECS and its components. The web server exposes port 8081, service SG ingress rule allows all TCP from ALB SG, ALB SG allows connection on PORT 80 - later changed to all TCP for testing. ALB has a listener on port 80 – later also on port 8081 – which forwards traffic to the Target Group on HTTP:8081, fargate tasks are automatically registered, health checks are passing.
Everything seems to be set up the right way, however, when going to [alb-dns].com I get nothing – not even a 504 – DNS just cannot be found. But when I go with [alb-dns].com:8081 it serves me the "hello world" from the webserver. This works regardless of whether my Target Group is on HTTP:8081 or HTTP:80.
I tried an old github/stackoverflow solution of passing a listener as port mapping to a container, but that doesn't work anymore – type mismatch.
What am I missing here?
Code:
this.cluster = new Cluster(this, 'exanubes-cluster', {
vpc: props.vpc,
clusterName: 'exanubes-cluster',
containerInsights: true,
enableFargateCapacityProviders: true,
})
const albSg = new SecurityGroup(this, 'SecurityGroupLoadBalancer', {
vpc: props.vpc,
allowAllOutbound: true
})
albSg.addIngressRule(Peer.anyIpv4(), Port.allTcp())
const alb = new ApplicationLoadBalancer(this, 'alb', {
vpc: props.vpc,
loadBalancerName: 'exanubes-ecs-application-LB',
internetFacing: true,
securityGroup: albSg,
http2Enabled: false,
deletionProtection: false
})
const listener = alb.addListener('http listener', {
port: 80,
open: true
})
const targetGroup = listener.addTargets('tcp-listener-target', {
targetGroupName: 'tcp-target-ecs-service',
protocol: ApplicationProtocol.HTTP,
protocolVersion: ApplicationProtocolVersion.HTTP1,
port: CONTAINER_PORT
})
const taskDefinition = new FargateTaskDefinition(this, 'fargate-task-definition');
taskDefinition.addContainer('web-server', {
image: EcrImage.fromEcrRepository(props.repository),
}).addPortMappings({
containerPort: CONTAINER_PORT
})
const securityGroup = new SecurityGroup(this, 'http-sg', {
vpc: props.vpc,
})
securityGroup.addIngressRule(Peer.securityGroupId(albSg.securityGroupId), Port.allTcp(), 'Allow inbound connections from ALB')
const fargateService = new FargateService(this, 'fargate-service', {
cluster: this.cluster,
assignPublicIp: true,
taskDefinition,
capacityProviderStrategies: [
{
capacityProvider: "FARGATE_SPOT",
weight: 0,
},
{
capacityProvider: "FARGATE",
weight: 1
}
],
securityGroups: [securityGroup],
})
targetGroup.addTarget(fargateService)
PS: I know of ApplicationLoadBalancedFargateService but I wanted to build it myself.
I think this example in the source code .../aws_cdk/aws_ecs/__init__.py should help
Example::
# cluster: ecs.Cluster
# task_definition: ecs.TaskDefinition
# vpc: ec2.Vpc
service = ecs.FargateService(self, "Service", cluster=cluster, task_definition=task_definition)
lb = elbv2.ApplicationLoadBalancer(self, "LB", vpc=vpc, internet_facing=True)
listener = lb.add_listener("Listener", port=80)
service.register_load_balancer_targets(
container_name="web",
container_port=80,
new_target_group_id="ECS",
listener=ecs.ListenerConfig.application_listener(listener,
protocol=elbv2.ApplicationProtocol.HTTPS
)
)
Edit: the above did not work for me, but this did
listener.add_targets('tcp-target-group',
protocol=ApplicationProtocol.HTTP,
target_group_name="my-target",
targets=[service.load_balancer_target(
container_name=container.container_name,
container_port=CONTAINER_PORT
)],
)

How to configure ELB for two different ports in CDK?

I am having an elastic load balancer serving traffic to an EC2 instance. I have an application running on port 443 and it runs just fine.
Now I want to run another application on the EC2 instance on port 444. I want to be able to run the first application by hitting port 443 and the second application by hitting port 444.
Somehow I cant manage to add port 444 to the load balancer in CDK. I am doing something like this.
const appLoadbalancer = new elbv2.ApplicationLoadBalancer(this, `${props.type}AppLoadBalancer`, {
vpc: vpc,
vpcSubnets: subnets,
internetFacing: true,
});
const httpsListener = appLoadbalancer.addListener(`${props.type}HTTPSListener`, {
port: 443,
open: true,
certificates: [props.certificate]
});
httpsListener.addTargets(`${props.type}HTTPSTarget`, {
port: 443,
targets: [autoscalingGroup],
healthCheck: {
enabled: true,
healthyHttpCodes: "200,302"
}
});
const httpsListener2 = appLoadbalancer.addListener(`${props.type}HTTPSListener2`, {
port: 444,
protocol: elbv2.ApplicationProtocol.HTTPS,
open: true,
certificates: [props.certificate]
});
httpsListener2.addTargets(`${props.type}HTTPSTarget2`, {
port: 444,
protocol: elbv2.ApplicationProtocol.HTTPS,
targets: [autoscalingGroup],
healthCheck: {
enabled: true,
healthyHttpCodes: "200,302"
}
});
Everything is working just fine if it set it up only for port 443. But When I try the above i get something like:
Error: Cannot add AutoScalingGroup to 2nd Target Group
I dont know what is meant by this and how to fix it in cdk...
I ended up with a solution like this:
const appLoadbalancer = new elbv2.ApplicationLoadBalancer(this, `${props.type}AppLoadBalancer`, {
vpc: vpc,
vpcSubnets: subnet,
internetFacing: true,
});
const tg1 = new elbv2.ApplicationTargetGroup(this, "tg1", {
vpc: vpc,
protocol: elbv2.ApplicationProtocol.HTTPS})
const tg2 = new elbv2.ApplicationTargetGroup(this, "tg2", {vpc: vpc,
protocol: elbv2.ApplicationProtocol.HTTPS, port: 444})
const httpsListener = appLoadbalancer.addListener(`${props.type}HTTPSListener`, {
port: 443,
protocol: elbv2.ApplicationProtocol.HTTPS,
open: true,
certificates: [props.certificate]
});
httpsListener.addTargetGroups("RestTarget", {
targetGroups: [tg1]
});
const httpsListener2 = appLoadbalancer.addListener(`${props.type}HTTPSListener2`, {
port: 444,
protocol: elbv2.ApplicationProtocol.HTTPS,
open: true,
certificates: [props.certificate]
});
httpsListener2.addTargetGroups("RestTarget", {
targetGroups: [tg2]
});
const ServiceAsg = autoscalingGroup.node.defaultChild as autoscaling.CfnAutoScalingGroup
ServiceAsg.targetGroupArns = [tg1.targetGroupArn, tg2.targetGroupArn]

AWS CDK stuck while creating EcsService Cloud Formation stack using ApplicationLoadBalancedEc2Service

I have the following code to create a ECS ApplicationLoadBalancedEc2Service, however it is stuck in creation for 2 hours and i don't see any errors in events.
Below is my code:
this.cluster = new Cluster(this, 'Cluster', {
vpc: props.vpc
});
this.cluster.addCapacity('DefaultAutoScalingGroupCapacity', {
instanceType: InstanceType.of(InstanceClass.R5D, InstanceSize.XLARGE24),
minCapacity: 2,
maxCapacity: 50,
});
this.service = new ApplicationLoadBalancedEc2Service(this, 'Service', {
cluster: props.ecsCluster,
memoryLimitMiB: 768000,
taskImageOptions: {
containerPort: 8080,
image: new ContainerImage({
package: Package.fromString('ECSMatching'),
transformPackage: Package.fromString('ECSMatchingImage'),
componentName: 'service',
}),
taskRole: getDefaultEcsTaskInstanceRole(this),
environment: {'STAGE': props.stage}
},
});
this.service.service.connections.allowFrom(
Peer.ipv4(props.ecsCluster.vpc.vpcCidrBlock),
Port.allTraffic(),
'Local VPC Access'
);
this.service.targetGroup.setAttribute('deregistration_delay.timeout_seconds', '6000');