1. Answers
  2. Using aws ecs with cloudfront

How do I set up an AWS ECS service fronted by CloudFront?

To set up an AWS ECS service fronted by CloudFront, we need to take several key steps. This includes creating an ECS cluster, defining a task definition, setting up the service, and creating a CloudFront distribution to route traffic to the ECS service. Below is a detailed explanation of each step along with the complete program.

  1. Vpc and Subnets: We first define the networking resources like VPC and Subnets which are required for our ECS services.
  2. Cluster: We create an ECS cluster to host our services.
  3. Task Definition: We define a task with the required container definition specifying the Docker image to run.
  4. Service: We create an ECS service that runs the task.
  5. Load Balancer: We create an Application Load Balancer which routes traffic to your ECS service.
  6. CloudFront Distribution: We define a CloudFront Distribution to route the traffic to your ALB.

Here’s the detailed configuration:

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as std from "@pulumi/std";

// VPC and Subnets
const example = new aws.ec2.Vpc("example", {cidrBlock: "10.0.0.0/16"});
const exampleSubnet: aws.ec2.Subnet[] = [];
for (const range = {value: 0}; range.value < 2; range.value++) {
    exampleSubnet.push(new aws.ec2.Subnet(`example-${range.value}`, {
        vpcId: example.id,
        cidrBlock: std.cidrsubnetOutput({
            input: example.cidrBlock,
            newbits: 8,
            netnum: range.value,
        }).apply(invoke => invoke.result),
        availabilityZone: [
            "us-west-2a",
            "us-west-2b",
        ][range.value],
    }));
}
const exampleInternetGateway = new aws.ec2.InternetGateway("example", {vpcId: example.id});
const albSg = new aws.ec2.SecurityGroup("alb_sg", {
    name: "alb_sg",
    vpcId: example.id,
    ingress: [{
        fromPort: 80,
        toPort: 80,
        protocol: "tcp",
        cidrBlocks: ["0.0.0.0/0"],
    }],
    egress: [{
        fromPort: 0,
        toPort: 0,
        protocol: "-1",
        cidrBlocks: ["0.0.0.0/0"],
    }],
});
const ecsSg = new aws.ec2.SecurityGroup("ecs_sg", {
    name: "ecs_sg",
    vpcId: example.id,
    ingress: [{
        fromPort: 80,
        toPort: 80,
        protocol: "tcp",
        securityGroups: [albSg.id],
    }],
    egress: [{
        fromPort: 0,
        toPort: 0,
        protocol: "-1",
        cidrBlocks: ["0.0.0.0/0"],
    }],
});
// ECS Cluster
const exampleCluster = new aws.ecs.Cluster("example", {name: "example"});
// ECS Task Definition
const exampleTaskDefinition = new aws.ecs.TaskDefinition("example", {
    family: "task_definition",
    networkMode: "awsvpc",
    requiresCompatibilities: ["FARGATE"],
    cpu: "256",
    memory: "512",
    containerDefinitions: JSON.stringify([{
        name: "app",
        image: "nginx",
        portMappings: [{
            containerPort: 80,
            hostPort: 80,
        }],
    }]),
});
const exampleTargetGroup = new aws.lb.TargetGroup("example", {
    name: "example-tg",
    port: 80,
    protocol: "HTTP",
    vpcId: example.id,
    healthCheck: {
        path: "/",
        interval: 30,
        timeout: 5,
        healthyThreshold: 2,
        unhealthyThreshold: 2,
    },
});
// Load Balancer
const exampleLoadBalancer = new aws.lb.LoadBalancer("example", {
    name: "example-lb",
    internal: false,
    loadBalancerType: "application",
    securityGroups: [albSg.id],
    subnets: exampleSubnet.map(__item => __item.id),
});
const exampleListener = new aws.lb.Listener("example", {
    loadBalancerArn: exampleLoadBalancer.arn,
    port: 80,
    protocol: "HTTP",
    defaultActions: [{
        type: "forward",
        targetGroupArn: exampleTargetGroup.arn,
    }],
});
// ECS Service
const exampleService = new aws.ecs.Service("example", {
    name: "example-service",
    cluster: exampleCluster.id,
    taskDefinition: exampleTaskDefinition.arn,
    desiredCount: 1,
    launchType: "FARGATE",
    networkConfiguration: {
        subnets: exampleSubnet.map(__item => __item.id),
        securityGroups: [ecsSg.id],
        assignPublicIp: true,
    },
    loadBalancers: [{
        targetGroupArn: exampleTargetGroup.arn,
        containerName: "app",
        containerPort: 80,
    }],
}, {
    dependsOn: [exampleListener],
});
// CloudFront Distribution
const exampleDistribution = new aws.cloudfront.Distribution("example", {
    origins: [{
        domainName: exampleLoadBalancer.dnsName,
        originId: "alb_origin",
        customOriginConfig: {
            httpPort: 80,
            httpsPort: 443,
            originProtocolPolicy: "http-only",
            originSslProtocols: ["TLSv1.2"],
        },
    }],
    enabled: true,
    defaultRootObject: "index.html",
    defaultCacheBehavior: {
        allowedMethods: [
            "DELETE",
            "GET",
            "HEAD",
            "OPTIONS",
            "PATCH",
            "POST",
            "PUT",
        ],
        cachedMethods: [
            "GET",
            "HEAD",
        ],
        targetOriginId: "alb_origin",
        forwardedValues: {
            queryString: false,
            cookies: {
                forward: "none",
            },
        },
        viewerProtocolPolicy: "allow-all",
        minTtl: 0,
        defaultTtl: 3600,
        maxTtl: 86400,
    },
    restrictions: {
        geoRestriction: {
            restrictionType: "none",
        },
    },
    viewerCertificate: {
        cloudfrontDefaultCertificate: true,
    },
});
export const cloudfrontDomainName = exampleDistribution.domainName;

Deploy this code

Want to deploy this code? Sign up for a free Pulumi account to deploy in a few clicks.

Sign up

New to Pulumi?

Want to deploy this code? Sign up with Pulumi to deploy in a few clicks.

Sign up