CDKv2: ECS with EC2 launch type stuck in AWS::ECS::Service CREATE_IN_PROGRESS

0

Why doesn't this work? It gets stuck in AWS::ECS::Service CREATE_IN_PROGRESS:

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';
import * as autoscaling from 'aws-cdk-lib/aws-autoscaling';

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
        const cluster = new ecs.Cluster(this, 'Cluster', {
            vpc: vpc,
        });

        // Create a launch template
        const userData = ec2.UserData.forLinux();
        userData.addCommands(
            "echo ECS_CLUSTER=" + cluster.clusterName + " >> /etc/ecs/ecs.config",
            "yum install -y aws-cfn-bootstrap",
        );
        const launchTemplate = new ec2.LaunchTemplate(this, 'LaunchTemplate', {
            instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
            machineImage: ecs.EcsOptimizedImage.amazonLinux2(),
            userData: userData,
            role: new iam.Role(this, 'InstanceRole', {
                assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
                managedPolicies: [
                    iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonEC2ContainerServiceforEC2Role'),
                ],
            }),
        });

        // Create an Auto Scaling group using the launch template
        const autoScalingGroup = new autoscaling.AutoScalingGroup(this, 'ASG', {
            vpc,
            launchTemplate: launchTemplate,
            minCapacity: 1,
            maxCapacity: 2,
        });

        const capacityProvider = new ecs.AsgCapacityProvider(this, 'AsgCapacityProvider', {
            autoScalingGroup,
        });
        cluster.addAsgCapacityProvider(capacityProvider);

        // 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.Ec2TaskDefinition(this, 'TaskDefinition', {
            executionRole: executionRole,
        });

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

        // Create an EC2 service
        const service = new ecs.Ec2Service(this, 'Service', {
            cluster,
            taskDefinition,
            desiredCount: 1,
            cloudMapOptions: {
                name: 'search-service',
                cloudMapNamespace: namespace,
                dnsRecordType: servicediscovery.DnsRecordType.SRV,
            },
        });

        const scaling = service.autoScaleTaskCount(
            { maxCapacity: 2, minCapacity: 1 });
        scaling.scaleOnCpuUtilization('CpuScaling', {
            targetUtilizationPercent: 80,
        });

        // 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,
        // });
    }
}
1 Antwort
1
Akzeptierte Antwort

Hello.

Probably, but I suspect that the ECS task is not starting properly.
If EC2 is started in a private subnet (ec2.SubnetType.PRIVATE_ISOLATED) in a VPC subnet, there will be no access route to ECR, so I thought it would be necessary to configure a NAT Gateway and VPC endpoint.
https://repost.aws/knowledge-center/cloudformation-ecs-service-stabilize

So why not change the private subnet as shown below to use NAT Gateway?
https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.SubnetType.html

ec2.SubnetType.PRIVATE_WITH_NAT
profile picture
EXPERTE
beantwortet vor 2 Monaten
profile picture
EXPERTE
überprüft vor 2 Monaten

Du bist nicht angemeldet. Anmelden um eine Antwort zu veröffentlichen.

Eine gute Antwort beantwortet die Frage klar, gibt konstruktives Feedback und fördert die berufliche Weiterentwicklung des Fragenstellers.

Richtlinien für die Beantwortung von Fragen