Skip to content

Commit 5b4e32c

Browse files
author
Abdul Kader Maliyakkal
committed
Add ECS deployment circuit breaker support to higher-level constructs
1 parent fe37174 commit 5b4e32c

14 files changed

+191
-3
lines changed

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

+23
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,29 @@ const loadBalancedFargateService = new ApplicationLoadBalancedFargateService(sta
393393
});
394394
```
395395

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

398421
```ts

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,
@@ -224,6 +227,14 @@ export interface ApplicationLoadBalancedServiceBaseProps {
224227
* @default - Rolling update (ECS)
225228
*/
226229
readonly deploymentController?: DeploymentController;
230+
231+
/**
232+
* Whether to enable the deployment circuit breaker. If this property is defined, circuit breaker will be implicitly
233+
* enabled.
234+
* @default - disabled
235+
*/
236+
readonly circuitBreaker?: DeploymentCircuitBreaker;
237+
227238
}
228239

229240
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';
@@ -174,6 +177,13 @@ export interface NetworkLoadBalancedServiceBaseProps {
174177
* @default - Rolling update (ECS)
175178
*/
176179
readonly deploymentController?: DeploymentController;
180+
181+
/**
182+
* Whether to enable the deployment circuit breaker. If this property is defined, circuit breaker will be implicitly
183+
* enabled.
184+
* @default - disabled
185+
*/
186+
readonly circuitBreaker?: DeploymentCircuitBreaker;
177187
}
178188

179189
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 { Construct } from 'constructs';
@@ -178,6 +181,13 @@ export interface QueueProcessingServiceBaseProps {
178181
* @default - Rolling update (ECS)
179182
*/
180183
readonly deploymentController?: DeploymentController;
184+
185+
/**
186+
* Whether to enable the deployment circuit breaker. If this property is defined, circuit breaker will be implicitly
187+
* enabled.
188+
* @default - disabled
189+
*/
190+
readonly circuitBreaker?: DeploymentCircuitBreaker;
181191
}
182192

