diff --git a/design/aws-ecs/aws-ecs-autoscaling-queue-worker.md b/design/aws-ecs/aws-ecs-autoscaling-queue-worker.md index 2d646ceb5f88c..148b3a23aa567 100644 --- a/design/aws-ecs/aws-ecs-autoscaling-queue-worker.md +++ b/design/aws-ecs/aws-ecs-autoscaling-queue-worker.md @@ -1,38 +1,38 @@ # AWS ECS - L3 Construct for Autoscaling ECS/Fargate Service that Processes Items in a SQS Queue -To address issue [#2396](https://github.com/awslabs/aws-cdk/issues/2396), the AWS ECS CDK construct library should provide a way for customers to create a queue worker service (an AWS ECS/Fargate service that processes items from an sqs queue). This would mean adding new ECS CDK constructs `Ec2QueueWorkerService` and `FargateQueryWorkerService`, that would take in the necessary properties required to create a task definition, an SQS queue as well as an ECS/Fargate service and enable autoscaling for the service based on cpu usage and the SQS queue's approximateNumberOfMessagesVisible metric. +To address issue [#2396](https://github.com/awslabs/aws-cdk/issues/2396), the AWS ECS CDK construct library should provide a way for customers to create a queue processing service (an AWS ECS/Fargate service that processes items from an sqs queue). This would mean adding new ECS CDK constructs `QueueProcessingEc2Service` and `QueueProcessingFargateService`, that would take in the necessary properties required to create a task definition, an SQS queue as well as an ECS/Fargate service and enable autoscaling for the service based on cpu usage and the SQS queue's approximateNumberOfMessagesVisible metric. ## General approach -The new `ecs.QueueWorkerServiceBase`, `ecs.Ec2QueueWorkerService` and `ecs.FargateQueueWorkerService` classes will create L3 constructs for: +The new `ecs.QueueProcessingServiceBase`, `ecs.QueueProcessingEc2Service` and `ecs.QueueProcessingFargateService` classes will create L3 constructs for: -* Ec2QueueWorkerService -* FargateQueueWorkerService +* QueueProcessingEc2Service +* QueueProcessingFargateService -A `QueueWorkerService` will create a task definition with the specified container (on both EC2 and Fargate). An AWS SQS `Queue` will be created and autoscaling of the ECS Service will be dependent on both CPU as well as the SQS queue's `ApproximateNumberOfMessagesVisible` metric. +A `QueueProcessingService` will create a task definition with the specified container (on both EC2 and Fargate). An AWS SQS `Queue` will be created and autoscaling of the ECS Service will be dependent on both CPU as well as the SQS queue's `ApproximateNumberOfMessagesVisible` metric. -The `QueueWorkerService` constructs (for EC2 and Fargate) will use the following existing constructs: +The `QueueProcessingService` constructs (for EC2 and Fargate) will use the following existing constructs: * Ec2TaskDefinition/FargateTaskDefinition - To create a Task Definition for the container to start -* SQSQueue - The queue that the worker is processing from +* SQSQueue - The queue that the service is processing from * Ec2Service/FargateService - The Service running the container ## Code changes -Given the above, we should make the following changes to support queue workers on ECS (for both EC2 and Fargate): -1. Create `QueueWorkerServiceBaseProps` interface and `QueueWorkerServiceBase` construct -2. Create `Ec2QueueWorkerServiceProps` interface and `Ec2QueueWorkerService` construct -3. Create `FargateQueueWorkerServiceProps` interface and `FargateQueueWorkerService` construct +Given the above, we should make the following changes to support queue processing on ECS (for both EC2 and Fargate): +1. Create `QueueProcessingServiceBaseProps` interface and `QueueProcessingServiceBase` construct +2. Create `QueueProcessingEc2ServiceProps` interface and `QueueProcessingEc2Service` construct +3. Create `QueueProcessingFargateServiceProps` interface and `QueueProcessingFargateService` construct -### Part 1: Create `QueueWorkerServiceBaseProps` interface and `QueueWorkerServiceBase` construct +### Part 1: Create `QueueProcessingServiceBaseProps` interface and `QueueProcessingServiceBase` construct -The `QueueWorkerServiceBaseProps` interface will contain common properties used to construct both the Ec2QueueWorkerService and the FargateQueueWorkerService: +The `QueueProcessingServiceBaseProps` interface will contain common properties used to construct both the QueueProcessingEc2Service and the QueueProcessingFargateService: ```ts /** - * Properties to define a Query Worker service + * Properties to define a queue processing service */ -export interface QueueWorkerServiceBaseProps { +export interface QueueProcessingServiceBaseProps { /** * Cluster where service will be deployed */ @@ -100,15 +100,15 @@ export interface QueueWorkerServiceBaseProps { } ``` -### Part 2: Create `Ec2QueueWorkerServiceProps` interface and `Ec2QueueWorkerService` construct +### Part 2: Create `QueueProcessingEc2ServiceProps` interface and `QueueProcessingEc2Service` construct -The `Ec2QueueWorkerServiceProps` interface will contain properties to construct the Ec2TaskDefinition, SQSQueue and Ec2Service: +The `QueueProcessingEc2ServiceProps` interface will contain properties to construct the Ec2TaskDefinition, SQSQueue and Ec2Service: ```ts /** * Properties to define an ECS service */ -export interface Ec2QueueWorkerServiceProps { +export interface QueueProcessingEc2ServiceProps { /** * The minimum number of CPU units to reserve for the container. * @@ -146,18 +146,18 @@ export interface Ec2QueueWorkerServiceProps { An example use case: ```ts -// Create the vpc and cluster used by the Queue Worker task +// Create the vpc and cluster used by the queue processing service const vpc = new ec2.VpcNetwork(stack, 'Vpc', { maxAZs: 1 }); const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); -const queue = new sqs.Queue(stack, 'WorkerQueue', { - QueueName: 'EcsWorkerQueue' +const queue = new sqs.Queue(stack, 'ProcessingQueue', { + QueueName: 'EcsEventQueue' }); -// Create the Queue Worker task -new Ec2QueueWorkerService(stack, 'EcsQueueWorkerService', { +// Create the queue processing service +new QueueProcessingEc2Service(stack, 'QueueProcessingEc2Service', { cluster, image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), desiredTaskCount: 2, @@ -168,15 +168,15 @@ new Ec2QueueWorkerService(stack, 'EcsQueueWorkerService', { }); ``` -### Part 3: Create `FargateQueueWorkerServiceProps` interface and `FargateQueueWorkerService` construct +### Part 3: Create `QueueProcessingFargateServiceProps` interface and `QueueProcessingFargateService` construct -The `FargateQueueWorkerServiceProps` interface will contain properties to construct the FargateTaskDefinition, SQSQueue and FargateService: +The `QueueProcessingFargateServiceProps` interface will contain properties to construct the FargateTaskDefinition, SQSQueue and FargateService: ```ts /** - * Properties to define an Fargate service + * Properties to define a Fargate service */ -export interface FargateQueueWorkerServiceProps { +export interface QueueProcessingFargateServiceProps { /** * The number of cpu units used by the task. * Valid values, which determines your range of valid values for the memory parameter: @@ -218,15 +218,15 @@ export interface FargateQueueWorkerServiceProps { An example use case: ```ts -// Create the vpc and cluster used by the Queue Worker task +// Create the vpc and cluster used by the queue processing service const vpc = new ec2.VpcNetwork(stack, 'Vpc', { maxAZs: 2 }); const cluster = new ecs.Cluster(stack, 'FargateCluster', { vpc }); -const queue = new sqs.Queue(stack, 'WorkerQueue', { - QueueName: 'FargateWorkerQueue' +const queue = new sqs.Queue(stack, 'ProcessingQueue', { + QueueName: 'FargateEventQueue' }); -// Create the Queue Worker task -new FargateQueueWorkerService(stack, 'FargateQueueWorkerService', { +// Create the queue processing service +new QueueProcessingFargateService(stack, 'QueueProcessingFargateService', { cluster, image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), desiredTaskCount: 2, diff --git a/packages/@aws-cdk/aws-ecs-patterns/README.md b/packages/@aws-cdk/aws-ecs-patterns/README.md index e36e7a6f22a12..83f9571644027 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/README.md +++ b/packages/@aws-cdk/aws-ecs-patterns/README.md @@ -15,7 +15,7 @@ This library provides higher-level ECS constructs which follow common architectural patterns. It contains: * Load Balanced Services -* Queue Worker Services +* Queue Processing Services * Scheduled Tasks (cron jobs) ## Load Balanced Services @@ -48,14 +48,14 @@ const loadBalancedFargateService = new ecsPatterns.LoadBalancedFargateService(st }); ``` -## Queue Worker Services +## Queue Processing Services To define a service that creates a queue and reads from that queue, instantiate one of the following: -* `Ec2QueueWorkerService` +* `QueueProcessingEc2Service` ```ts -const ecsQueueWorkerService = new Ec2QueueWorkerService(stack, 'Service', { +const queueProcessingEc2Service = new QueueProcessingEc2Service(stack, 'Service', { cluster, memoryLimitMiB: 1024, image: ecs.ContainerImage.fromRegistry('test'), @@ -71,10 +71,10 @@ const ecsQueueWorkerService = new Ec2QueueWorkerService(stack, 'Service', { }); ``` -* `FargateQueueWorkerService` +* `QueueProcessingFargateService` ```ts -const fargateQueueWorkerService = new FargateQueueWorkerService(stack, 'Service', { +const queueProcessingFargateService = new QueueProcessingFargateService(stack, 'Service', { cluster, memoryMiB: '512', image: ecs.ContainerImage.fromRegistry('test'), diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/load-balanced-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/load-balanced-service-base.ts index 9eaf2396b6c53..77299cdeea30f 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/load-balanced-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/load-balanced-service-base.ts @@ -1,6 +1,8 @@ import { ICertificate } from '@aws-cdk/aws-certificatemanager'; import ecs = require('@aws-cdk/aws-ecs'); import elbv2 = require('@aws-cdk/aws-elasticloadbalancingv2'); +import { AddressRecordTarget, ARecord, IHostedZone } from '@aws-cdk/aws-route53'; +import route53targets = require('@aws-cdk/aws-route53-targets'); import cdk = require('@aws-cdk/cdk'); export enum LoadBalancerType { @@ -8,6 +10,9 @@ export enum LoadBalancerType { Network } +/** + * Base properties for load-balanced Fargate and ECS services + */ export interface LoadBalancedServiceBaseProps { /** * The cluster where your service will be deployed @@ -61,10 +66,38 @@ export interface LoadBalancedServiceBaseProps { * @default - No environment variables. */ readonly environment?: { [key: string]: string }; + + /** + * Whether to create an AWS log driver + * + * @default true + */ + readonly enableLogging?: boolean; + + /** + * Determines whether your Fargate Service will be assigned a public IP address. + * + * @default false + */ + readonly publicTasks?: boolean; + + /** + * Domain name for the service, e.g. api.example.com + * + * @default - No domain name. + */ + readonly domainName?: string; + + /** + * Route53 hosted zone for the domain, e.g. "example.com." + * + * @default - No Route53 hosted domain zone. + */ + readonly domainZone?: IHostedZone; } /** - * Base class for load-balanced Fargate and ECS service + * Base class for load-balanced Fargate and ECS services */ export abstract class LoadBalancedServiceBase extends cdk.Construct { public readonly loadBalancerType: LoadBalancerType; @@ -75,9 +108,15 @@ export abstract class LoadBalancedServiceBase extends cdk.Construct { public readonly targetGroup: elbv2.ApplicationTargetGroup | elbv2.NetworkTargetGroup; + public readonly logDriver?: ecs.LogDriver; + constructor(scope: cdk.Construct, id: string, props: LoadBalancedServiceBaseProps) { super(scope, id); + // Create log driver if logging is enabled + const enableLogging = props.enableLogging !== undefined ? props.enableLogging : true; + this.logDriver = enableLogging ? this.createAWSLogDriver(this.node.id) : undefined; + // Load balancer this.loadBalancerType = props.loadBalancerType !== undefined ? props.loadBalancerType : LoadBalancerType.Application; @@ -122,6 +161,18 @@ export abstract class LoadBalancedServiceBase extends cdk.Construct { this.targetGroup = this.listener.addTargets('ECS', targetProps); } + if (typeof props.domainName !== 'undefined') { + if (typeof props.domainZone === 'undefined') { + throw new Error('A Route53 hosted domain zone name is required to configure the specified domain name'); + } + + new ARecord(this, "DNS", { + zone: props.domainZone, + recordName: props.domainName, + target: AddressRecordTarget.fromAlias(new route53targets.LoadBalancerTarget(this.loadBalancer)), + }); + } + new cdk.CfnOutput(this, 'LoadBalancerDNS', { value: this.loadBalancer.loadBalancerDnsName }); } @@ -132,4 +183,8 @@ export abstract class LoadBalancedServiceBase extends cdk.Construct { (this.targetGroup as elbv2.NetworkTargetGroup).addTarget(service); } } + + private createAWSLogDriver(prefix: string): ecs.AwsLogDriver { + return new ecs.AwsLogDriver(this, 'Logging', { streamPrefix: prefix }); + } } diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-worker-service-base.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts similarity index 84% rename from packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-worker-service-base.ts rename to packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts index 569d1bff004af..f35fa64a6cfb0 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-worker-service-base.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/base/queue-processing-service-base.ts @@ -4,9 +4,9 @@ import sqs = require('@aws-cdk/aws-sqs'); import cdk = require('@aws-cdk/cdk'); /** - * Properties to define a queue worker service + * Properties to define a queue processing service */ -export interface QueueWorkerServiceBaseProps { +export interface QueueProcessingServiceBaseProps { /** * Cluster where service will be deployed */ @@ -74,15 +74,15 @@ export interface QueueWorkerServiceBaseProps { } /** - * Base class for a Fargate and ECS queue worker service + * Base class for a Fargate and ECS queue processing service */ -export abstract class QueueWorkerServiceBase extends cdk.Construct { +export abstract class QueueProcessingServiceBase extends cdk.Construct { /** - * The SQS queue that the worker service will process from + * The SQS queue that the service will process from */ public readonly sqsQueue: sqs.IQueue; - // Properties that have defaults defined. The Queue Worker will handle assigning undefined properties with default + // Properties that have defaults defined. The Queue Processing Service will handle assigning undefined properties with default // values so that derived classes do not need to maintain the same logic. /** @@ -106,11 +106,11 @@ export abstract class QueueWorkerServiceBase extends cdk.Construct { */ public readonly logDriver?: ecs.LogDriver; - constructor(scope: cdk.Construct, id: string, props: QueueWorkerServiceBaseProps) { + constructor(scope: cdk.Construct, id: string, props: QueueProcessingServiceBaseProps) { super(scope, id); - // Create the worker SQS queue if one is not provided - this.sqsQueue = props.queue !== undefined ? props.queue : new sqs.Queue(this, 'EcsWorkerServiceQueue', {}); + // Create the SQS queue if one is not provided + this.sqsQueue = props.queue !== undefined ? props.queue : new sqs.Queue(this, 'EcsProcessingQueue', {}); // Setup autoscaling scaling intervals const defaultScalingSteps = [{ upper: 0, change: -1 }, { lower: 100, change: +1 }, { lower: 500, change: +5 }]; @@ -118,7 +118,7 @@ export abstract class QueueWorkerServiceBase extends cdk.Construct { // Create log driver if logging is enabled const enableLogging = props.enableLogging !== undefined ? props.enableLogging : true; - this.logDriver = enableLogging ? this.createAwsLogDriver(this.node.id) : undefined; + this.logDriver = enableLogging ? this.createAWSLogDriver(this.node.id) : undefined; // Add the queue name to environment variables this.environment = { ...(props.environment || {}), QUEUE_NAME: this.sqsQueue.queueName }; @@ -152,7 +152,7 @@ export abstract class QueueWorkerServiceBase extends cdk.Construct { * * @param prefix the Cloudwatch logging prefix */ - private createAwsLogDriver(prefix: string): ecs.AwsLogDriver { - return new ecs.AwsLogDriver(this, 'QueueWorkerLogging', { streamPrefix: prefix }); + private createAWSLogDriver(prefix: string): ecs.AwsLogDriver { + return new ecs.AwsLogDriver(this, 'ProcessingContainerLogging', { streamPrefix: prefix }); } } diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/load-balanced-ecs-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/load-balanced-ecs-service.ts index 6512718f45b07..ce4be1ecce73e 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/load-balanced-ecs-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/load-balanced-ecs-service.ts @@ -52,17 +52,20 @@ export class LoadBalancedEc2Service extends LoadBalancedServiceBase { image: props.image, memoryLimitMiB: props.memoryLimitMiB, memoryReservationMiB: props.memoryReservationMiB, - environment: props.environment + environment: props.environment, + logging: this.logDriver, }); container.addPortMappings({ containerPort: props.containerPort || 80 }); + const assignPublicIp = props.publicTasks !== undefined ? props.publicTasks : false; const service = new ecs.Ec2Service(this, "Service", { cluster: props.cluster, desiredCount: props.desiredCount || 1, - taskDefinition + taskDefinition, + assignPublicIp }); this.service = service; diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/ecs-queue-worker-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts similarity index 76% rename from packages/@aws-cdk/aws-ecs-patterns/lib/ecs/ecs-queue-worker-service.ts rename to packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts index 935fc72031149..3d78627818c3c 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/ecs-queue-worker-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/ecs/queue-processing-ecs-service.ts @@ -1,11 +1,11 @@ import ecs = require('@aws-cdk/aws-ecs'); import cdk = require('@aws-cdk/cdk'); -import { QueueWorkerServiceBase, QueueWorkerServiceBaseProps } from '../base/queue-worker-service-base'; +import { QueueProcessingServiceBase, QueueProcessingServiceBaseProps } from '../base/queue-processing-service-base'; /** - * Properties to define an Ec2 queue worker service + * Properties to define a queue processing Ec2 service */ -export interface Ec2QueueWorkerServiceProps extends QueueWorkerServiceBaseProps { +export interface QueueProcessingEc2ServiceProps extends QueueProcessingServiceBaseProps { /** * The minimum number of CPU units to reserve for the container. * @@ -41,21 +41,21 @@ export interface Ec2QueueWorkerServiceProps extends QueueWorkerServiceBaseProps } /** - * Class to create an Ec2 queue worker service + * Class to create a queue processing Ec2 service */ -export class Ec2QueueWorkerService extends QueueWorkerServiceBase { +export class QueueProcessingEc2Service extends QueueProcessingServiceBase { /** * The ECS service in this construct */ public readonly service: ecs.Ec2Service; - constructor(scope: cdk.Construct, id: string, props: Ec2QueueWorkerServiceProps) { + constructor(scope: cdk.Construct, id: string, props: QueueProcessingEc2ServiceProps) { super(scope, id, props); // Create a Task Definition for the container to start - const taskDefinition = new ecs.Ec2TaskDefinition(this, 'QueueWorkerTaskDef'); - taskDefinition.addContainer('QueueWorkerContainer', { + const taskDefinition = new ecs.Ec2TaskDefinition(this, 'QueueProcessingTaskDef'); + taskDefinition.addContainer('QueueProcessingContainer', { image: props.image, memoryLimitMiB: props.memoryLimitMiB, memoryReservationMiB: props.memoryReservationMiB, @@ -67,7 +67,7 @@ export class Ec2QueueWorkerService extends QueueWorkerServiceBase { // Create an ECS service with the previously defined Task Definition and configure // autoscaling based on cpu utilization and number of messages visible in the SQS queue. - this.service = new ecs.Ec2Service(this, 'QueueWorkerService', { + this.service = new ecs.Ec2Service(this, 'QueueProcessingService', { cluster: props.cluster, desiredCount: this.desiredCount, taskDefinition diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/load-balanced-fargate-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/load-balanced-fargate-service.ts index 6129c57a2f7b9..67692d8c7bdd4 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/load-balanced-fargate-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/load-balanced-fargate-service.ts @@ -1,11 +1,9 @@ import ecs = require('@aws-cdk/aws-ecs'); -import { AddressRecordTarget, ARecord, IHostedZone } from '@aws-cdk/aws-route53'; -import targets = require('@aws-cdk/aws-route53-targets'); import cdk = require('@aws-cdk/cdk'); import { LoadBalancedServiceBase, LoadBalancedServiceBaseProps } from '../base/load-balanced-service-base'; /** - * Properties for a LoadBalancedEcsService + * Properties for a LoadBalancedFargateService */ export interface LoadBalancedFargateServiceProps extends LoadBalancedServiceBaseProps { /** @@ -44,34 +42,6 @@ export interface LoadBalancedFargateServiceProps extends LoadBalancedServiceBase * @default 512 */ readonly memoryMiB?: string; - - /** - * Determines whether your Fargate Service will be assigned a public IP address. - * - * @default false - */ - readonly publicTasks?: boolean; - - /** - * Domain name for the service, e.g. api.example.com - * - * @default - No domain name. - */ - readonly domainName?: string; - - /** - * Route53 hosted zone for the domain, e.g. "example.com." - * - * @default - No Route53 hosted domain zone. - */ - readonly domainZone?: IHostedZone; - - /** - * Whether to create an AWS log driver - * - * @default true - */ - readonly createLogs?: boolean; } /** @@ -92,11 +62,9 @@ export class LoadBalancedFargateService extends LoadBalancedServiceBase { cpu: props.cpu }); - const optIn = props.createLogs !== undefined ? props.createLogs : true; - const container = taskDefinition.addContainer('web', { image: props.image, - logging: optIn ? this.createAWSLogDriver(this.node.id) : undefined, + logging: this.logDriver, environment: props.environment }); @@ -114,21 +82,5 @@ export class LoadBalancedFargateService extends LoadBalancedServiceBase { this.service = service; this.addServiceAsTarget(service); - - if (typeof props.domainName !== 'undefined') { - if (typeof props.domainZone === 'undefined') { - throw new Error('A Route53 hosted domain zone name is required to configure the specified domain name'); - } - - new ARecord(this, "DNS", { - zone: props.domainZone, - recordName: props.domainName, - target: AddressRecordTarget.fromAlias(new targets.LoadBalancerTarget(this.loadBalancer)), - }); - } - } - - private createAWSLogDriver(prefix: string): ecs.AwsLogDriver { - return new ecs.AwsLogDriver(this, 'Logging', { streamPrefix: prefix }); } } diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/fargate-queue-worker-service.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts similarity index 77% rename from packages/@aws-cdk/aws-ecs-patterns/lib/fargate/fargate-queue-worker-service.ts rename to packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts index 748cb2eb9d276..c7355d159b9db 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/fargate-queue-worker-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/fargate/queue-processing-fargate-service.ts @@ -1,11 +1,11 @@ import ecs = require('@aws-cdk/aws-ecs'); import cdk = require('@aws-cdk/cdk'); -import { QueueWorkerServiceBase, QueueWorkerServiceBaseProps } from '../base/queue-worker-service-base'; +import { QueueProcessingServiceBase, QueueProcessingServiceBaseProps } from '../base/queue-processing-service-base'; /** - * Properties to define a Fargate queue worker service + * Properties to define a queue processing Fargate service */ -export interface FargateQueueWorkerServiceProps extends QueueWorkerServiceBaseProps { +export interface QueueProcessingFargateServiceProps extends QueueProcessingServiceBaseProps { /** * The number of cpu units used by the task. * Valid values, which determines your range of valid values for the memory parameter: @@ -45,23 +45,23 @@ export interface FargateQueueWorkerServiceProps extends QueueWorkerServiceBasePr } /** - * Class to create a Fargate queue worker service + * Class to create a queue processing Fargate service */ -export class FargateQueueWorkerService extends QueueWorkerServiceBase { +export class QueueProcessingFargateService extends QueueProcessingServiceBase { /** * The Fargate service in this construct */ public readonly service: ecs.FargateService; - constructor(scope: cdk.Construct, id: string, props: FargateQueueWorkerServiceProps) { + constructor(scope: cdk.Construct, id: string, props: QueueProcessingFargateServiceProps) { super(scope, id, props); // Create a Task Definition for the container to start - const taskDefinition = new ecs.FargateTaskDefinition(this, 'QueueWorkerTaskDef', { + const taskDefinition = new ecs.FargateTaskDefinition(this, 'QueueProcessingTaskDef', { memoryMiB: props.memoryMiB !== undefined ? props.memoryMiB : '512', cpu: props.cpu !== undefined ? props.cpu : '256', }); - taskDefinition.addContainer('QueueWorkerContainer', { + taskDefinition.addContainer('QueueProcessingContainer', { image: props.image, command: props.command, environment: this.environment, @@ -70,7 +70,7 @@ export class FargateQueueWorkerService extends QueueWorkerServiceBase { // Create a Fargate service with the previously defined Task Definition and configure // autoscaling based on cpu utilization and number of messages visible in the SQS queue. - this.service = new ecs.FargateService(this, 'FargateQueueWorkerService', { + this.service = new ecs.FargateService(this, 'QueueProcessingFargateService', { cluster: props.cluster, desiredCount: this.desiredCount, taskDefinition diff --git a/packages/@aws-cdk/aws-ecs-patterns/lib/index.ts b/packages/@aws-cdk/aws-ecs-patterns/lib/index.ts index b8ec155b6ffd9..be4de21a3e53b 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/lib/index.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/lib/index.ts @@ -1,6 +1,6 @@ -export * from './ecs/ecs-queue-worker-service'; -export * from './fargate/fargate-queue-worker-service'; -export * from './base/queue-worker-service-base'; +export * from './ecs/queue-processing-ecs-service'; +export * from './fargate/queue-processing-fargate-service'; +export * from './base/queue-processing-service-base'; export * from './ecs/load-balanced-ecs-service'; export * from './fargate/load-balanced-fargate-service'; diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts index dae71312eb660..4050b72674cab 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.l3s.ts @@ -151,7 +151,7 @@ export = { cluster, image: ecs.ContainerImage.fromRegistry('test'), desiredCount: 2, - createLogs: false, + enableLogging: false, environment: { TEST_ENVIRONMENT_VARIABLE1: "test environment variable 1 value", TEST_ENVIRONMENT_VARIABLE2: "test environment variable 2 value" diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.ecs-worker-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts similarity index 93% rename from packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.ecs-worker-service.ts rename to packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts index fd79eaf55e863..c8337c1866a76 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.ecs-worker-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/test.queue-processing-ecs-service.ts @@ -15,7 +15,7 @@ export = { cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); // WHEN - new ecsPatterns.Ec2QueueWorkerService(stack, 'Service', { + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { cluster, memoryLimitMiB: 512, image: ecs.ContainerImage.fromRegistry('test') @@ -37,7 +37,7 @@ export = { Name: "QUEUE_NAME", Value: { "Fn::GetAtt": [ - "ServiceEcsWorkerServiceQueue19BF278C", + "ServiceEcsProcessingQueueC266885C", "QueueName" ] } @@ -47,7 +47,7 @@ export = { LogDriver: "awslogs", Options: { "awslogs-group": { - Ref: "ServiceQueueWorkerLoggingLogGroup5E11C73B" + Ref: "ServiceProcessingContainerLoggingLogGroupF40B9C5D" }, "awslogs-stream-prefix": "Service", "awslogs-region": { @@ -55,6 +55,7 @@ export = { } } }, + Essential: true, Image: "test", Memory: 512 } @@ -73,7 +74,7 @@ export = { const queue = new sqs.Queue(stack, 'ecs-test-queue', { queueName: 'ecs-test-sqs-queue'}); // WHEN - new ecsPatterns.Ec2QueueWorkerService(stack, 'Service', { + new ecsPatterns.QueueProcessingEc2Service(stack, 'Service', { cluster, memoryLimitMiB: 1024, image: ecs.ContainerImage.fromRegistry('test'), diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.fargate-worker-service.ts b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts similarity index 93% rename from packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.fargate-worker-service.ts rename to packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts index 129afab94114c..84fb41f1d289e 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.fargate-worker-service.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/fargate/test.queue-processing-fargate-service.ts @@ -15,7 +15,7 @@ export = { cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); // WHEN - new ecsPatterns.FargateQueueWorkerService(stack, 'Service', { + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { cluster, memoryMiB: '512', image: ecs.ContainerImage.fromRegistry('test') @@ -37,7 +37,7 @@ export = { Name: "QUEUE_NAME", Value: { "Fn::GetAtt": [ - "ServiceEcsWorkerServiceQueue19BF278C", + "ServiceEcsProcessingQueueC266885C", "QueueName" ] } @@ -47,7 +47,7 @@ export = { LogDriver: "awslogs", Options: { "awslogs-group": { - Ref: "ServiceQueueWorkerLoggingLogGroup5E11C73B" + Ref: "ServiceProcessingContainerLoggingLogGroupF40B9C5D" }, "awslogs-stream-prefix": "Service", "awslogs-region": { @@ -72,7 +72,7 @@ export = { const queue = new sqs.Queue(stack, 'fargate-test-queue', { queueName: 'fargate-test-sqs-queue'}); // WHEN - new ecsPatterns.FargateQueueWorkerService(stack, 'Service', { + new ecsPatterns.QueueProcessingFargateService(stack, 'Service', { cluster, memoryMiB: '512', image: ecs.ContainerImage.fromRegistry('test'), diff --git a/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts b/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts index 207a1fc9baa91..59f4552f174a9 100644 --- a/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts +++ b/packages/@aws-cdk/aws-ecs/lib/ec2/ec2-service.ts @@ -18,6 +18,13 @@ export interface Ec2ServiceProps extends BaseServiceProps { */ readonly taskDefinition: TaskDefinition; + /** + * Assign public IP addresses to each task + * + * @default - Use subnet default. + */ + readonly assignPublicIp?: boolean; + /** * In what subnets to place the task's ENIs * @@ -127,7 +134,7 @@ export class Ec2Service extends BaseService implements IEc2Service, elb.ILoadBal this.daemon = props.daemon || false; if (props.taskDefinition.networkMode === NetworkMode.AwsVpc) { - this.configureAwsVpcNetworking(props.cluster.vpc, false, props.vpcSubnets, props.securityGroup); + this.configureAwsVpcNetworking(props.cluster.vpc, props.assignPublicIp, props.vpcSubnets, props.securityGroup); } else { // Either None, Bridge or Host networking. Copy SecurityGroup from ASG. validateNoNetworkingProps(props); @@ -281,8 +288,8 @@ export class Ec2Service extends BaseService implements IEc2Service, elb.ILoadBal * Validate combinations of networking arguments */ function validateNoNetworkingProps(props: Ec2ServiceProps) { - if (props.vpcSubnets !== undefined || props.securityGroup !== undefined) { - throw new Error('vpcSubnets and securityGroup can only be used in AwsVpc networking mode'); + if (props.vpcSubnets !== undefined || props.securityGroup !== undefined || props.assignPublicIp) { + throw new Error('vpcSubnets, securityGroup and assignPublicIp can only be used in AwsVpc networking mode'); } } diff --git a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts index df0d7ed05a21f..57566c5cc95c1 100644 --- a/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts +++ b/packages/@aws-cdk/aws-ecs/test/ec2/test.ec2-service.ts @@ -229,6 +229,34 @@ export = { // THEN test.done(); }, + + "it errors if assignPublicIp is true"(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'MyVpc', {}); + const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc }); + cluster.addCapacity('DefaultAutoScalingGroup', { instanceType: new ec2.InstanceType('t2.micro') }); + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'Ec2TaskDef', { + networkMode: NetworkMode.Bridge + }); + + taskDefinition.addContainer("web", { + image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), + memoryLimitMiB: 512 + }); + + // THEN + test.throws(() => { + new ecs.Ec2Service(stack, "Ec2Service", { + cluster, + taskDefinition, + assignPublicIp: true + }); + }); + + // THEN + test.done(); + }, }, "with a TaskDefinition with AwsVpc network mode": {