npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@blend-col/alb-to-fargate

v1.0.6

Published

A **high-level AWS CDK Construct** for rapidly deploying a secure, scalable Application Load Balancer (ALB) in front of an ECS Fargate service. Handles VPC, ECS cluster, ECR, Route53, ACM, and more — all with minimal configuration.

Readme

🚀 aws-cdk-alb-to-fargate

A high-level AWS CDK Construct for rapidly deploying a secure, scalable Application Load Balancer (ALB) in front of an ECS Fargate service. Handles VPC, ECS cluster, ECR, Route53, ACM, and more — all with minimal configuration.


📦 Installation

Option 1: Install with Peer Dependencies (Recommended)

# Install the construct and its peer dependencies
npm install @blend-col/alb-to-fargate [email protected] constructs@^10.0.0

# Or with yarn
yarn add @blend-col/alb-to-fargate [email protected] constructs@^10.0.0

Option 2: Install with Legacy Peer Deps (If conflicts occur)

npm install @blend-col/alb-to-fargate --legacy-peer-deps
npm install [email protected] constructs@^10.0.0

Why Peer Dependencies?

Peer dependencies ensure compatibility with your existing CDK version and prevent version conflicts in your project. This construct requires:

  • [email protected] - Exact CDK version for guaranteed compatibility
  • constructs@^10.0.0 - CDK constructs library for infrastructure components

By using peer dependencies, you maintain control over your CDK version while ensuring this construct works seamlessly with your existing infrastructure code.


⚡️ Quick Start

Basic Example (Create New ALB)

import * as cdk from 'aws-cdk-lib';
import { Vpc } from 'aws-cdk-lib/aws-ec2';
import { Repository } from 'aws-cdk-lib/aws-ecr';
import { Certificate } from 'aws-cdk-lib/aws-certificatemanager';
import { ApplicationProtocol, SslPolicy, ApplicationTargetGroupProps } from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { AlbToFargate } from '@blend-col/alb-to-fargate';

const app = new cdk.App();
const stack = new cdk.Stack(app, 'MyStack');

// Use an existing VPC
const vpc = Vpc.fromLookup(stack, 'Vpc', { isDefault: true });

// Reference your ECR repository
const ecrRepository = Repository.fromRepositoryName(
    stack,
    'MyRepo',
    'my-app-repo'
);

// (Optional) Use an existing ACM certificate
const certificate = Certificate.fromCertificateArn(
    stack,
    'Cert',
    'arn:aws:acm:us-east-1:123456789012:certificate/abcdefg'
);

new AlbToFargate(stack, 'MyAlbFargate', {
    namespace: 'MyApp',
    publicApi: true,
    existingVpc: vpc,
    ecrRepository: ecrRepository,
    ecrImageVersion: 'latest',
    domainName: 'example.com',
    appDomainName: 'api.example.com',
    certificate: certificate,
    loadBalancerProps: {
        vpc,
        internetFacing: true,
    },
    listenerProps: {
        port: 443,
        protocol: ApplicationProtocol.HTTPS,
        sslPolicy: SslPolicy.RECOMMENDED,
        certificates: [certificate],
    },
    targetGroupProps: {
        port: 80,
        protocol: ApplicationProtocol.HTTP,
        targetType: 'ip',
        healthCheck: {
            path: '/',
            interval: cdk.Duration.seconds(30),
            healthyThresholdCount: 2,
            timeout: cdk.Duration.seconds(5),
        },
    } as ApplicationTargetGroupProps,
    clusterProps: { 
        vpc, 
        clusterName: 'MyCluster' 
    },
    fargateTaskDefinitionProps: {
        cpu: 256,
        memoryLimitMiB: 512,
    },
    fargateServiceProps: {
        desiredCount: 2,
    },
});

Using Existing ALB

import { ApplicationLoadBalancer, ApplicationListener } from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { ListenerCondition } from 'aws-cdk-lib/aws-elasticloadbalancingv2';

// Reference existing ALB and listener
const existingAlb = ApplicationLoadBalancer.fromApplicationLoadBalancerAttributes(
    stack,
    'ExistingALB',
    {
        loadBalancerArn: 'arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/my-alb/1234567890123456',
        securityGroupId: 'sg-12345678',
        vpc: vpc,
    }
);

const existingListener = ApplicationListener.fromApplicationListenerAttributes(
    stack,
    'ExistingListener',
    {
        listenerArn: 'arn:aws:elasticloadbalancing:us-east-1:123456789012:listener/app/my-alb/1234567890123456/0123456789012345',
        securityGroup: existingAlb.connections.securityGroups[0],
    }
);

new AlbToFargate(stack, 'MyAlbFargateExisting', {
    namespace: 'MyApp',
    publicApi: true,
    existingVpc: vpc,
    ecrRepository: ecrRepository,
    ecrImageVersion: 'latest',
    existingLoadBalancerObj: {
        loadBalancer: existingAlb,
        listener: existingListener,
    },
    targetGroupProps: {
        port: 80,
        protocol: ApplicationProtocol.HTTP,
        targetType: 'ip',
        healthCheck: {
            path: '/health',
        },
    } as ApplicationTargetGroupProps,
    ruleProps: {
        priority: 100,
        conditions: [
            ListenerCondition.pathPatterns(['/api/*']),
        ],
    },
});

🛠️ Configuration Properties

Core Configuration

| Property | Type | Required | Description | |----------|------|----------|-------------| | namespace | string | ❌ | Prefix for all resource names (defaults to construct ID) | | publicApi | boolean | ✅ | Whether to make the ALB internet-facing (true) or internal/private (false). Set to false for internal services only accessible within your VPC |

VPC Configuration

| Property | Type | Required | Description | |----------|------|----------|-------------| | existingVpc | IVpc | ⚠️ | Use existing VPC (either this or vpcProps) | | vpcProps | VpcProps | ⚠️ | Properties for new VPC (either this or existingVpc) |

Container & ECR

| Property | Type | Required | Description | |----------|------|----------|-------------| | ecrRepository | IRepository | ✅ | ECR repository containing your container image | | ecrImageVersion | string | ❌ | Docker image tag (defaults to 'latest') | | containerDefinitionProps | ContainerDefinitionProps | ❌ | Custom container configuration | | existingContainerDefinitionObject | ContainerDefinition | ❌ | Use existing container definition |

Load Balancer Configuration

| Property | Type | Required | Description | |----------|------|----------|-------------| | loadBalancerProps | LoadBalancerProps | ⚠️ | ALB configuration (either this or existingLoadBalancerObj) | | existingLoadBalancerObj | existingLoadBalancerObj | ⚠️ | Use existing ALB + listener | | listenerProps | ListenerProps \| ApplicationListenerProps | ❌ | ALB listener configuration (required with loadBalancerProps) | | targetGroupProps | ApplicationTargetGroupProps | ✅ | Target group settings for health checks and routing | | ruleProps | AddRuleProps | ❌ | Listener rules (required with existingLoadBalancerObj) |

ECS Configuration

| Property | Type | Required | Description | |----------|------|----------|-------------| | clusterProps | ClusterProps | ⚠️ | ECS cluster configuration (either this or existingFargateServiceObject) | | existingFargateServiceObject | FargateService | ⚠️ | Use existing Fargate service | | fargateTaskDefinitionProps | FargateTaskDefinitionProps | ❌ | Task definition settings (CPU, memory) | | fargateServiceProps | FargateServiceProps | ❌ | Service settings (desired count, etc.) |

SSL/TLS & DNS

| Property | Type | Required | Description | |----------|------|----------|-------------| | certificate | ICertificate | ❌ | ACM certificate for HTTPS | | domainName | string | ❌ | Root domain (e.g., 'example.com') | | appDomainName | string | ❌ | Full domain (e.g., 'api.example.com') |

Logging

| Property | Type | Required | Description | |----------|------|----------|-------------| | logAlbAccessLogs | boolean | ❌ | Enable ALB access logging | | albLoggingBucketProps | BucketProps | ❌ | S3 bucket configuration for ALB logs |


🔗 Accessing Construct Properties

The AlbToFargate construct exposes all created resources as public readonly properties, allowing you to access and configure them further:

Available Properties

const albFargate = new AlbToFargate(stack, 'MyService', { /* props */ });

// Access all created resources
const vpc = albFargate.vpc;                           // VPC instance
const cluster = albFargate.cluster;                   // ECS Cluster
const taskDefinition = albFargate.taskDefinition;     // Fargate Task Definition
const fargateService = albFargate.fargateService;     // Fargate Service
const loadBalancer = albFargate.loadBalancer;         // Application Load Balancer
const listener = albFargate.listener;                 // ALB Listener
const targetGroup = albFargate.targetGroupService;    // Target Group
const containerDefinition = albFargate.containerDefinition; // Container Definition
const certificate = albFargate.certificate;          // ACM Certificate (if created)
const hostedZone = albFargate.hostedZone;            // Route53 Hosted Zone (if created)
const ecrRepository = albFargate.ecrRepository;      // ECR Repository

Advanced Configuration Examples

Configure Auto-Scaling with Custom Metrics

const apiService = new AlbToFargate(stack, 'APIService', {
    // ... basic configuration
    fargateServiceProps: {
        desiredCount: 2,
        enableAutoScaling: true,
        autoScaleTaskCount: {
            minCapacity: 2,
            maxCapacity: 10,
        },
    },
});

// Access the Fargate service for advanced auto-scaling configuration
const scalingTarget = apiService.fargateService!.autoScaleTaskCount({
    minCapacity: 2,
    maxCapacity: 10,
});

// Scale based on CPU utilization
scalingTarget.scaleOnCpuUtilization('CpuScaling', {
    targetUtilizationPercent: 70,
    scaleInCooldown: cdk.Duration.minutes(5),
    scaleOutCooldown: cdk.Duration.minutes(2),
});

// Scale based on memory utilization
scalingTarget.scaleOnMemoryUtilization('MemoryScaling', {
    targetUtilizationPercent: 80,
});

// Scale based on ALB request count
scalingTarget.scaleOnMetric('RequestCountScaling', {
    metric: apiService.targetGroupService!.metricRequestCountPerTarget(),
    scalingSteps: [
        { upper: 100, change: -1 },
        { lower: 500, change: +1 },
        { lower: 1000, change: +2 },
    ],
});

Add Additional ALB Listeners and Rules

const webService = new AlbToFargate(stack, 'WebService', {
    // ... configuration
});

// Add a redirect from HTTP to HTTPS
webService.loadBalancer!.addListener('HttpRedirect', {
    port: 80,
    protocol: ApplicationProtocol.HTTP,
    defaultAction: ListenerAction.redirect({
        protocol: 'HTTPS',
        port: '443',
        permanent: true,
    }),
});

// Add additional rules to existing listener
webService.listener!.addRule('StaticContentRule', {
    priority: 50,
    conditions: [
        ListenerCondition.pathPatterns(['/static/*', '/assets/*']),
    ],
    action: ListenerAction.fixedResponse(200, {
        contentType: 'text/plain',
        messageBody: 'Static content served by CDN',
    }),
});

Configure CloudWatch Alarms

import { Alarm, Metric, TreatMissingData } from 'aws-cdk-lib/aws-cloudwatch';
import { SnsAction } from 'aws-cdk-lib/aws-cloudwatch-actions';

const monitoredService = new AlbToFargate(stack, 'MonitoredService', {
    // ... configuration
});

// Create CloudWatch alarms
const highCpuAlarm = new Alarm(stack, 'HighCpuAlarm', {
    metric: monitoredService.fargateService!.metricCpuUtilization(),
    threshold: 80,
    evaluationPeriods: 2,
    treatMissingData: TreatMissingData.NOT_BREACHING,
});

const highMemoryAlarm = new Alarm(stack, 'HighMemoryAlarm', {
    metric: monitoredService.fargateService!.metricMemoryUtilization(),
    threshold: 85,
    evaluationPeriods: 2,
});

const unhealthyTargetsAlarm = new Alarm(stack, 'UnhealthyTargetsAlarm', {
    metric: monitoredService.targetGroupService!.metricUnhealthyHostCount(),
    threshold: 1,
    evaluationPeriods: 1,
});

// Add SNS notifications (assuming you have an SNS topic)
// highCpuAlarm.addAlarmAction(new SnsAction(alertTopic));

Access Load Balancer for Additional Configuration

import { CfnLoadBalancer } from 'aws-cdk-lib/aws-elasticloadbalancingv2';

const service = new AlbToFargate(stack, 'Service', {
    // ... configuration
});

// Configure additional ALB attributes
const cfnLoadBalancer = service.loadBalancer!.node.defaultChild as CfnLoadBalancer;
cfnLoadBalancer.addPropertyOverride('LoadBalancerAttributes', [
    {
        Key: 'idle_timeout.timeout_seconds',
        Value: '60',
    },
    {
        Key: 'routing.http2.enabled',
        Value: 'true',
    },
    {
        Key: 'access_logs.s3.enabled',
        Value: 'true',
    },
    {
        Key: 'access_logs.s3.bucket',
        Value: 'my-alb-logs-bucket',
    },
]);

// Get load balancer DNS name for outputs
new cdk.CfnOutput(stack, 'LoadBalancerDNS', {
    value: service.loadBalancer!.loadBalancerDnsName,
    description: 'Load Balancer DNS Name',
});

Configure Task Definition with Additional Containers

import * as ecs from 'aws-cdk-lib/aws-ecs';

const multiContainerService = new AlbToFargate(stack, 'MultiContainerService', {
    // ... basic configuration
});

// Add a sidecar container (e.g., for logging or monitoring)
multiContainerService.taskDefinition.addContainer('LoggingContainer', {
    image: ecs.ContainerImage.fromRegistry('fluent/fluent-bit:latest'),
    memoryLimitMiB: 128,
    cpu: 64,
    essential: false,
    logging: ecs.LogDrivers.awsLogs({
        streamPrefix: 'sidecar-logging',
    }),
    environment: {
        FLB_LOG_LEVEL: 'info',
    },
});

// Add a monitoring sidecar
multiContainerService.taskDefinition.addContainer('MonitoringContainer', {
    image: ecs.ContainerImage.fromRegistry('prom/node-exporter:latest'),
    memoryLimitMiB: 64,
    cpu: 32,
    essential: false,
    portMappings: [{
        containerPort: 9100,
        protocol: ecs.Protocol.TCP,
    }],
});

🔄 Mutual Exclusivity Rules

  • VPC: Provide either existingVpc OR vpcProps
  • ALB: Provide either existingLoadBalancerObj OR (loadBalancerProps + listenerProps)
  • Container: Provide either containerDefinitionProps OR existingContainerDefinitionObject
  • ECS: Provide either clusterProps OR existingFargateServiceObject
  • Domains: If providing domain configuration, both domainName AND appDomainName are required
  • Rules: If using existingLoadBalancerObj, ruleProps is required

🏗️ Architecture Overview

This construct creates a complete serverless web application infrastructure:

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Route 53      │    │       ALB       │    │   ECS Fargate   │
│   (Optional)    │───▶│                 │───▶│                 │
│                 │    │  • HTTPS/HTTP   │    │  • Auto-scaling │
│                 │    │  • Health Check │    │  • Private/Pub  │
└─────────────────┘    └─────────────────┘    └─────────────────┘
                                │
                       ┌─────────────────┐
                       │   Target Group  │
                       │                 │
                       │ • Health Checks │
                       │ • Port Mapping  │
                       └─────────────────┘

🚀 Features

  • Flexible VPC: Use existing VPC or create new one
  • SSL/TLS: Automatic certificate management with ACM
  • Health Checks: Configurable health check endpoints
  • Auto Scaling: Built-in ECS service auto-scaling
  • Security: Proper security groups and IAM roles
  • Logging: Optional ALB access logging to S3
  • DNS: Optional Route53 integration
  • Existing Resources: Support for existing ALB, ECS services, etc.

🔧 Comprehensive Deployment Examples

1. Simple HTTP API Service

import * as cdk from 'aws-cdk-lib';
import { Vpc } from 'aws-cdk-lib/aws-ec2';
import { Repository } from 'aws-cdk-lib/aws-ecr';
import { ApplicationProtocol } from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import { AlbToFargate } from '@blend-col/alb-to-fargate';

const simpleApi = new AlbToFargate(stack, 'SimpleAPI', {
    namespace: 'simple-api',
    publicApi: true,
    existingVpc: vpc,
    ecrRepository: repository,
    ecrImageVersion: 'latest',
    loadBalancerProps: {
        vpc,
        internetFacing: true,
    },
    listenerProps: {
        name: 'HttpListener',
        port: 80,
        protocol: ApplicationProtocol.HTTP,
    },
    targetGroupProps: {
        port: 3000,
        protocol: ApplicationProtocol.HTTP,
        targetType: 'ip',
        healthCheck: { 
            path: '/health',
            interval: cdk.Duration.seconds(30),
            healthyThresholdCount: 2,
        },
    },
    clusterProps: {
        clusterName: 'SimpleAPICluster',
        vpc,
    },
    fargateTaskDefinitionProps: {
        cpu: 256,
        memoryLimitMiB: 512,
    },
    fargateServiceProps: {
        desiredCount: 2,
        assignPublicIp: false,
    },
});

2. Private (Internal) ALB Service

import * as ecs from 'aws-cdk-lib/aws-ecs';

