DEV Community

Muhammad Ahmad Khan
Muhammad Ahmad Khan

Posted on

Rapidly Deploy ECS Infrastructure on AWS with AWS CDK (TypeScript)

When building and deploying containerized applications on AWS, Amazon ECS (Elastic Container Service) provides a powerful and flexible solution. AWS CDK (Cloud Development Kit) simplifies the process of creating ECS infrastructure by providing a programmatic approach to define cloud resources in code. This blog post walks through how to rapidly deploy ECS infrastructure using the aws-cdk-lib/aws-ecs-patterns module, which abstracts complex tasks like load balancing, service management, and autoscaling.

We’ll cover how to create an ECS Fargate service, set up an Application Load Balancer (ALB), enable auto-scaling, and integrate AWS Secrets Manager for securely managing sensitive data, all with just a few lines of TypeScript code.

Prerequisites

Before getting started, make sure you have the following:

  1. Node.js and npm installed.
  2. AWS CLI configured with appropriate permissions to create resources. You can configure it with:
   aws configure
Enter fullscreen mode Exit fullscreen mode
  1. AWS CDK installed globally:
   npm install -g aws-cdk
Enter fullscreen mode Exit fullscreen mode
  1. Docker installed (optional but useful for container builds).

Setting Up the Project

To begin, create a new directory for your CDK project and initialize it with TypeScript:

mkdir ecs-fargate
cd ecs-fargate
cdk init app --language typescript
Enter fullscreen mode Exit fullscreen mode

This will generate the basic project structure for an AWS CDK application. Next, install the necessary dependencies for ECS, VPC, ECR, and other related services:

npm install @aws-cdk/aws-ec2 @aws-cdk/aws-ecs @aws-cdk/aws-ecr @aws-cdk/aws-ecs-patterns @aws-cdk/aws-iam @aws-cdk/aws-elasticloadbalancingv2 @aws-cdk/aws-certificatemanager @aws-cdk/aws-secretsmanager
Enter fullscreen mode Exit fullscreen mode

Now you're ready to start defining your infrastructure!

Using aws-cdk-lib/aws-ecs-patterns

The aws-cdk-lib/aws-ecs-patterns module simplifies ECS service setup by providing high-level abstractions for common ECS patterns. It includes constructs for easy configuration of services like Application Load Balanced Fargate services, which handle the complexity of setting up load balancers, auto-scaling, and other integrations.

For example, the ApplicationLoadBalancedFargateService construct automatically creates an ECS Fargate service with an Application Load Balancer (ALB) in front of it, managing much of the networking and routing for you.

Here’s a quick look at some key benefits of using the ApplicationLoadBalancedFargateService construct from the aws-cdk-lib/aws-ecs-patterns module:

  • Simplified Infrastructure Setup: You don't need to manually define an Application Load Balancer or its target group—everything is handled for you.
  • Built-in Auto-Scaling: Easily configure auto-scaling for your Fargate tasks based on CPU or memory usage.
  • HTTPS Setup: You can easily set up SSL certificates via ACM (AWS Certificate Manager) and configure the load balancer to use HTTPS.

For more details on other architectural patterns, you can refer to the official AWS CDK ECS Patterns Documentation.

Defining the ECS Fargate Infrastructure

Here’s an example that demonstrates how to quickly deploy ECS infrastructure with AWS CDK using TypeScript.

Example: ECS Fargate Service with Application Load Balancer

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecr from 'aws-cdk-lib/aws-ecr';
import * as ecs_patterns from 'aws-cdk-lib/aws-ecs-patterns';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import * as acm from 'aws-cdk-lib/aws-certificatemanager';
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';

interface EcsFargateStackProps extends cdk.StackProps {
  vpcId: string; // VPC Id
  ecrRepositoryName: string; // ECR repository name
  acmCertificateArn: string; // ACM certificate ARN for HTTPS
  demoServiceSecretArn: string; // Secret ARN for demoService
}

export class EcsFargateStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props: EcsFargateStackProps) {
    super(scope, id, props);

    // Lookup existing VPC using VPC ID from props
    const vpc = ec2.Vpc.fromLookup(this, 'EcsVpc', {
      vpcId: props.vpcId,
    });

    // Reference the existing ECR repository
    const ecrRepo = ecr.Repository.fromRepositoryName(this, 'ExistingEcrRepository', props.ecrRepositoryName);

    // ECS Cluster
    const cluster = new ecs.Cluster(this, 'EcsCluster', {
      clusterName: 'demo-service-EcsFargateCluster',
      vpc,
    });

    // Task Definition
    const taskDefinition = new ecs.FargateTaskDefinition(this, 'FargateTaskDef', {
      memoryLimitMiB: 512,
      cpu: 256,
    });

    // Reference the secret from AWS Secrets Manager
    const taskSecret = secretsmanager.Secret.fromSecretCompleteArn(this, 'FargateTaskSecret', props.demoServiceSecretArn);