183193
/**

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

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

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

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

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

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export class QueueProcessingEc2Service extends QueueProcessingServiceBase {
110110
propagateTags: props.propagateTags,
111111
enableECSManagedTags: props.enableECSManagedTags,
112112
deploymentController: props.deploymentController,
113+
circuitBreaker: props.circuitBreaker,
113114
});
114115
this.configureAutoscalingForService(this.service);
115116
this.grantPermissionsToService(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
@@ -167,6 +167,7 @@ export class ApplicationLoadBalancedFargateService extends ApplicationLoadBalanc
167167
cloudMapOptions: props.cloudMapOptions,
168168
platformVersion: props.platformVersion,
169169
deploymentController: props.deploymentController,
170+
circuitBreaker: props.circuitBreaker,
170171
securityGroups: props.securityGroups,
171172
vpcSubnets: props.taskSubnets,
172173
});

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

+1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ export class NetworkLoadBalancedFargateService extends NetworkLoadBalancedServic
156156
cloudMapOptions: props.cloudMapOptions,
157157
platformVersion: props.platformVersion,
158158
deploymentController: props.deploymentController,
159+
circuitBreaker: props.circuitBreaker,
159160
vpcSubnets: props.taskSubnets,
160161
});
161162
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
@@ -117,6 +117,7 @@ export class QueueProcessingFargateService extends QueueProcessingServiceBase {
117117
enableECSManagedTags: props.enableECSManagedTags,
118118
platformVersion: props.platformVersion,
119119
deploymentController: props.deploymentController,
120+
circuitBreaker: props.circuitBreaker,
120121
});
121122
this.configureAutoscalingForService(this.service);
122123
this.grantPermissionsToService(this.service);

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

+66
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,72 @@ export = {
10011001
test.done();
10021002
},
10031003

1004+
'ALB with circuit breaker'(test: Test) {
1005+
// GIVEN
1006+
const stack = new cdk.Stack();
1007+
const vpc = new ec2.Vpc(stack, 'VPC');
1008+
const cluster = new ecs.Cluster(stack, 'Cluster', { vpc });
1009+
cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') });
1010+
1011+
// WHEN
1012+
new ecsPatterns.ApplicationLoadBalancedEc2Service(stack, 'Service', {
1013+
cluster,
1014+
memoryLimitMiB: 1024,
1015+
taskImageOptions: {
1016+
image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
1017+
},
1018+
deploymentController: {
1019+
type: ecs.DeploymentControllerType.ECS,
1020+
},
1021+
circuitBreaker: { rollback: true },
1022+
});
1023+
1024+
// THEN
1025+
expect(stack).to(haveResourceLike('AWS::ECS::Service', {
1026+
DeploymentConfiguration: {
1027+
DeploymentCircuitBreaker: {
1028+
Enable: true,
1029+
Rollback: true,
1030+
},
1031+
},
1032+
}));
1033+
1034+
test.done();
1035+
},
1036+
1037+
'NLB with circuit breaker'(test: Test) {
1038+
// GIVEN
1039+
const stack = new cdk.Stack();
1040+
const vpc = new ec2.Vpc(stack, 'VPC');
1041+
const cluster = new ecs.Cluster(stack, 'Cluster', { vpc });
1042+
cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') });
1043+
1044+
// WHEN
1045+
new ecsPatterns.NetworkLoadBalancedEc2Service(stack, 'Service', {
1046+
cluster,
1047+
memoryLimitMiB: 1024,
1048+
taskImageOptions: {
1049+
image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
1050+
},
1051+
deploymentController: {
1052+
type: ecs.DeploymentControllerType.ECS,
1053+
},
1054+
circuitBreaker: { rollback: true },
1055+
});
1056+
1057+
// THEN
1058+
expect(stack).to(haveResourceLike('AWS::ECS::Service', {
1059+
DeploymentConfiguration: {
1060+
DeploymentCircuitBreaker: {
1061+
Enable: true,
1062+
Rollback: true,
1063+
},
1064+
},
1065+
}));
1066+
1067+
test.done();
1068+
},
1069+
10041070
'NetworkLoadbalancedEC2Service accepts previously created load balancer'(test: Test) {
10051071
// GIVEN
10061072
const stack = new cdk.Stack();

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

+5
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ export = {
186186
deploymentController: {
187187
type: ecs.DeploymentControllerType.CODE_DEPLOY,
188188
},
189+
circuitBreaker: { rollback: true },
189190
});
190191

191192
// THEN - QueueWorker is of EC2 launch type, an SQS queue is created and all optional properties are set.
@@ -194,6 +195,10 @@ export = {
194195
DeploymentConfiguration: {
195196
MinimumHealthyPercent: 60,
196197
MaximumPercent: 150,
198+
DeploymentCircuitBreaker: {
199+
Enable: true,
200+
Rollback: true,
201+
},
197202
},
198203
LaunchType: 'EC2',
199204
ServiceName: 'ecs-test-service',

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

+52
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,58 @@ export = {
427427
test.done();
428428
},
429429

430+
'setting ALB circuitBreaker works'(test: Test) {
431+
// GIVEN
432+
const stack = new cdk.Stack();
433+
434+
// WHEN
435+
new ecsPatterns.ApplicationLoadBalancedFargateService(stack, 'Service', {
436+
taskImageOptions: {
437+
image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'),
438+
},
439+
deploymentController: {
440+
type: ecs.DeploymentControllerType.ECS,
441+
},
442+
circuitBreaker: { rollback: true },
443+
});
444+
// THEN
445+
expect(stack).to(haveResourceLike('AWS::ECS::Service', {
446+
DeploymentConfiguration: {
447+
DeploymentCircuitBreaker: {
448+
Enable: true,
449+
Rollback: true,
450+
},
451+
},
452+
}));
453+
test.done();
454+
},
455+
456+
'setting NLB circuitBreaker works'(test: Test) {
457+
// GIVEN
458+
const stack = new cdk.Stack();
459+
460+
// WHEN
461+
new ecsPatterns.NetworkLoadBalancedFargateService(stack, 'Service', {
462+
taskImageOptions: {
463+
image: ecs.ContainerImage.fromRegistry('/aws/aws-example-app'),
464+
},
465+
deploymentController: {
466+
type: ecs.DeploymentControllerType.ECS,
467+
},
468+
circuitBreaker: { rollback: true },
469+
});
470+
// THEN
471+
expect(stack).to(haveResourceLike('AWS::ECS::Service', {
472+
DeploymentConfiguration: {
473+
DeploymentCircuitBreaker: {
474+
Enable: true,
475+
Rollback: true,
476+
},
477+
},
478+
}));
479+
test.done();
480+
},
481+
430482
'setting NLB special listener port to create the listener'(test: Test) {
431483
// GIVEN
432484
const stack = new cdk.Stack();

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

+5
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ export = {
231231
deploymentController: {
232232
type: ecs.DeploymentControllerType.CODE_DEPLOY,
233233
},
234+
circuitBreaker: { rollback: true },
234235
});
235236

236237
// THEN - QueueWorker is of FARGATE launch type, an SQS queue is created and all optional properties are set.
@@ -239,6 +240,10 @@ export = {
239240
DeploymentConfiguration: {
240241
MinimumHealthyPercent: 60,
241242
MaximumPercent: 150,
243+
DeploymentCircuitBreaker: {
244+
Enable: true,
245+
Rollback: true,
246+
},
242247
},
243248
LaunchType: 'FARGATE',
244249
ServiceName: 'fargate-test-service',

0 commit comments

Comments
 (0)