aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.41k stars 3.8k forks source link

aws_ecs: Cannot get a service to use the default capacity provider strategy #24961

Open SydneyUni-Jim opened 1 year ago

SydneyUni-Jim commented 1 year ago

Describe the bug

The L2 constructs EC2Service and FargateService don't have an interface for having them use the default capacity provider strategy from the cluster.

Expected Behavior

Don't include the LaunchType when the cluster's default capacity provider strategy needs to be used.

Current Behavior

The CFT for an ECS service always includes a LaunchType unless there is a custom capacity provider strategy or an external deployment controller type.

Reproduction Steps

import * as ecs from 'aws-cdk-lib/aws-ecs'

// …

const ecsCluster = new ecs.Cluster(this, 'EcsCluster', {
  enableFargateCapacityProviders: true,
  vpc,
})
ecsCluster.addDefaultCapacityProviderStrategy([
  { capacityProvider: 'FARGATE_SPOT', base: 1, weight: 1 },
])
const ecsService = new ecs.FargateService(this, 'FargateService', {
  // … but no capacityProviderStrategies
})
  1. Set the service's desired capacity to 2.
  2. Observe that the service's tasks have no capacity provider.
  3. Set the service's desired capacity to 0.
  4. Apply to workaround.
  5. Set the service's desired capacity to 2.
  6. Observe that the service's tasks have the FARGATE_SPOT capacity provider.

Possible Solution

Workaround
// Use the cluster's default capacity provider strategy
const cfnService = ecsService.node.defaultChild as ecs.CfnService
cfnService.addPropertyDeletionOverride('LaunchType')

But see https://github.com/aws/aws-cdk/issues/24961#issuecomment-1499027348 before you do this.

Additional Information/Context

From the AWS documentation at https://docs.aws.amazon.com/AmazonECS/latest/userguide/cluster-capacity-providers.html

[…] a default capacity provider strategy is used when creating a service or running a standalone task in the cluster and whenever a custom capacity provider strategy or a launch type isn't specified.

So both the custom capacity provider strategy and the launch type must not be specified for the default capacity provider strategy to be used.

CDK CLI Version

2.72.1 (build ddbfac7)

Framework Version

2.72.1

Node.js Version

v19.8.1

OS

macOS v13.3 aarch64

Language

Typescript

Language Version

TypeScript (4.9.5)

Other information

No response

pahud commented 1 year ago

We probably can improve the user experience to switch between default capacity provider strategy and launchType in this scenario. But at this moment you should consider to use the sample below rather than property deletion override.


export class Demotack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const vpc = getDefaultVpc(this);

    const ecsCluster = new ecs.Cluster(this, 'EcsCluster', {
      enableFargateCapacityProviders: true,
      vpc,
    })
    ecsCluster.addDefaultCapacityProviderStrategy([
      { capacityProvider: 'FARGATE_SPOT', base: 1, weight: 1 },
    ])
    const taskDefinition = new FargateTaskDefinition(this, 'Task');
    const ecsService = new ecs.FargateService(this, 'FargateService', {
      capacityProviderStrategies: [ { capacityProvider: 'FARGATE_SPOT', base: 1, weight: 1 } ],
      cluster: ecsCluster,
      taskDefinition,
    });
    taskDefinition.addContainer('nginx', {
      image: ecs.ContainerImage.fromRegistry('nginx'),
      portMappings: [{containerPort: 80}],
    })
  }
}

I am leaving this issue open as p2 feature request and welcome any PR to improve user experience in this use case.

SydneyUni-Jim commented 1 year ago

In real use case, my stack doesn't define the cluster and I don't know what the default capacity provider strategy is. I'm reluctant to discover that during synth.

Irame commented 4 months ago

I had the same problem with an Ec2Service and solved it by providing an empty array for capacityProviderStrategies. Since this is implemented in the BaseService I assume its the same for a FargateService.