Skip to content

Commit e80a98a

Browse files
authored
feat(ecs-patterns): Add ECS deployment circuit breaker support to higher-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*
1 parent 20a2820 commit e80a98a

20 files changed

+1791
-16
lines changed

packages/@aws-cdk/aws-ecs-patterns/README.md

+20-1
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,25 @@ const loadBalancedFargateService = new ApplicationLoadBalancedFargateService(sta
394394
});
395395
```
396396

397+
### Deployment circuit breaker and rollback
398+
399+
Amazon ECS [deployment circuit breaker](https://aws.amazon.com/tw/blogs/containers/announcing-amazon-ecs-deployment-circuit-breaker/)
400+
automatically rolls back unhealthy service deployments without the need for manual intervention. Use `circuitBreaker` to enable
401+
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)
402+
for more details.
403+
404+
```ts
405+
const service = new ApplicationLoadBalancedFargateService(stack, 'Service', {
406+
cluster,
407+
memoryLimitMiB: 1024,
408+
desiredCount: 1,
409+
cpu: 512,
410+
taskImageOptions: {
411+
image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"),
412+
},
413+
circuitBreaker: { rollback: true },
414+
});
415+
```
397416

398417
### Set deployment configuration on QueueProcessingService
399418

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

470489
### Use the REMOVE_DEFAULT_DESIRED_COUNT feature flag
471490

472-
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.
491+
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.
473492

474493
* ApplicationLoadBalancedEc2Service
475494
* ApplicationLoadBalancedFargateService

packages/@aws-cdk/aws-ecs-patterns/lib/base/application-load-balanced-service-base.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { Certificate, CertificateValidation, ICertificate } from '@aws-cdk/aws-certificatemanager';
22
import { IVpc } from '@aws-cdk/aws-ec2';
3-
import { AwsLogDriver, BaseService, CloudMapOptions, Cluster, ContainerImage, DeploymentController, ICluster, LogDriver, PropagatedTagSource, Secret } from '@aws-cdk/aws-ecs';
3+
import {
4+
AwsLogDriver, BaseService, CloudMapOptions, Cluster, ContainerImage, DeploymentController, DeploymentCircuitBreaker,
5+
ICluster, LogDriver, PropagatedTagSource, Secret,
6+
} from '@aws-cdk/aws-ecs';
47
import {
58
ApplicationListener, ApplicationLoadBalancer, ApplicationProtocol, ApplicationTargetGroup,
69
IApplicationLoadBalancer, ListenerCertificate, ListenerAction, AddApplicationTargetsProps,
@@ -226,6 +229,14 @@ export interface ApplicationLoadBalancedServiceBaseProps {
226229
* @default - Rolling update (ECS)
227230
*/
228231
readonly deploymentController?: DeploymentController;
232+
233+
/**
234+
* Whether to enable the deployment circuit breaker. If this property is defined, circuit breaker will be implicitly
235+
* enabled.
236+
* @default - disabled
237+
*/
238+
readonly circuitBreaker?: DeploymentCircuitBreaker;
239+
229240
}
230241

231242
export interface ApplicationLoadBalancedTaskImageOptions {

packages/@aws-cdk/aws-ecs-patterns/lib/base/network-load-balanced-service-base.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { IVpc } from '@aws-cdk/aws-ec2';
2-
import { AwsLogDriver, BaseService, CloudMapOptions, Cluster, ContainerImage, DeploymentController, ICluster, LogDriver, PropagatedTagSource, Secret } from '@aws-cdk/aws-ecs';
2+
import {
3+
AwsLogDriver, BaseService, CloudMapOptions, Cluster, ContainerImage, DeploymentController, DeploymentCircuitBreaker,
4+
ICluster, LogDriver, PropagatedTagSource, Secret,
5+
} from '@aws-cdk/aws-ecs';
36
import { INetworkLoadBalancer, NetworkListener, NetworkLoadBalancer, NetworkTargetGroup } from '@aws-cdk/aws-elasticloadbalancingv2';
47
import { IRole } from '@aws-cdk/aws-iam';
58
import { ARecord, CnameRecord, IHostedZone, RecordTarget } from '@aws-cdk/aws-route53';
@@ -176,6 +179,13 @@ export interface NetworkLoadBalancedServiceBaseProps {
176179
* @default - Rolling update (ECS)
177180
*/
178181
readonly deploymentController?: DeploymentController;
182+
183+
/**
184+
* Whether to enable the deployment circuit breaker. If this property is defined, circuit breaker will be implicitly
185+
* enabled.
186+
* @default - disabled
187+
*/
188+
readonly circuitBreaker?: DeploymentCircuitBreaker;
179189
}
180190

181191
export interface NetworkLoadBalancedTaskImageOptions {

packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { ScalingInterval } from '@aws-cdk/aws-applicationautoscaling';
22
import { IVpc } from '@aws-cdk/aws-ec2';
3-
import { AwsLogDriver, BaseService, Cluster, ContainerImage, DeploymentController, ICluster, LogDriver, PropagatedTagSource, Secret } from '@aws-cdk/aws-ecs';
3+
import {
4+
AwsLogDriver, BaseService, Cluster, ContainerImage, DeploymentController, DeploymentCircuitBreaker,
5+
ICluster, LogDriver, PropagatedTagSource, Secret,
6+
} from '@aws-cdk/aws-ecs';
47
import { IQueue, Queue } from '@aws-cdk/aws-sqs';
58
import { CfnOutput, Duration, Stack } from '@aws-cdk/core';
69
import * as cxapi from '@aws-cdk/cx-api';
@@ -189,6 +192,13 @@ export interface QueueProcessingServiceBaseProps {
189192
* @default - Rolling update (ECS)
190193
*/
191194
readonly deploymentController?: DeploymentController;
195+
196+
/**
197+
* Whether to enable the deployment circuit breaker. If this property is defined, circuit breaker will be implicitly
198+
* enabled.
199+
* @default - disabled
200+
*/
201+
readonly circuitBreaker?: DeploymentCircuitBreaker;
192202
}
193203

194204
/**

packages/@aws-cdk/aws-ecs-patterns/lib/ecs/application-load-balanced-ecs-service.ts

+1
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ export class ApplicationLoadBalancedEc2Service extends ApplicationLoadBalancedSe
133133
enableECSManagedTags: props.enableECSManagedTags,
134134
cloudMapOptions: props.cloudMapOptions,
135135
deploymentController: props.deploymentController,
136+
circuitBreaker: props.circuitBreaker,
136137
});
137138
this.addServiceAsTarget(this.service);
138139
}

packages/@aws-cdk/aws-ecs-patterns/lib/ecs/network-load-balanced-ecs-service.ts

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ export class NetworkLoadBalancedEc2Service extends NetworkLoadBalancedServiceBas
131131
enableECSManagedTags: props.enableECSManagedTags,
132132
cloudMapOptions: props.cloudMapOptions,
133133
deploymentController: props.deploymentController,
134+
circuitBreaker: props.circuitBreaker,
134135
});
135136
this.addServiceAsTarget(this.service);
136137
}

packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export class QueueProcessingEc2Service extends QueueProcessingServiceBase {
114114
propagateTags: props.propagateTags,
115115
enableECSManagedTags: props.enableECSManagedTags,
116116
deploymentController: props.deploymentController,
117+
circuitBreaker: props.circuitBreaker,
117118
});
118119

119120
this.configureAutoscalingForService(this.service);

packages/@aws-cdk/aws-ecs-patterns/lib/fargate/application-load-balanced-fargate-service.ts

+1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ export class ApplicationLoadBalancedFargateService extends ApplicationLoadBalanc
170170
cloudMapOptions: props.cloudMapOptions,
171171
platformVersion: props.platformVersion,
172172
deploymentController: props.deploymentController,
173+
circuitBreaker: props.circuitBreaker,
173174
securityGroups: props.securityGroups,
174175
vpcSubnets: props.taskSubnets,
175176
});

packages/@aws-cdk/aws-ecs-patterns/lib/fargate/network-load-balanced-fargate-service.ts

+1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ export class NetworkLoadBalancedFargateService extends NetworkLoadBalancedServic
157157
cloudMapOptions: props.cloudMapOptions,
158158
platformVersion: props.platformVersion,
159159
deploymentController: props.deploymentController,
160+
circuitBreaker: props.circuitBreaker,
160161
vpcSubnets: props.taskSubnets,
161162
});
162163
this.addServiceAsTarget(this.service);

packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts

+1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ export class QueueProcessingFargateService extends QueueProcessingServiceBase {
148148
securityGroups: props.securityGroups,
149149
vpcSubnets: props.taskSubnets,
150150
assignPublicIp: props.assignPublicIp,
151+
circuitBreaker: props.circuitBreaker,
151152
});
152153

153154
this.configureAutoscalingForService(this.service);

packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts

+66
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,72 @@ export = {
10981098
test.done();
10991099
},
11001100

1101+
'ALB with circuit breaker'(test: Test) {
1102+
// GIVEN
1103+
const stack = new cdk.Stack();
1104+
const vpc = new ec2.Vpc(stack, 'VPC');
1105+
const cluster = new ecs.Cluster(stack, 'Cluster', { vpc });
1106+
cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') });
1107+
1108+
// WHEN
1109+
new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', {
1110+
cluster,
1111+
memoryLimitMiB: 1024,
1112+
taskImageOptions: {
1113+
image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
1114+
},
1115+
circuitBreaker: { rollback: true },
1116+
});
1117+
1118+
// THEN
1119+
expect(stack).to(haveResourceLike('AWS::ECS::Service', {
1120+
DeploymentConfiguration: {
1121+
DeploymentCircuitBreaker: {
1122+
Enable: true,
1123+
Rollback: true,
1124+
},
1125+
},
1126+
DeploymentController: {
1127+
Type: 'ECS',
1128+
},
1129+
}));
1130+
1131+
test.done();
1132+
},
1133+
1134+
'NLB with circuit breaker'(test: Test) {
1135+
// GIVEN
1136+
const stack = new cdk.Stack();
1137+
const vpc = new ec2.Vpc(stack, 'VPC');
1138+
const cluster = new ecs.Cluster(stack, 'Cluster', { vpc });
1139+
cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') });
1140+
1141+
// WHEN
1142+
new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', {
1143+
cluster,
1144+
memoryLimitMiB: 1024,
1145+
taskImageOptions: {
1146+
image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
1147+
},
1148+
circuitBreaker: { rollback: true },
1149+
});
1150+
1151+
// THEN
1152+
expect(stack).to(haveResourceLike('AWS::ECS::Service', {
1153+
DeploymentConfiguration: {
1154+
DeploymentCircuitBreaker: {
1155+
Enable: true,
1156+
Rollback: true,
1157+
},
1158+
},
1159+
DeploymentController: {
1160+
Type: 'ECS',
1161+
},
1162+
}));
1163+
1164+
test.done();
1165+
},
1166+
11011167
'NetworkLoadbalancedEC2Service accepts previously created load balancer'(test: Test) {
11021168
// GIVEN
11031169
const stack = new cdk.Stack();

packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,7 @@ export = {
209209
maxHealthyPercent: 150,
210210
serviceName: 'ecs-test-service',
211211
family: 'ecs-task-family',
212-
deploymentController: {
213-
type: ecs.DeploymentControllerType.CODE_DEPLOY,
214-
},
212+
circuitBreaker: { rollback: true },
215213
});
216214

217215
// THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all optional properties are set.
@@ -220,11 +218,15 @@ export = {
220218
DeploymentConfiguration: {
221219
MinimumHealthyPercent: 60,
222220
MaximumPercent: 150,
221+
DeploymentCircuitBreaker: {
222+
Enable: true,
223+
Rollback: true,
224+
},
223225
},
224226
LaunchType: 'EC2',
225227
ServiceName: 'ecs-test-service',
226228
DeploymentController: {
227-
Type: 'CODE_DEPLOY',
229+
Type: 'ECS',
228230
},
229231
}));
230232

0 commit comments

Comments
 (0)