const privateApi = new AlbToFargate(stack, 'PrivateAPI', {
    namespace: 'private-api',
    publicApi: false, // Creates an internal ALB
    existingVpc: vpc,
    ecrRepository: repository,
    ecrImageVersion: 'latest',
    loadBalancerProps: {
        vpc,
        internetFacing: false, // Internal ALB - only accessible within VPC
        loadBalancerName: 'PrivateALB',
    },
    listenerProps: {
        name: 'PrivateListener',
        port: 80,
        protocol: ApplicationProtocol.HTTP,
    },
    targetGroupProps: {
        port: 8080,
        protocol: ApplicationProtocol.HTTP,
        targetType: 'ip',
        healthCheck: {
            path: '/internal/health',
            interval: cdk.Duration.seconds(30),
        },
    },
    clusterProps: {
        clusterName: 'PrivateCluster',
        vpc,
    },
    fargateTaskDefinitionProps: {
        cpu: 512,
        memoryLimitMiB: 1024,
    },
    fargateServiceProps: {
        serviceName: 'private-api-service',
        desiredCount: 2,
        assignPublicIp: false, // No public IP - runs in private subnets
        vpcSubnets: {
            subnets: vpc.privateSubnets,
        },
    },
    containerDefinitionProps: {
        containerName: 'private-api-container',
        image: ecs.ContainerImage.fromEcrRepository(repository),
        memoryLimitMiB: 1024,
        cpu: 512,
        portMappings: [{
            containerPort: 8080,
            protocol: ecs.Protocol.TCP,
        }],
        environment: {
            ENVIRONMENT: 'private',
            INTERNAL_SERVICE: 'true',
        },
        logging: ecs.LogDrivers.awsLogs({
            streamPrefix: 'private-api',
        }),
    },
});

// The private ALB is only accessible from within the VPC
// Useful for internal microservices, backend APIs, or services
// that should only be accessed by other services in your VPC

3. Production HTTPS Service with Auto-Scaling

import { Certificate } from 'aws-cdk-lib/aws-certificatemanager';
import { SslPolicy } from 'aws-cdk-lib/aws-elasticloadbalancingv2';

const productionApi = new AlbToFargate(stack, 'ProductionAPI', {
    namespace: 'prod-api',
    publicApi: true,
    existingVpc: vpc,
    ecrRepository: repository,
    ecrImageVersion: 'v1.2.0',
    domainName: 'mycompany.com',
    appDomainName: 'api.mycompany.com',
    certificate: certificate,
    loadBalancerProps: {
        vpc,
        internetFacing: true,
        loadBalancerName: 'ProductionALB',
    },
    listenerProps: {
        name: 'HttpsListener',
        port: 443,
        protocol: ApplicationProtocol.HTTPS,
        sslPolicy: SslPolicy.RECOMMENDED,
        certificates: [certificate],
    },
    targetGroupProps: {
        port: 8080,
        protocol: ApplicationProtocol.HTTP,
        targetType: 'ip',
        healthCheck: {
            path: '/api/health',
            interval: cdk.Duration.seconds(30),
            timeout: cdk.Duration.seconds(5),
            healthyThresholdCount: 2,
            unhealthyThresholdCount: 3,
        },
    },
    clusterProps: {
        clusterName: 'ProductionCluster',
        vpc,
        containerInsights: true,
    },
    fargateTaskDefinitionProps: {
        cpu: 1024,
        memoryLimitMiB: 2048,
    },
    fargateServiceProps: {
        serviceName: 'production-api-service',
        desiredCount: 3,
        assignPublicIp: false,
        enableAutoScaling: true,
        minHealthyPercent: 50,
        maxHealthyPercent: 200,
        capacityProviderStrategies: [
            {
                capacityProvider: 'FARGATE',
                weight: 1,
                base: 2,
            },
            {
                capacityProvider: 'FARGATE_SPOT',
                weight: 4,
                base: 0,
            },
        ],
        autoScaleTaskCount: {
            minCapacity: 2,
            maxCapacity: 10,
        },
    },
    containerDefinitionProps: {
        containerName: 'api-container',
        memoryLimitMiB: 2048,
        cpu: 1024,
        portMappings: [{
            containerPort: 8080,
            protocol: 'tcp',
        }],
        environment: {
            NODE_ENV: 'production',
            LOG_LEVEL: 'info',
        },
        logging: {
            streamPrefix: 'production-api',
        },
    },
    logAlbAccessLogs: true,
});

// Configure additional auto-scaling based on CPU utilization
const scalingTarget = productionApi.fargateService!.autoScaleTaskCount({
    minCapacity: 2,
    maxCapacity: 10,
});

scalingTarget.scaleOnCpuUtilization('CpuScaling', {
    targetUtilizationPercent: 70,
    scaleInCooldown: cdk.Duration.minutes(5),
    scaleOutCooldown: cdk.Duration.minutes(2),
});

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

4. Microservice with Existing ALB and Path-Based Routing

