Skip to content

Commit fa8f2e2

Browse files
authored
feat(aws-ecs): support runtime platform property for create fargate windows runtime. (#17622)
feat(aws-ecs): support runtime platform property for create fargate windows and Graviton2 runtime. close #17242 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 9fe48b3 commit fa8f2e2

File tree

8 files changed

+1097
-1
lines changed

8 files changed

+1097
-1
lines changed

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

+44
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,50 @@ taskDefinition.addContainer('container', {
447447
});
448448
```
449449

450+
### Using Windows containers on Fargate
451+
452+
AWS Fargate supports Amazon ECS Windows containers. For more details, please see this [blog post](https://aws.amazon.com/tw/blogs/containers/running-windows-containers-with-amazon-ecs-on-aws-fargate/)
453+
454+
```ts
455+
// Create a Task Definition for the Windows container to start
456+
const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef', {
457+
runtimePlatform: {
458+
operatingSystemFamily: ecs.OperatingSystemFamily.WINDOWS_SERVER_2019_CORE,
459+
cpuArchitecture: ecs.CpuArchitecture.X86_64,
460+
},
461+
cpu: 1024,
462+
memoryLimitMiB: 2048,
463+
});
464+
465+
taskDefinition.addContainer('windowsservercore', {
466+
logging: ecs.LogDriver.awsLogs({ streamPrefix: 'win-iis-on-fargate' }),
467+
portMappings: [{ containerPort: 80 }],
468+
image: ecs.ContainerImage.fromRegistry('mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019'),
469+
});
470+
```
471+
472+
### Using Graviton2 with Fargate
473+
474+
AWS Graviton2 supports AWS Fargate. For more details, please see this [blog post](https://aws.amazon.com/blogs/aws/announcing-aws-graviton2-support-for-aws-fargate-get-up-to-40-better-price-performance-for-your-serverless-containers/)
475+
476+
```ts
477+
// Create a Task Definition for running container on Graviton Runtime.
478+
const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef', {
479+
runtimePlatform: {
480+
operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
481+
cpuArchitecture: ecs.CpuArchitecture.ARM64,
482+
},
483+
cpu: 1024,
484+
memoryLimitMiB: 2048,
485+
});
486+
487+
taskDefinition.addContainer('webarm64', {
488+
logging: ecs.LogDriver.awsLogs({ streamPrefix: 'graviton2-on-fargate' }),
489+
portMappings: [{ containerPort: 80 }],
490+
image: ecs.ContainerImage.fromRegistry('public.ecr.aws/nginx/nginx:latest-arm64v8'),
491+
});
492+
```
493+
450494
## Service
451495

452496
A `Service` instantiates a `TaskDefinition` on a `Cluster` a given number of

packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts

+47
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { FirelensLogRouter, FirelensLogRouterDefinitionOptions, FirelensLogRoute
88
import { AwsLogDriver } from '../log-drivers/aws-log-driver';
99
import { PlacementConstraint } from '../placement';
1010
import { ProxyConfiguration } from '../proxy-configuration/proxy-configuration';
11+
import { RuntimePlatform } from '../runtime-platform';
1112
import { ImportedTaskDefinition } from './_imported-task-definition';
1213

1314
/**
@@ -208,6 +209,15 @@ export interface TaskDefinitionProps extends CommonTaskDefinitionProps {
208209
* @default - Undefined, in which case, the task will receive 20GiB ephemeral storage.
209210
*/
210211
readonly ephemeralStorageGiB?: number;
212+
213+
/**
214+
* The operating system that your task definitions are running on.
215+
* A runtimePlatform is supported only for tasks using the Fargate launch type.
216+
*
217+
*
218+
* @default - Undefined.
219+
*/
220+
readonly runtimePlatform?: RuntimePlatform;
211221
}
212222

213223
/**
@@ -369,6 +379,8 @@ export class TaskDefinition extends TaskDefinitionBase {
369379

370380
private _referencesSecretJsonField?: boolean;
371381

382+
private runtimePlatform?: RuntimePlatform;
383+
372384
/**
373385
* Constructs a new instance of the TaskDefinition class.
374386
*/
@@ -405,6 +417,10 @@ export class TaskDefinition extends TaskDefinitionBase {
405417
throw new Error(`External tasks can only have Bridge network mode, got: ${this.networkMode}`);
406418
}
407419

420+
if (!this.isFargateCompatible && props.runtimePlatform) {
421+
throw new Error('Cannot specify runtimePlatform in non-Fargate compatible tasks');
422+
}
423+
408424
this._executionRole = props.executionRole;
409425

410426
this.taskRole = props.taskRole || new iam.Role(this, 'TaskRole', {
@@ -417,6 +433,15 @@ export class TaskDefinition extends TaskDefinitionBase {
417433

418434
this.ephemeralStorageGiB = props.ephemeralStorageGiB;
419435

436+
// validate the cpu and memory size for the Windows operation system family.
437+
if (props.runtimePlatform?.operatingSystemFamily?._operatingSystemFamily.includes('WINDOWS')) {
438+
// We know that props.cpu and props.memoryMiB are defined because an error would have been thrown previously if they were not.
439+
// But, typescript is not able to figure this out, so using the `!` operator here to let the type-checker know they are defined.
440+
this.checkFargateWindowsBasedTasksSize(props.cpu!, props.memoryMiB!, props.runtimePlatform!);
441+
}
442+
443+
this.runtimePlatform = props.runtimePlatform;
444+
420445
const taskDef = new CfnTaskDefinition(this, 'Resource', {
421446
containerDefinitions: Lazy.any({ produce: () => this.renderContainers() }, { omitEmptyArray: true }),
422447
volumes: Lazy.any({ produce: () => this.renderVolumes() }, { omitEmptyArray: true }),
@@ -445,6 +470,10 @@ export class TaskDefinition extends TaskDefinitionBase {
445470
ephemeralStorage: this.ephemeralStorageGiB ? {
446471
sizeInGiB: this.ephemeralStorageGiB,
447472
} : undefined,
473+
runtimePlatform: this.isFargateCompatible && this.runtimePlatform ? {
474+
cpuArchitecture: this.runtimePlatform?.cpuArchitecture?._cpuArchitecture,
475+
operatingSystemFamily: this.runtimePlatform?.operatingSystemFamily?._operatingSystemFamily,
476+
} : undefined,
448477
});
449478

450479
if (props.placementConstraints) {
@@ -697,6 +726,24 @@ export class TaskDefinition extends TaskDefinitionBase {
697726

698727
return this.containers.map(x => x.renderContainerDefinition());
699728
}
729+
730+
private checkFargateWindowsBasedTasksSize(cpu: string, memory: string, runtimePlatform: RuntimePlatform) {
731+
if (Number(cpu) === 1024) {
732+
if (Number(memory) < 1024 || Number(memory) > 8192 || (Number(memory)% 1024 !== 0)) {
733+
throw new Error(`If provided cpu is ${cpu}, then memoryMiB must have a min of 1024 and a max of 8192, in 1024 increments. Provided memoryMiB was ${Number(memory)}.`);
734+
}
735+
} else if (Number(cpu) === 2048) {
736+
if (Number(memory) < 4096 || Number(memory) > 16384 || (Number(memory) % 1024 !== 0)) {
737+
throw new Error(`If provided cpu is ${cpu}, then memoryMiB must have a min of 4096 and max of 16384, in 1024 increments. Provided memoryMiB ${Number(memory)}.`);
738+
}
739+
} else if (Number(cpu) === 4096) {
740+
if (Number(memory) < 8192 || Number(memory) > 30720 || (Number(memory) % 1024 !== 0)) {
741+
throw new Error(`If provided cpu is ${ cpu }, then memoryMiB must have a min of 8192 and a max of 30720, in 1024 increments.Provided memoryMiB was ${ Number(memory) }.`);
742+
}
743+
} else {
744+
throw new Error(`If operatingSystemFamily is ${runtimePlatform.operatingSystemFamily!._operatingSystemFamily}, then cpu must be in 1024 (1 vCPU), 2048 (2 vCPU), or 4096 (4 vCPU). Provided value was: ${cpu}`);
745+
}
746+
};
700747
}
701748

702749
/**

packages/@aws-cdk/aws-ecs/lib/fargate/fargate-task-definition.ts

+10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
NetworkMode,
1010
TaskDefinition,
1111
} from '../base/task-definition';
12+
import { RuntimePlatform } from '../runtime-platform';
1213

1314
/**
1415
* The properties for a task definition.
@@ -59,6 +60,15 @@ export interface FargateTaskDefinitionProps extends CommonTaskDefinitionProps {
5960
* @default 20
6061
*/
6162
readonly ephemeralStorageGiB?: number;
63+
64+
/**
65+
* The operating system that your task definitions are running on.
66+
*
67+
* A runtimePlatform is supported only for tasks using the Fargate launch type.
68+
*
69+
* @default - Undefined.
70+
*/
71+
readonly runtimePlatform?: RuntimePlatform;
6272
}
6373

6474
/**

packages/@aws-cdk/aws-ecs/lib/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export * from './log-drivers/log-drivers';
4242
export * from './proxy-configuration/app-mesh-proxy-configuration';
4343
export * from './proxy-configuration/proxy-configuration';
4444
export * from './proxy-configuration/proxy-configurations';
45+
export * from './runtime-platform';
4546

4647
// AWS::ECS CloudFormation Resources:
4748
//
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/**
2+
* The CpuArchitecture for Fargate Runtime Platform.
3+
*/
4+
export class CpuArchitecture {
5+
/**
6+
* ARM64
7+
*/
8+
public static readonly ARM64 = CpuArchitecture.of('ARM64');
9+
10+
/**
11+
* X86_64
12+
*/
13+
public static readonly X86_64 = CpuArchitecture.of('X86_64');
14+
15+
/**
16+
* Other cpu architecture.
17+
*
18+
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-runtimeplatform.html#cfn-ecs-taskdefinition-runtimeplatform-cpuarchitecture for all available cpu architecture.
19+
*
20+
* @param cpuArchitecture cpu architecture.
21+
*
22+
*/
23+
public static of(cpuArchitecture: string) { return new CpuArchitecture(cpuArchitecture); }
24+
25+
/**
26+
*
27+
* @param _cpuArchitecture The CPU architecture.
28+
*/
29+
private constructor(public readonly _cpuArchitecture: string) { }
30+
}
31+
32+
/**
33+
* The operating system for Fargate Runtime Platform.
34+
*/
35+
export class OperatingSystemFamily {
36+
/**
37+
* LINUX
38+
*/
39+
public static readonly LINUX = OperatingSystemFamily.of('LINUX');
40+
41+
/**
42+
* WINDOWS_SERVER_2004_CORE
43+
*/
44+
public static readonly WINDOWS_SERVER_2004_CORE = OperatingSystemFamily.of('WINDOWS_SERVER_2004_CORE');
45+
46+
/**
47+
* WINDOWS_SERVER_2016_FULL
48+
*/
49+
public static readonly WINDOWS_SERVER_2016_FULL = OperatingSystemFamily.of('WINDOWS_SERVER_2016_FULL');
50+
51+
/**
52+
* WINDOWS_SERVER_2019_CORE
53+
*/
54+
public static readonly WINDOWS_SERVER_2019_CORE = OperatingSystemFamily.of('WINDOWS_SERVER_2019_CORE');
55+
56+
/**
57+
* WINDOWS_SERVER_2019_FULL
58+
*/
59+
public static readonly WINDOWS_SERVER_2019_FULL = OperatingSystemFamily.of('WINDOWS_SERVER_2019_FULL');
60+
61+
/**
62+
* WINDOWS_SERVER_2022_CORE
63+
*/
64+
public static readonly WINDOWS_SERVER_2022_CORE = OperatingSystemFamily.of('WINDOWS_SERVER_2022_CORE');
65+
66+
/**
67+
* WINDOWS_SERVER_2022_FULL
68+
*/
69+
public static readonly WINDOWS_SERVER_2022_FULL = OperatingSystemFamily.of('WINDOWS_SERVER_2022_FULL');
70+
71+
/**
72+
* WINDOWS_SERVER_20H2_CORE
73+
*/
74+
public static readonly WINDOWS_SERVER_20H2_CORE = OperatingSystemFamily.of('WINDOWS_SERVER_20H2_CORE');
75+
76+
/**
77+
* Other operating system family.
78+
*
79+
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-runtimeplatform.html#cfn-ecs-taskdefinition-runtimeplatform-operatingsystemfamily for all available operating system family.
80+
*
81+
* @param family operating system family.
82+
*
83+
*/
84+
public static of(family: string) { return new OperatingSystemFamily(family); }
85+
86+
/**
87+
*
88+
* @param _operatingSystemFamily The operating system family.
89+
*/
90+
private constructor(public readonly _operatingSystemFamily: string) { }
91+
}
92+
93+
94+
/**
95+
* The interface for Runtime Platform.
96+
*/
97+
export interface RuntimePlatform {
98+
/**
99+
* The CpuArchitecture for Fargate Runtime Platform.
100+
*
101+
* @default - Undefined.
102+
*/
103+
readonly cpuArchitecture?: CpuArchitecture,
104+
105+
/**
106+
* The operating system for Fargate Runtime Platform.
107+
*
108+
* @default - Undefined.
109+
*/
110+
readonly operatingSystemFamily?: OperatingSystemFamily,
111+
}

0 commit comments

Comments
 (0)