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