import { ListenerCondition } from 'aws-cdk-lib/aws-elasticloadbalancingv2';

const userService = new AlbToFargate(stack, 'UserService', {
    namespace: 'user-service',
    publicApi: true,
    existingVpc: vpc,
    ecrRepository: userServiceRepository,
    ecrImageVersion: 'latest',
    existingLoadBalancerObj: {
        loadBalancer: existingAlb,
        listener: existingListener,
    },
    ruleProps: {
        priority: 100,
        conditions: [
            ListenerCondition.pathPatterns(['/api/users/*']),
            ListenerCondition.hostHeaders(['api.mycompany.com']),
        ],
    },
    targetGroupProps: {
        port: 3000,
        protocol: ApplicationProtocol.HTTP,
        targetType: 'ip',
        healthCheck: {
            path: '/api/users/health',
            matcher: '200,204',
        },
    },
    clusterProps: {
        clusterName: 'MicroservicesCluster',
        vpc,
    },
    fargateTaskDefinitionProps: {
        cpu: 512,
        memoryLimitMiB: 1024,
    },
    fargateServiceProps: {
        serviceName: 'user-service',
        desiredCount: 2,
        assignPublicIp: false,
        capacityProviderStrategies: [
            {
                capacityProvider: 'FARGATE_SPOT',
                weight: 1,
                base: 1,
            },
        ],
    },
});

5. Development Environment with Custom Container Configuration

import { LogDrivers } from 'aws-cdk-lib/aws-ecs';

const devApi = new AlbToFargate(stack, 'DevAPI', {
    namespace: 'dev-api',
    publicApi: true,
    existingVpc: vpc,
    ecrRepository: repository,
    ecrImageVersion: 'dev-latest',
    loadBalancerProps: {
        vpc,
        internetFacing: true,
        loadBalancerName: 'DevALB',
    },
    listenerProps: {
        name: 'DevListener',
        port: 80,
        protocol: ApplicationProtocol.HTTP,
    },
    targetGroupProps: {
        port: 3000,
        protocol: ApplicationProtocol.HTTP,
        targetType: 'ip',
        healthCheck: {
            path: '/health',
            interval: cdk.Duration.seconds(60),
            healthyThresholdCount: 2,
        },
    },
    clusterProps: {
        clusterName: 'DevCluster',
        vpc,
    },
    fargateTaskDefinitionProps: {
        cpu: 256,
        memoryLimitMiB: 512,
    },
    fargateServiceProps: {
        serviceName: 'dev-api-service',
        desiredCount: 1,
        assignPublicIp: false,
    },
    containerDefinitionProps: {
        containerName: 'dev-api-container',
        memoryLimitMiB: 512,
        cpu: 256,
        portMappings: [{
            containerPort: 3000,
            protocol: 'tcp',
        }],
        environment: {
            NODE_ENV: 'development',
            DEBUG: 'true',
            LOG_LEVEL: 'debug',
        },
        logging: LogDrivers.awsLogs({
            streamPrefix: 'dev-api',
            logRetention: 7, // 7 days retention for dev
        }),
    },
});

// Access the created resources for additional configuration
console.log(`Load Balancer DNS: ${devApi.loadBalancer!.loadBalancerDnsName}`);
console.log(`Cluster ARN: ${devApi.cluster.clusterArn}`);

6. Multi-Environment Service with Shared ALB

// Shared ALB for multiple services
const sharedAlb = new ApplicationLoadBalancer(stack, 'SharedALB', {
    vpc,
    internetFacing: true,
    loadBalancerName: 'SharedMicroservicesALB',
});

const httpsListener = sharedAlb.addListener('HttpsListener', {
    port: 443,
    protocol: ApplicationProtocol.HTTPS,
    certificates: [certificate],
    sslPolicy: SslPolicy.RECOMMENDED,
});

// Service 1: Auth Service
const authService = new AlbToFargate(stack, 'AuthService', {
    namespace: 'auth-service',
    publicApi: true,
    existingVpc: vpc,
    ecrRepository: authRepository,
    ecrImageVersion: 'v2.1.0',
    existingLoadBalancerObj: {
        loadBalancer: sharedAlb,
        listener: httpsListener,
    },
    ruleProps: {
        priority: 10,
        conditions: [
            ListenerCondition.pathPatterns(['/auth/*']),
        ],
    },
    targetGroupProps: {
        port: 8080,
        protocol: ApplicationProtocol.HTTP,
        targetType: 'ip',
        healthCheck: { path: '/auth/health' },
    },
    clusterProps: {
        clusterName: 'AuthCluster',
        vpc,
    },
    fargateTaskDefinitionProps: {
        cpu: 512,
        memoryLimitMiB: 1024,
    },
    fargateServiceProps: {
        desiredCount: 2,
        assignPublicIp: false,
        capacityProviderStrategies: [
            {
                capacityProvider: 'FARGATE',
                weight: 1,
                base: 1,
            },
        ],
    },
});

// Service 2: Payment Service
const paymentService = new AlbToFargate(stack, 'PaymentService', {
    namespace: 'payment-service',
    publicApi: true,
    existingVpc: vpc,
    ecrRepository: paymentRepository,
    ecrImageVersion: 'v1.5.2',
    existingLoadBalancerObj: {
        loadBalancer: sharedAlb,
        listener: httpsListener,
    },
    ruleProps: {
        priority: 20,
        conditions: [
            ListenerCondition.pathPatterns(['/payments/*']),
        ],
    },
    targetGroupProps: {
        port: 9000,
        protocol: ApplicationProtocol.HTTP,
        targetType: 'ip',
        healthCheck: { path: '/payments/health' },
    },
    clusterProps: {
        clusterName: 'PaymentCluster',
        vpc,
    },
    fargateTaskDefinitionProps: {
        cpu: 1024,
        memoryLimitMiB: 2048,
    },
    fargateServiceProps: {
        desiredCount: 3,
        assignPublicIp: false,
        enableAutoScaling: true,
        capacityProviderStrategies: [
            {
                capacityProvider: 'FARGATE',
                weight: 2,
                base: 1,
            },
            {
                capacityProvider: 'FARGATE_SPOT',
                weight: 3,
                base: 0,
            },
        ],
        autoScaleTaskCount: {
            minCapacity: 2,
            maxCapacity: 8,
        },
    },
});

// Configure auto-scaling for payment service based on custom metrics
const paymentScalingTarget = paymentService.fargateService!.autoScaleTaskCount({
    minCapacity: 2,
    maxCapacity: 8,
});

paymentScalingTarget.scaleOnMetric('RequestCountScaling', {
    metric: paymentService.targetGroupService!.metricRequestCountPerTarget(),
    scalingSteps: [
        { upper: 100, change: -1 },
        { lower: 500, change: +1 },
        { lower: 1000, change: +2 },
    ],
});

7. High-Availability Service with Logging and Monitoring

import { BucketProps } from 'aws-cdk-lib/aws-s3';
import { RemovalPolicy } from 'aws-cdk-lib';

const haService = new AlbToFargate(stack, 'HAService', {
    namespace: 'ha-service',
    publicApi: true,
    existingVpc: vpc,
    ecrRepository: repository,
    ecrImageVersion: 'stable',
    domainName: 'mycompany.com',
    appDomainName: 'ha-api.mycompany.com',
    certificate: certificate,
    loadBalancerProps: {
        vpc,
        internetFacing: true,
        loadBalancerName: 'HA-ALB',
        crossZone: true,
    },
    listenerProps: {
        name: 'HAListener',
        port: 443,
        protocol: ApplicationProtocol.HTTPS,
        sslPolicy: SslPolicy.RECOMMENDED,
        certificates: [certificate],
    },
    targetGroupProps: {
        port: 8080,
        protocol: ApplicationProtocol.HTTP,
        targetType: 'ip',
        healthCheck: {
            path: '/health',
            interval: cdk.Duration.seconds(15),
            timeout: cdk.Duration.seconds(5),
            healthyThresholdCount: 2,
            unhealthyThresholdCount: 2,
        },
        deregistrationDelay: cdk.Duration.seconds(30),
    },
    clusterProps: {
        clusterName: 'HACluster',
        vpc,
        containerInsights: true,
    },
    fargateTaskDefinitionProps: {
        cpu: 2048,
        memoryLimitMiB: 4096,
    },
    fargateServiceProps: {
        serviceName: 'ha-service',
        desiredCount: 4,
        assignPublicIp: false,
        enableAutoScaling: true,
        minHealthyPercent: 75,
        maxHealthyPercent: 200,
        capacityProviderStrategies: [
            {
                capacityProvider: 'FARGATE',
                weight: 1,
                base: 2,
            },
        ],
        autoScaleTaskCount: {
            minCapacity: 4,
            maxCapacity: 20,
        },
        vpcSubnets: {
            subnets: vpc.privateSubnets,
        },
    },
    containerDefinitionProps: {
        containerName: 'ha-api-container',
        memoryLimitMiB: 4096,
        cpu: 2048,
        portMappings: [{
            containerPort: 8080,
            protocol: 'tcp',
        }],
        environment: {
            NODE_ENV: 'production',
            LOG_LEVEL: 'info',
            METRICS_ENABLED: 'true',
        },
        logging: LogDrivers.awsLogs({
            streamPrefix: 'ha-service',
            logRetention: 30,
        }),
    },
    logAlbAccessLogs: true,
    albLoggingBucketProps: {
        bucketName: 'ha-service-alb-logs',
        removalPolicy: RemovalPolicy.RETAIN,
        lifecycleRules: [{
            id: 'DeleteOldLogs',
            expiration: cdk.Duration.days(90),
        }],
    } as BucketProps,
});

