Use ApplicationLoadBalancedFargateService to run an ECS task behind an Application Load Balancer. This example uses a public container image so the first deployment does not depend on an ECR repository or a missing application Dockerfile.
Create the project
Use sandbox AWS credentials, a supported Node.js installation, and AWS CDK v2:
mkdir fargate-cdk cd fargate-cdk cdk init app --language typescript npm install --save-exact aws-cdk-lib@2.272.0 constructs@10.5.0
Complete Fargate stack
Replace lib/fargate-cdk-stack.ts:
import { CfnOutput, Stack, StackProps } from "aws-cdk-lib"; import * as ec2 from "aws-cdk-lib/aws-ec2"; import * as ecs from "aws-cdk-lib/aws-ecs"; import * as patterns from "aws-cdk-lib/aws-ecs-patterns"; import { Construct } from "constructs"; export class FargateCdkStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); const vpc = new ec2.Vpc(this, "Network", { maxAzs: 2, natGateways: 0, subnetConfiguration: [{ name: "public", subnetType: ec2.SubnetType.PUBLIC, cidrMask: 24, }], }); const cluster = new ecs.Cluster(this, "Cluster", { vpc }); const service = new patterns.ApplicationLoadBalancedFargateService(this, "Web", { cluster, cpu: 256, memoryLimitMiB: 512, desiredCount: 1, publicLoadBalancer: true, assignPublicIp: true, taskSubnets: { subnetType: ec2.SubnetType.PUBLIC }, taskImageOptions: { image: ecs.ContainerImage.fromRegistry("public.ecr.aws/docker/library/nginx:1.28"), containerPort: 80, }, }); service.targetGroup.configureHealthCheck({ path: "/", healthyHttpCodes: "200" }); new CfnOutput(this, "ServiceUrl", { value: `http://${service.loadBalancer.loadBalancerDnsName}`, }); } }
The task uses public subnets with a public IP for outbound image pulls, avoiding a NAT gateway in this small exercise. The pattern connects the load balancer to the task port; public addressing alone does not grant unrestricted inbound task access. Inspect the synthesized security groups rather than assuming the exposure is correct.
The image tag is an explicit example baseline, not an immutable digest. For repeatable production deployments, select and scan an approved image digest. The Fargate pattern documentation covers configuration options.
Validate and deploy
npx tsc --noEmit npx aws-cdk synth npx aws-cdk diff npx aws-cdk deploy --outputs-file stack-outputs.json
Bootstrap the target environment first if needed. Open the ServiceUrl output and inspect ECS service events and target-group health if the request fails. Common causes include image pull failures, an incorrect container port, or an application listening only on loopback.
This revision has not been deployed to AWS. Compilation and local synthesis do not prove that a remote image is available or that the task starts successfully.
Production differences and cleanup
This demonstration has one task and an HTTP listener. Production design needs an appropriate task count, health and deployment policies, HTTPS with a certificate, scaling limits, logging, and image-update controls. Private task networking with NAT or required VPC endpoints may fit your organization better.
Fargate and load-balancer resources incur charges even when request traffic is low. Review npx aws-cdk destroy for this exercise stack, then check for retained log groups. Do not delete a shared ECR repository as part of routine service cleanup.
Continue with subnet selection, VPC creation, and CDK outputs.
Quick Recap
Does Fargate require an ECR repository?
No. A task can use an image from ECR or another supported registry. This example uses a public image; private images need the appropriate pull permissions and network access.
Does no NAT gateway mean no cost?
No. Tasks, the load balancer, logs, public IPv4 addresses, and data transfer can still incur charges.
Comments
Share your thoughts and questions below