Search code examples
amazon-ecsaws-cdkinfrastructure-as-code

aws-ecs-patterns error: Cluster for this service needs Ec2 capacity. Call addXxxCapacity() on the cluster


Hoping someone can help me here, according to AWS CDK documentation if I declare my VPC then I shouldn't declare 'capacity', but when I run cdk synth I get the following error...

throw new Error(Validation failed with the following errors:\n ${errorList});

Error: Validation failed with the following errors: [PrerenderInfrasctutureStack/preRenderApp/Service] Cluster for this service needs Ec2 capacity. Call addXxxCapacity() on the cluster.

here is my code... (i hope Nathan Peck sees this)

const ec2 = require('@aws-cdk/aws-ec2');
const ecsPattern = require('@aws-cdk/aws-ecs-patterns');
const ecs = require('@aws-cdk/aws-ecs');
class PrerenderInfrasctutureStack extends cdk.Stack {
  /**
   *
   * @param {cdk.Construct} scope
   * @param {string} id
   * @param {cdk.StackProps=} props
   */


  constructor(scope, id, props) {
    super(scope, id, props);

    const myVPC = ec2.Vpc.fromLookup(this, 'publicVpc', {
      vpcId:'vpc-xxx'
    });


    const preRenderApp = new ecsPattern.ApplicationLoadBalancedEc2Service(this, 'preRenderApp', {
      vpcId: myVPC,
      certificate: 'arn:aws:acm:ap-southeast-2:xxx:certificate/xxx', //becuase this is spcified, then the LB will automatically use HTTPS
      domainName: 'my-dev.com.au.',
      domainZone:'my-dev.com.au',
      listenerPort: 443,
      publicLoadBalancer: true,
      memoryReservationMiB: 8,
      cpu: 4096,
      desiredCount: 1,
      taskImageOptions:{
        image: ecs.ContainerImage.fromRegistry('xxx.dkr.ecr.region.amazonaws.com/express-prerender-server'), 
        containerPort: 3000
      },
    });


  }

}


module.exports = { PrerenderInfrasctutureStack }


Solution

  • This is because if you don't explicitly pass a cluster then it uses the default cluster that exists on your account. However the default cluster starts out with no EC2 capacity, since EC2 instances cost money when they run. You can use the empty default cluster with Fargate mode since Fargate does not require EC2 capacity, it just runs your container inside Fargate, but the default cluster won't work with EC2 mode until you add EC2 instances to the cluster.

    The easy solution here is to switch to ApplicationLoadBalancedFargateService instead, because Fargate services run using Fargate capacity, so they don't require EC2 instances in the cluster. Alternatively you should define your own cluster using something like:

    // Create an ECS cluster
    const cluster = new ecs.Cluster(this, 'Cluster', {
      vpc,
    });
    
    // Add capacity to it
    cluster.addCapacity('DefaultAutoScalingGroupCapacity', {
      instanceType: new ec2.InstanceType("t2.xlarge"),
      desiredCapacity: 3,
    });
    

    Then pass that cluster as a property when creating the ApplicationLoadBalancedEc2Service

    Hope this helps!