// Configure comprehensive auto-scaling
const haScalingTarget = haService.fargateService!.autoScaleTaskCount({
    minCapacity: 4,
    maxCapacity: 20,
});

haScalingTarget.scaleOnCpuUtilization('CpuScaling', {
    targetUtilizationPercent: 60,
    scaleInCooldown: cdk.Duration.minutes(10),
    scaleOutCooldown: cdk.Duration.minutes(3),
});

haScalingTarget.scaleOnMemoryUtilization('MemoryScaling', {
    targetUtilizationPercent: 70,
    scaleInCooldown: cdk.Duration.minutes(10),
    scaleOutCooldown: cdk.Duration.minutes(3),
});

// Add custom metric scaling based on ALB request count
haScalingTarget.scaleOnMetric('RequestCountScaling', {
    metric: haService.loadBalancer!.metricRequestCount(),
    scalingSteps: [
        { upper: 1000, change: -2 },
        { lower: 5000, change: +2 },
        { lower: 10000, change: +4 },
    ],
    adjustmentType: AdjustmentType.CHANGE_IN_CAPACITY,
});

// Output important information
new cdk.CfnOutput(stack, 'HAServiceURL', {
    value: `https://${haService.loadBalancer!.loadBalancerDnsName}`,
    description: 'HA Service Load Balancer URL',
});

new cdk.CfnOutput(stack, 'HAServiceClusterArn', {
    value: haService.cluster.clusterArn,
    description: 'HA Service ECS Cluster ARN',
});

📋 Prerequisites

  • AWS CDK v2.x installed
  • Node.js 18+ or TypeScript 4.7+
  • ECR repository with your container image
  • (Optional) Existing VPC, ALB, or ECS resources

🎯 Best Practices

Security

  • Always use HTTPS in production (ApplicationProtocol.HTTPS)
  • Enable ALB access logging for audit trails
  • Use specific security groups and VPC configurations
  • Implement proper health check endpoints

Performance

  • Configure appropriate CPU and memory for your containers
  • Set reasonable health check intervals
  • Use multiple AZs for high availability
  • Consider using Application Auto Scaling

Cost Optimization

  • Use Fargate Spot capacity when appropriate
  • Configure appropriate desired count for your traffic
  • Monitor and adjust resource allocation based on usage

🔍 Troubleshooting

Common Issues

Health Check Failures

targetGroupProps: {
    healthCheck: {
        path: '/health',
        interval: cdk.Duration.seconds(30),
        timeout: cdk.Duration.seconds(5),
        healthyThresholdCount: 2,
        unhealthyThresholdCount: 3,
    },
}

Certificate Issues

  • Ensure your certificate is in the same region as your ALB
  • Verify domain validation is complete
  • Check that certificate covers your domain

Container Issues

  • Verify your container exposes the correct port
  • Check container logs in CloudWatch
  • Ensure proper IAM permissions for ECR access

🤝 Contributing

We welcome contributions! Here's how to get started:

  1. Fork this repository
  2. Clone your fork: git clone https://github.com/your-username/aws-cdk-alb-to-fargate.git
  3. Install dependencies: npm install
  4. Make your changes
  5. Build and test: npm run build && npm test
  6. Submit a Pull Request

Development Setup

git clone https://github.com/ai-scm/cdk-albToFargate-construct.git
cd cdk-albToFargate-construct
npm install
npm run build
npm test

Running Tests

npm test                 # Run all tests
npm run test:watch      # Run tests in watch mode

📄 License

MIT - see the LICENSE file for details.


🆘 Support

  • 📚 Documentation: Check this README and inline code comments
  • 🐛 Issues: GitHub Issues
  • 💬 Discussions: GitHub Discussions
  • 📧 Email: For enterprise support, contact us

🏷️ Tags

aws-cdk fargate ecs alb application-load-balancer serverless containers infrastructure-as-code typescript aws