Skip to content

Commit

Permalink
feat(ecs-patterns): Add ECS deployment circuit breaker support to hig…
Browse files Browse the repository at this point in the history
…her-level constructs (#12719)

Fixes #12534
Fixes #12360

This change adds the option to set the `circuitBreaker` on the higher-level constructs such as ApplicationLoadBalancedFargateService

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
ridha authored Mar 15, 2021
1 parent 20a2820 commit e80a98a
Show file tree
Hide file tree
Showing 20 changed files with 1,791 additions and 16 deletions.
21 changes: 20 additions & 1 deletion packages/@aws-cdk/aws-ecs-patterns/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,25 @@ const loadBalancedFargateService = new ApplicationLoadBalancedFargateService(sta
});
```

### Deployment circuit breaker and rollback

Amazon ECS [deployment circuit breaker](https://aws.amazon.com/tw/blogs/containers/announcing-amazon-ecs-deployment-circuit-breaker/)
automatically rolls back unhealthy service deployments without the need for manual intervention. Use `circuitBreaker` to enable
deployment circuit breaker and optionally enable `rollback` for automatic rollback. See [Using the deployment circuit breaker](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-type-ecs.html)
for more details.

```ts
const service = new ApplicationLoadBalancedFargateService(stack, 'Service', {
cluster,
memoryLimitMiB: 1024,
desiredCount: 1,
cpu: 512,
taskImageOptions: {
image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"),
},
circuitBreaker: { rollback: true },
});
```

### Set deployment configuration on QueueProcessingService

Expand Down Expand Up @@ -469,7 +488,7 @@ const scheduledFargateTask = new ScheduledFargateTask(stack, 'ScheduledFargateTa

### Use the REMOVE_DEFAULT_DESIRED_COUNT feature flag

The REMOVE_DEFAULT_DESIRED_COUNT feature flag is used to override the default desiredCount that is autogenerated by the CDK. This will set the desiredCount of any service created by any of the following constructs to be undefined.
The REMOVE_DEFAULT_DESIRED_COUNT feature flag is used to override the default desiredCount that is autogenerated by the CDK. This will set the desiredCount of any service created by any of the following constructs to be undefined.

* ApplicationLoadBalancedEc2Service
* ApplicationLoadBalancedFargateService
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Certificate, CertificateValidation, ICertificate } from '@aws-cdk/aws-certificatemanager';
import { IVpc } from '@aws-cdk/aws-ec2';
import { AwsLogDriver, BaseService, CloudMapOptions, Cluster, ContainerImage, DeploymentController, ICluster, LogDriver, PropagatedTagSource, Secret } from '@aws-cdk/aws-ecs';
import {
AwsLogDriver, BaseService, CloudMapOptions, Cluster, ContainerImage, DeploymentController, DeploymentCircuitBreaker,
ICluster, LogDriver, PropagatedTagSource, Secret,
} from '@aws-cdk/aws-ecs';
import {
ApplicationListener, ApplicationLoadBalancer, ApplicationProtocol, ApplicationTargetGroup,
IApplicationLoadBalancer, ListenerCertificate, ListenerAction, AddApplicationTargetsProps,
Expand Down Expand Up @@ -226,6 +229,14 @@ export interface ApplicationLoadBalancedServiceBaseProps {
* @default - Rolling update (ECS)
*/
readonly deploymentController?: DeploymentController;

/**
* Whether to enable the deployment circuit breaker. If this property is defined, circuit breaker will be implicitly
* enabled.
* @default - disabled
*/
readonly circuitBreaker?: DeploymentCircuitBreaker;

}

export interface ApplicationLoadBalancedTaskImageOptions {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { IVpc } from '@aws-cdk/aws-ec2';
import { AwsLogDriver, BaseService, CloudMapOptions, Cluster, ContainerImage, DeploymentController, ICluster, LogDriver, PropagatedTagSource, Secret } from '@aws-cdk/aws-ecs';
import {
AwsLogDriver, BaseService, CloudMapOptions, Cluster, ContainerImage, DeploymentController, DeploymentCircuitBreaker,
ICluster, LogDriver, PropagatedTagSource, Secret,
} from '@aws-cdk/aws-ecs';
import { INetworkLoadBalancer, NetworkListener, NetworkLoadBalancer, NetworkTargetGroup } from '@aws-cdk/aws-elasticloadbalancingv2';
import { IRole } from '@aws-cdk/aws-iam';
import { ARecord, CnameRecord, IHostedZone, RecordTarget } from '@aws-cdk/aws-route53';
Expand Down Expand Up @@ -176,6 +179,13 @@ export interface NetworkLoadBalancedServiceBaseProps {
* @default - Rolling update (ECS)
*/
readonly deploymentController?: DeploymentController;

/**
* Whether to enable the deployment circuit breaker. If this property is defined, circuit breaker will be implicitly
* enabled.
* @default - disabled
*/
readonly circuitBreaker?: DeploymentCircuitBreaker;
}

export interface NetworkLoadBalancedTaskImageOptions {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { ScalingInterval } from '@aws-cdk/aws-applicationautoscaling';
import { IVpc } from '@aws-cdk/aws-ec2';
import { AwsLogDriver, BaseService, Cluster, ContainerImage, DeploymentController, ICluster, LogDriver, PropagatedTagSource, Secret } from '@aws-cdk/aws-ecs';
import {
AwsLogDriver, BaseService, Cluster, ContainerImage, DeploymentController, DeploymentCircuitBreaker,
ICluster, LogDriver, PropagatedTagSource, Secret,
} from '@aws-cdk/aws-ecs';
import { IQueue, Queue } from '@aws-cdk/aws-sqs';
import { CfnOutput, Duration, Stack } from '@aws-cdk/core';
import * as cxapi from '@aws-cdk/cx-api';
Expand Down Expand Up @@ -189,6 +192,13 @@ export interface QueueProcessingServiceBaseProps {
* @default - Rolling update (ECS)
*/
readonly deploymentController?: DeploymentController;

/**
* Whether to enable the deployment circuit breaker. If this property is defined, circuit breaker will be implicitly
* enabled.
* @default - disabled
*/
readonly circuitBreaker?: DeploymentCircuitBreaker;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export class ApplicationLoadBalancedEc2Service extends ApplicationLoadBalancedSe
enableECSManagedTags: props.enableECSManagedTags,
cloudMapOptions: props.cloudMapOptions,
deploymentController: props.deploymentController,
circuitBreaker: props.circuitBreaker,
});
this.addServiceAsTarget(this.service);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export class NetworkLoadBalancedEc2Service extends NetworkLoadBalancedServiceBas
enableECSManagedTags: props.enableECSManagedTags,
cloudMapOptions: props.cloudMapOptions,
deploymentController: props.deploymentController,
circuitBreaker: props.circuitBreaker,
});
this.addServiceAsTarget(this.service);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export class QueueProcessingEc2Service extends QueueProcessingServiceBase {
propagateTags: props.propagateTags,
enableECSManagedTags: props.enableECSManagedTags,
deploymentController: props.deploymentController,
circuitBreaker: props.circuitBreaker,
});

this.configureAutoscalingForService(this.service);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ export class ApplicationLoadBalancedFargateService extends ApplicationLoadBalanc
cloudMapOptions: props.cloudMapOptions,
platformVersion: props.platformVersion,
deploymentController: props.deploymentController,
circuitBreaker: props.circuitBreaker,
securityGroups: props.securityGroups,
vpcSubnets: props.taskSubnets,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export class NetworkLoadBalancedFargateService extends NetworkLoadBalancedServic
cloudMapOptions: props.cloudMapOptions,
platformVersion: props.platformVersion,
deploymentController: props.deploymentController,
circuitBreaker: props.circuitBreaker,
vpcSubnets: props.taskSubnets,
});
this.addServiceAsTarget(this.service);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ export class QueueProcessingFargateService extends QueueProcessingServiceBase {
securityGroups: props.securityGroups,
vpcSubnets: props.taskSubnets,
assignPublicIp: props.assignPublicIp,
circuitBreaker: props.circuitBreaker,
});

this.configureAutoscalingForService(this.service);
Expand Down
66 changes: 66 additions & 0 deletions packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,72 @@ export = {
test.done();
},

'ALB with circuit breaker'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'VPC');
const cluster = new ecs.Cluster(stack, 'Cluster', { vpc });
cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') });

// WHEN
new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', {
cluster,
memoryLimitMiB: 1024,
taskImageOptions: {
image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
},
circuitBreaker: { rollback: true },
});

// THEN
expect(stack).to(haveResourceLike('AWS::ECS::Service', {
DeploymentConfiguration: {
DeploymentCircuitBreaker: {
Enable: true,
Rollback: true,
},
},
DeploymentController: {
Type: 'ECS',
},
}));

test.done();
},

'NLB with circuit breaker'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'VPC');
const cluster = new ecs.Cluster(stack, 'Cluster', { vpc });
cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') });

// WHEN
new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', {
cluster,
memoryLimitMiB: 1024,
taskImageOptions: {
image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
},
circuitBreaker: { rollback: true },
});

// THEN
expect(stack).to(haveResourceLike('AWS::ECS::Service', {
DeploymentConfiguration: {
DeploymentCircuitBreaker: {
Enable: true,
Rollback: true,
},
},
DeploymentController: {
Type: 'ECS',
},
}));

test.done();
},

'NetworkLoadbalancedEC2Service accepts previously created load balancer'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,7 @@ export = {
maxHealthyPercent: 150,
serviceName: 'ecs-test-service',
family: 'ecs-task-family',
deploymentController: {
type: ecs.DeploymentControllerType.CODE_DEPLOY,
},
circuitBreaker: { rollback: true },
});

// THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all optional properties are set.
Expand All @@ -220,11 +218,15 @@ export = {
DeploymentConfiguration: {
MinimumHealthyPercent: 60,
MaximumPercent: 150,
DeploymentCircuitBreaker: {
Enable: true,
Rollback: true,
},
},
LaunchType: 'EC2',
ServiceName: 'ecs-test-service',
DeploymentController: {
Type: 'CODE_DEPLOY',
Type: 'ECS',
},
}));

Expand Down
Loading

0 comments on commit e80a98a

Please sign in to comment.