CREATE_FAILED | AWS::ECS::Service + CloudFront, Cloud Map, LAX Local Zone, CDKv2

0

I'm trying to create a simple ECS service exposed to CloudFront via Cloud Map (I don't want an ALB). Why doesn't this work?

import * as cdk from 'aws-cdk-lib';
import { StackProps } from 'aws-cdk-lib';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as servicediscovery from 'aws-cdk-lib/aws-servicediscovery';
import * as ssm from 'aws-cdk-lib/aws-ssm';
import { Construct } from 'constructs';

interface EcsDeployStackProps extends StackProps {
    dockerImageUriParam: string;
}

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

        const vpc = new ec2.Vpc(this, 'LosAngelesVPC', {
            cidr: '10.210.0.0/16',
            availabilityZones: ['us-west-2-lax-1a', 'us-west-2-lax-1b'],
            subnetConfiguration: [
                {
                    cidrMask: 24,
                    name: 'lax-public-subnet-1',
                    subnetType: ec2.SubnetType.PUBLIC,
                },
                {
                    cidrMask: 24,
                    name: 'lax-public-subnet-2',
                    subnetType: ec2.SubnetType.PUBLIC,
                },
                {
                    cidrMask: 24,
                    name: 'lax-private-subnet-1',
                    subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
                },
                {
                    cidrMask: 24,
                    name: 'lax-private-subnet-2',
                    subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
                }
            ],
        });
        // Create an ECS cluster with Fargate and Fargate Spot capacity providers
        const cluster = new ecs.Cluster(this, 'Cluster', {
            enableFargateCapacityProviders: true,
            vpc: vpc,
        });

        // Create a Cloud Map namespace for service discovery
        const namespace = new servicediscovery.PrivateDnsNamespace(this, 'Namespace', {
            name: 'search-namespace.local',
            vpc: cluster.vpc,
        });

        const dockerImageUriParameter = ssm.StringParameter.fromStringParameterName(this, 'DockerImageUriParam', props.dockerImageUriParam);

        const executionRole = new iam.Role(this, 'TaskExecutionRole', {
            assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'),
        });

        executionRole.addManagedPolicy(
            iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonECSTaskExecutionRolePolicy')
        );

        // Create a task definition for your application
        const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDefinition', {
            memoryLimitMiB: 512,
            cpu: 256,
            executionRole: executionRole,
        });

        // Add your application container to the task definition
        const appContainer = taskDefinition.addContainer('AppContainer', {
            image: ecs.ContainerImage.fromRegistry(dockerImageUriParameter.stringValue),
            portMappings: [{ containerPort: 8080 }],
        });

        // Create a Fargate service with Spot capacity provider
        const service = new ecs.FargateService(this, 'Service', {
            cluster,
            taskDefinition,
            capacityProviderStrategies: [
                {
                    capacityProvider: 'FARGATE_SPOT',
                    weight: 4,
                },
                {
                    capacityProvider: 'FARGATE',
                    weight: 1,
                },
            ],
            cloudMapOptions: {
                name: 'search-service',
                cloudMapNamespace: namespace,
                dnsRecordType: servicediscovery.DnsRecordType.A,
            },
        });

        // Create a CloudFront distribution with the service as the origin
        const distribution = new cloudfront.Distribution(this, 'Distribution', {
            defaultBehavior: {
                origin: new origins.HttpOrigin(`search-service.${namespace.namespaceName}`, {
                    protocolPolicy: cloudfront.OriginProtocolPolicy.HTTP_ONLY,
                }),
                viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
                allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
                cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
                compress: true,
            },
            httpVersion: cloudfront.HttpVersion.HTTP3,
        });
    }
}

The error on cdk deploy is:

DeployStack | 42/44 | 11:56:31 PM | CREATE_FAILED | AWS::ECS::Service | Service/Service (ServiceD69D759B) Resource creation cancelled

  • I got past the original error by switching to an EC2 launch type, but now I'm stuck in AWS::ECS::Service CREATE_IN_PROGRESS

1 Answer
1
Accepted Answer

Hello,

After reviewing the ECS Service Discovery documentation, I regret to inform you that the proposed setup for integrating Amazon CloudFront with an Amazon ECS service hosted in a private subnet would not be feasible. The documentation states:

The DNS records created for a service discovery service always register with the private IP address for the task, rather than the public IP address, even when public namespaces are used.

As Amazon CloudFront is an Internet-facing service, it requires access to content through a publicly accessible origin. However, Amazon ECS tasks running in a private subnet are not accessible from the Internet, thereby preventing CloudFront from retrieving the content.

Troubleshooting CloudFormation Stack Deployment

Regarding the issue with the CREATE_IN_PROGRESS state for the CloudFormation stack, I would recommend the following steps:

  1. Review the ECS Service events in the AWS Management Console for any relevant error messages or logs.
  2. Verify if the EC2 instances are successfully registering with the ECS Cluster. If they are not, please refer to the Knowledge Center article for further troubleshooting guidance.

Please let me know if you require any further assistance or have additional questions.

profile pictureAWS
answered a month ago
profile picture
EXPERT
reviewed a month ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions