From 50b477cf41fd439c5a83e923c96af45b179cc2b7 Mon Sep 17 00:00:00 2001 From: Dave Harmon Date: Tue, 9 Mar 2021 13:25:12 -0500 Subject: [PATCH] feat(aws-ecs-patterns): add circuitbreaker deployment configuration --- packages/@aws-cdk/aws-ecs-patterns/README.md | 26 ++++++++++++++++++- .../application-load-balanced-service-base.ts | 9 ++++++- .../network-load-balanced-service-base.ts | 9 ++++++- .../lib/base/queue-processing-service-base.ts | 9 ++++++- .../application-load-balanced-ecs-service.ts | 1 + .../ecs/network-load-balanced-ecs-service.ts | 1 + .../lib/ecs/queue-processing-ecs-service.ts | 1 + ...plication-load-balanced-fargate-service.ts | 1 + .../network-load-balanced-fargate-service.ts | 1 + .../queue-processing-fargate-service.ts | 1 + .../ec2/test.queue-processing-ecs-service.ts | 7 +++++ .../test.queue-processing-fargate-service.ts | 7 +++++ 12 files changed, 69 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-ecs-patterns/README.md b/packages/@aws-cdk/aws-ecs-patterns/README.md index a1072d47fe700..adb8ed95b0337 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/README.md +++ b/packages/@aws-cdk/aws-ecs-patterns/README.md @@ -413,6 +413,30 @@ const queueProcessingFargateService = new QueueProcessingFargateService(stack, ' }); ``` +### 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 queueProcessingFargateService = new ecs.QueueProcessingFargateService(stack, 'Service', { + cluster, + memoryLimitMiB: 512, + image: ecs.ContainerImage.fromRegistry('test'), + command: ["-c", "4", "amazon.com"], + enableLogging: false, + desiredTaskCount: 2, + environment: {}, + queue, + maxScalingCapacity: 5, + maxHealthyPercent: 200, + minHealthPercent: 66, + circuitBreaker: { rollback: true }, +}); +``` + ### Set taskSubnets and securityGroups for QueueProcessingFargateService ```ts @@ -469,7 +493,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 diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts index dde07a16e114c..89e29cceebeba 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts @@ -1,6 +1,6 @@ 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, @@ -226,6 +226,13 @@ 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 { diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts index 949b052aebbad..c8e696b1a581a 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts @@ -1,5 +1,5 @@ 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'; @@ -176,6 +176,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 { diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts index 2f72c6345c469..7537bc263dd4a 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts @@ -1,6 +1,6 @@ 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'; @@ -189,6 +189,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; } /** diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts index 2915fce6a48ff..ed606bb72c907 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts @@ -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); } diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts index 881a346c74f8a..4bae918ca67fc 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts @@ -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); } diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts index 6858813dfa9cc..985a4d2390e6b 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts @@ -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); diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts index fbb68aef84b2f..326a68529272b 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts @@ -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, }); diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts index 404d5429acfed..1f2618bbca314 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts @@ -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); diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts index 6444d05f81da6..57f9ec8403876 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts @@ -145,6 +145,7 @@ export class QueueProcessingFargateService extends QueueProcessingServiceBase { enableECSManagedTags: props.enableECSManagedTags, platformVersion: props.platformVersion, deploymentController: props.deploymentController, + circuitBreaker: props.circuitBreaker, securityGroups: props.securityGroups, vpcSubnets: props.taskSubnets, assignPublicIp: props.assignPublicIp, diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts index 2c410f6581b1e..93c9ab4607b72 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts @@ -212,12 +212,19 @@ export = { 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. expect(stack).to(haveResource('AWS::ECS::Service', { DesiredCount: 2, DeploymentConfiguration: { + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, MinimumHealthyPercent: 60, MaximumPercent: 150, }, diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts index 27671ae22e70d..1a38d1a554021 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts @@ -347,12 +347,19 @@ export = { deploymentController: { type: ecs.DeploymentControllerType.CODE_DEPLOY, }, + circuitBreaker: { + rollback: true, + }, }); // THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set. expect(stack).to(haveResource('AWS::ECS::Service', { DesiredCount: 2, DeploymentConfiguration: { + DeploymentCircuitBreaker: { + Enable: true, + Rollback: true, + }, MinimumHealthyPercent: 60, MaximumPercent: 150, },