    // Add a container to the task definition
    const container = taskDefinition.addContainer('AppContainer', {
      image: ecs.ContainerImage.fromEcrRepository(ecrRepo, 'latest'),
      logging: ecs.LogDriver.awsLogs({ streamPrefix: 'ecs-app' }),
      environment: {
        DEBUG: 'true', // Simple environment variable
      },
      secrets: {
        SECRET_KEY: ecs.Secret.fromSecretsManager(taskSecret, 'SECRET_KEY'), // Referencing secret for SECRET_KEY
      },
    });

    container.addPortMappings({
      containerPort: 5000, // Container runs on port 5000
    });

    // ACM Certificate for HTTPS
    const certificate = acm.Certificate.fromCertificateArn(this, 'AcmCertificate', props.acmCertificateArn);

    // Application Load Balanced Fargate Service
    const fargateService = new ecs_patterns.ApplicationLoadBalancedFargateService(this, 'FargateService', {
      cluster,
      taskDefinition,
      enableExecuteCommand: true, // Enable execute command
      certificate,
      publicLoadBalancer: true,
      loadBalancerName: 'demo-service-alb',
      sslPolicy: elbv2.SslPolicy.RECOMMENDED,
      serviceName: 'demo-service-EcsFargateService',
      redirectHTTP: true,
      protocol: elbv2.ApplicationProtocol.HTTPS, // Default HTTPS
    });

    // Adjust target group port to match the container port
    fargateService.targetGroup.configureHealthCheck({
      path: '/',
      port: '5000', // Health check targets container port 5000
    });

    // Autoscaling
    const scaling = fargateService.service.autoScaleTaskCount({
      minCapacity: 1,
      maxCapacity: 3,
    });

    scaling.scaleOnCpuUtilization('CpuScaling', {
      targetUtilizationPercent: 80,
    });

    scaling.scaleOnMemoryUtilization('MemoryScaling', {
      targetUtilizationPercent: 80,
    });

    // Outputs
    new cdk.CfnOutput(this, 'ClusterName', {
      value: cluster.clusterName,
      description: 'ECS Cluster Name',
    });

    new cdk.CfnOutput(this, 'ServiceName', {
      value: fargateService.service.serviceName,
      description: 'ECS Service Name',
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Breakdown of the Code:

  1. VPC and ECS Cluster: We use ec2.Vpc.fromLookup() to reference an existing VPC based on the VPC ID passed in as a parameter, and create an ECS cluster within that VPC.

  2. ECR Repository: The Docker image for the application is stored in an existing ECR repository. We reference this repository using ecr.Repository.fromRepositoryName().

  3. Task Definition: We define an ECS Fargate task with specified memory and CPU limits, referencing a Docker image from ECR. We also integrate environment variables and sensitive data from AWS Secrets Manager.

  4. Load Balancer and HTTPS: The ApplicationLoadBalancedFargateService construct from aws-cdk-lib/aws-ecs-patterns automatically provisions an ALB, configuring SSL termination using an ACM certificate for HTTPS.

  5. Auto-Scaling: We configure auto-scaling for the Fargate service based on CPU and memory utilization, ensuring the service can dynamically adjust to demand.

  6. Outputs: Finally, we output the ECS cluster name and service name, so they can be easily referenced.

Deploying the Stack

Step 1: Install Dependencies

Ensure that all dependencies are installed:

npm install
Enter fullscreen mode Exit fullscreen mode

Step 2: Bootstrap the CDK Environment

Run the bootstrap command to prepare your AWS account for CDK:

cdk bootstrap --profile your-aws-profile
Enter fullscreen mode Exit fullscreen mode

Step 3: Synthesize the Stack

Synthesize the CloudFormation template to verify the stack:

cdk synth --context vpcId=vpc-xxxxxxxx --context ecrRepositoryName=demo-service --context acmCertificateArn=arn:aws:acm:region:account-id:certificate/certificate-id --context demoServiceSecretArn=arn:aws:secretsmanager:region:account-id:secret:secret-id --profile your-aws-profile
Enter fullscreen mode Exit fullscreen mode

Step 4: Deploy the Stack

Deploy the ECS Fargate stack to AWS:

cdk deploy --context vpcId=vpc-xxxxxxxx --context ecrRepositoryName=demo-service --context acmCertificateArn=arn:aws:acm:region:account-id:certificate/certificate-id --context demoServiceSecretArn=arn:aws:secretsmanager:region:account-id:secret:secret-id --profile your-aws-profile
Enter fullscreen mode Exit fullscreen mode

Step 4: Verify the Deployment

After the stack is successfully deployed, AWS will automatically provision the ECS service, ALB, and other necessary resources. You can access the service via the load balancer’s public endpoint.

Conclusion

In this guide, we’ve rapidly provisioned ECS infrastructure using AWS CDK and TypeScript. By leveraging the ApplicationLoadBalancedFargateService construct from aws-cdk-lib/aws-ecs-patterns, we were able to simplify the creation of a fully managed ECS service that includes an ALB, auto-scaling, and HTTPS support.

This approach significantly reduces the complexity of deploying containerized applications on AWS, allowing you to focus on developing your application instead of managing infrastructure.

For more detailed information, check out the official AWS CDK ECS Patterns Documentation.

GitHub Repository

You can find the complete code for this deployment in my GitHub repository.

Top comments (0)