Skip to content

Commit ed75b16

Browse files
authored
feat(ecs): support pidMode for FargateTaskDefinition (#29670)
### Issue # (if applicable) Closes #29619. ### Reason for this change Support [`pidMode`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-taskdefinition.html#cfn-ecs-taskdefinition-pidmode) for `FargateTaskDefinition`. ### Description of changes Added support for the `pidMode` property along with the necessary validation, documentation, and test coverage. ### Description of how you validated changes - [x] Unit tests - [x] Integration tests ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 27b7a45 commit ed75b16

File tree

9 files changed

+197
-15
lines changed

9 files changed

+197
-15
lines changed

packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.runtime.js.snapshot/aws-ecs-integ-runtime.template.json

+1
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,7 @@
570570
"Family": "awsecsintegruntimeTaskDefGraviton28E28B263",
571571
"Memory": "1024",
572572
"NetworkMode": "awsvpc",
573+
"PidMode": "host",
573574
"RequiresCompatibilities": [
574575
"FARGATE"
575576
],

packages/@aws-cdk-testing/framework-integ/test/aws-ecs/test/fargate/integ.runtime.ts

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const taskDefinitiongraviton2 = new ecs.FargateTaskDefinition(stack, 'TaskDefGra
2727
},
2828
cpu: 256,
2929
memoryLimitMiB: 1024,
30+
pidMode: ecs.PidMode.HOST,
3031
});
3132

3233
taskDefinitionwindows.addContainer('windowsservercore', {

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

+17
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,23 @@ const fargateTaskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef', {
362362
});
363363
```
364364

365+
To specify the process namespace to use for the containers in the task, use the `pidMode` property:
366+
367+
```ts
368+
const fargateTaskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDef', {
369+
runtimePlatform: {
370+
operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
371+
cpuArchitecture: ecs.CpuArchitecture.ARM64,
372+
},
373+
memoryLimitMiB: 512,
374+
cpu: 256,
375+
pidMode: ecs.PidMode.HOST,
376+
});
377+
```
378+
379+
**Note:** `pidMode` is only supported for tasks that are hosted on AWS Fargate if the tasks are using platform version 1.4.0
380+
or later (Linux). This isn't supported for Windows containers on Fargate.
381+
365382
To add containers to a task definition, call `addContainer()`:
366383

367384
```ts

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

+16-4
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,9 @@ export interface TaskDefinitionProps extends CommonTaskDefinitionProps {
193193
/**
194194
* The process namespace to use for the containers in the task.
195195
*
196-
* Not supported in Fargate and Windows containers.
196+
* Only supported for tasks that are hosted on AWS Fargate if the tasks
197+
* are using platform version 1.4.0 or later (Linux).
198+
* Not supported in Windows containers.
197199
*
198200
* @default - PidMode used by the task is not specified
199201
*/
@@ -219,8 +221,8 @@ export interface TaskDefinitionProps extends CommonTaskDefinitionProps {
219221

220222
/**
221223
* The operating system that your task definitions are running on.
222-
* A runtimePlatform is supported only for tasks using the Fargate launch type.
223224
*
225+
* A runtimePlatform is supported only for tasks using the Fargate launch type.
224226
*
225227
* @default - Undefined.
226228
*/
@@ -372,6 +374,15 @@ export class TaskDefinition extends TaskDefinitionBase {
372374
*/
373375
public readonly ephemeralStorageGiB?: number;
374376

377+
/**
378+
* The process namespace to use for the containers in the task.
379+
*
380+
* Only supported for tasks that are hosted on AWS Fargate if the tasks
381+
* are using platform version 1.4.0 or later (Linux).
382+
* Not supported in Windows containers.
383+
*/
384+
public readonly pidMode?: PidMode;
385+
375386
/**
376387
* The container definitions.
377388
*/
@@ -453,9 +464,10 @@ export class TaskDefinition extends TaskDefinitionBase {
453464
}
454465

455466
this.ephemeralStorageGiB = props.ephemeralStorageGiB;
467+
this.pidMode = props.pidMode;
456468

457469
// validate the cpu and memory size for the Windows operation system family.
458-
if (props.runtimePlatform?.operatingSystemFamily?._operatingSystemFamily.includes('WINDOWS')) {
470+
if (props.runtimePlatform?.operatingSystemFamily?.isWindows()) {
459471
// We know that props.cpu and props.memoryMiB are defined because an error would have been thrown previously if they were not.
460472
// But, typescript is not able to figure this out, so using the `!` operator here to let the type-checker know they are defined.
461473
this.checkFargateWindowsBasedTasksSize(props.cpu!, props.memoryMiB!, props.runtimePlatform!);
@@ -485,7 +497,7 @@ export class TaskDefinition extends TaskDefinitionBase {
485497
cpu: props.cpu,
486498
memory: props.memoryMiB,
487499
ipcMode: props.ipcMode,
488-
pidMode: props.pidMode,
500+
pidMode: this.pidMode,
489501
inferenceAccelerators: Lazy.any({
490502
produce: () =>
491503
!isFargateCompatible(this.compatibility) ? this.renderInferenceAccelerators() : undefined,

packages/aws-cdk-lib/aws-ecs/lib/ec2/ec2-task-definition.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export interface Ec2TaskDefinitionProps extends CommonTaskDefinitionProps {
4949
/**
5050
* The process namespace to use for the containers in the task.
5151
*
52-
* Not supported in Fargate and Windows containers.
52+
* Not supported in Windows containers.
5353
*
5454
* @default - PidMode used by the task is not specified
5555
*/

packages/aws-cdk-lib/aws-ecs/lib/fargate/fargate-service.ts

+18-10
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,23 @@ export class FargateService extends BaseService implements IFargateService {
128128
throw new Error('Only one of SecurityGroup or SecurityGroups can be populated.');
129129
}
130130

131+
// Platform versions not supporting referencesSecretJsonField, ephemeralStorageGiB, or pidMode on a task definition
132+
const unsupportedPlatformVersions = [
133+
FargatePlatformVersion.VERSION1_0,
134+
FargatePlatformVersion.VERSION1_1,
135+
FargatePlatformVersion.VERSION1_2,
136+
FargatePlatformVersion.VERSION1_3,
137+
];
138+
const isUnsupportedPlatformVersion = props.platformVersion && unsupportedPlatformVersions.includes(props.platformVersion);
139+
140+
if (props.taskDefinition.ephemeralStorageGiB && isUnsupportedPlatformVersion) {
141+
throw new Error(`The ephemeralStorageGiB feature requires platform version ${FargatePlatformVersion.VERSION1_4} or later, got ${props.platformVersion}.`);
142+
}
143+
144+
if (props.taskDefinition.pidMode && isUnsupportedPlatformVersion) {
145+
throw new Error(`The pidMode feature requires platform version ${FargatePlatformVersion.VERSION1_4} or later, got ${props.platformVersion}.`);
146+
}
147+
131148
super(scope, id, {
132149
...props,
133150
desiredCount: props.desiredCount,
@@ -153,9 +170,7 @@ export class FargateService extends BaseService implements IFargateService {
153170
}
154171

155172
this.node.addValidation({
156-
validate: () => this.taskDefinition.referencesSecretJsonField
157-
&& props.platformVersion
158-
&& SECRET_JSON_FIELD_UNSUPPORTED_PLATFORM_VERSIONS.includes(props.platformVersion)
173+
validate: () => this.taskDefinition.referencesSecretJsonField && isUnsupportedPlatformVersion
159174
? [`The task definition of this service uses at least one container that references a secret JSON field. This feature requires platform version ${FargatePlatformVersion.VERSION1_4} or later.`]
160175
: [],
161176
});
@@ -214,10 +229,3 @@ export enum FargatePlatformVersion {
214229
*/
215230
VERSION1_0 = '1.0.0',
216231
}
217-
218-
const SECRET_JSON_FIELD_UNSUPPORTED_PLATFORM_VERSIONS = [
219-
FargatePlatformVersion.VERSION1_0,
220-
FargatePlatformVersion.VERSION1_1,
221-
FargatePlatformVersion.VERSION1_2,
222-
FargatePlatformVersion.VERSION1_3,
223-
];

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

+22
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
Compatibility,
88
ITaskDefinition,
99
NetworkMode,
10+
PidMode,
1011
TaskDefinition,
1112
} from '../base/task-definition';
1213
import { RuntimePlatform } from '../runtime-platform';
@@ -77,6 +78,17 @@ export interface FargateTaskDefinitionProps extends CommonTaskDefinitionProps {
7778
* @default - Undefined.
7879
*/
7980
readonly runtimePlatform?: RuntimePlatform;
81+
82+
/**
83+
* The process namespace to use for the containers in the task.
84+
*
85+
* Only supported for tasks that are hosted on AWS Fargate if the tasks
86+
* are using platform version 1.4.0 or later (Linux).
87+
* Not supported in Windows containers.
88+
*
89+
* @default - PidMode used by the task is not specified
90+
*/
91+
readonly pidMode?: PidMode;
8092
}
8193

8294
/**
@@ -147,13 +159,23 @@ export class FargateTaskDefinition extends TaskDefinition implements IFargateTas
147159
memoryMiB: props.memoryLimitMiB !== undefined ? Tokenization.stringifyNumber(props.memoryLimitMiB) : '512',
148160
compatibility: Compatibility.FARGATE,
149161
networkMode: NetworkMode.AWS_VPC,
162+
pidMode: props.pidMode,
150163
});
151164

152165
// eslint-disable-next-line max-len
153166
if (props.ephemeralStorageGiB && !Token.isUnresolved(props.ephemeralStorageGiB) && (props.ephemeralStorageGiB < 21 || props.ephemeralStorageGiB > 200)) {
154167
throw new Error('Ephemeral storage size must be between 21GiB and 200GiB');
155168
}
156169

170+
if (props.pidMode) {
171+
if (props.runtimePlatform?.operatingSystemFamily?.isWindows()) {
172+
throw new Error('\'pidMode\' is not supported for Windows containers.');
173+
}
174+
if (!Token.isUnresolved(props.pidMode) && props.pidMode !== PidMode.HOST) {
175+
throw new Error(`\'pidMode\' can only be set to \'${PidMode.HOST}\' for Fargate containers, got: \'${props.pidMode}\'.`);
176+
}
177+
}
178+
157179
this.ephemeralStorageGiB = props.ephemeralStorageGiB;
158180
}
159181
}

packages/aws-cdk-lib/aws-ecs/test/fargate/fargate-service.test.ts

+87
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { testDeprecated } from '@aws-cdk/cdk-build-tools';
22
import { Annotations, Match, Template } from '../../../assertions';
33
import * as appscaling from '../../../aws-applicationautoscaling';
4+
import * as batch from '../../../aws-batch';
45
import * as cloudwatch from '../../../aws-cloudwatch';
56
import * as ec2 from '../../../aws-ec2';
67
import * as elbv2 from '../../../aws-elasticloadbalancingv2';
@@ -685,6 +686,92 @@ describe('fargate service', () => {
685686
}).toThrow(/one essential container/);
686687
});
687688

689+
test('errors when platform version does not support containers which references secret JSON field', () => {
690+
// GIVEN
691+
const stack = new cdk.Stack();
692+
const vpc = new ec2.Vpc(stack, 'MyVpc', {});
693+
const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc });
694+
const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef', {
695+
runtimePlatform: {
696+
operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
697+
cpuArchitecture: ecs.CpuArchitecture.ARM64,
698+
},
699+
memoryLimitMiB: 512,
700+
cpu: 256,
701+
});
702+
703+
// Errors on validation, not on construction.
704+
new ecs.FargateService(stack, 'FargateService', {
705+
cluster,
706+
taskDefinition,
707+
platformVersion: ecs.FargatePlatformVersion.VERSION1_2,
708+
});
709+
710+
taskDefinition.addContainer('main', {
711+
image: ecs.ContainerImage.fromRegistry('somecontainer'),
712+
secrets: {
713+
envName: batch.Secret.fromSecretsManager(new secretsmanager.Secret(stack, 'testSecret'), 'secretField'),
714+
},
715+
});
716+
717+
// THEN
718+
expect(() => {
719+
Template.fromStack(stack);
720+
}).toThrow(/This feature requires platform version/);
721+
});
722+
723+
test('errors when platform version does not support ephemeralStorageGiB', () => {
724+
// GIVEN
725+
const stack = new cdk.Stack();
726+
const vpc = new ec2.Vpc(stack, 'MyVpc', {});
727+
const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc });
728+
const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef', {
729+
runtimePlatform: {
730+
operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
731+
cpuArchitecture: ecs.CpuArchitecture.ARM64,
732+
},
733+
memoryLimitMiB: 512,
734+
cpu: 256,
735+
ephemeralStorageGiB: 100,
736+
});
737+
738+
// WHEN
739+
// THEN
740+
expect(() => {
741+
new ecs.FargateService(stack, 'FargateService', {
742+
cluster,
743+
taskDefinition,
744+
platformVersion: ecs.FargatePlatformVersion.VERSION1_2,
745+
});
746+
}).toThrow(/The ephemeralStorageGiB feature requires platform version/);
747+
});
748+
749+
test('errors when platform version does not support pidMode', () => {
750+
// GIVEN
751+
const stack = new cdk.Stack();
752+
const vpc = new ec2.Vpc(stack, 'MyVpc', {});
753+
const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc });
754+
const taskDefinition = new ecs.FargateTaskDefinition(stack, 'FargateTaskDef', {
755+
runtimePlatform: {
756+
operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
757+
cpuArchitecture: ecs.CpuArchitecture.ARM64,
758+
},
759+
memoryLimitMiB: 512,
760+
cpu: 256,
761+
pidMode: ecs.PidMode.HOST,
762+
});
763+
764+
// WHEN
765+
// THEN
766+
expect(() => {
767+
new ecs.FargateService(stack, 'FargateService', {
768+
cluster,
769+
taskDefinition,
770+
platformVersion: ecs.FargatePlatformVersion.VERSION1_2,
771+
});
772+
}).toThrow(/The pidMode feature requires platform version/);
773+
});
774+
688775
test('allows adding the default container after creating the service', () => {
689776
// GIVEN
690777
const stack = new cdk.Stack();

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

+34
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ describe('fargate task definition', () => {
6060
cpuArchitecture: ecs.CpuArchitecture.X86_64,
6161
operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
6262
},
63+
pidMode: ecs.PidMode.HOST,
6364
});
6465

6566
taskDefinition.addVolume({
@@ -84,6 +85,7 @@ describe('fargate task definition', () => {
8485
Family: 'myApp',
8586
Memory: '1024',
8687
NetworkMode: 'awsvpc',
88+
PidMode: 'host',
8789
RequiresCompatibilities: [
8890
ecs.LaunchType.FARGATE,
8991
],
@@ -161,6 +163,38 @@ describe('fargate task definition', () => {
161163

162164
// THEN
163165
});
166+
167+
test('throws when pidMode is specified on Windows', () => {
168+
// GIVEN
169+
const stack = new cdk.Stack();
170+
171+
// WHEN
172+
// THEN
173+
expect(() => {
174+
new ecs.FargateTaskDefinition(stack, 'FargateTaskDef', {
175+
pidMode: ecs.PidMode.HOST,
176+
runtimePlatform: {
177+
operatingSystemFamily: ecs.OperatingSystemFamily.WINDOWS_SERVER_2019_CORE,
178+
cpuArchitecture: ecs.CpuArchitecture.X86_64,
179+
},
180+
cpu: 1024,
181+
memoryLimitMiB: 2048,
182+
});
183+
}).toThrow(/'pidMode' is not supported for Windows containers./);
184+
});
185+
186+
test('throws when pidMode is not host', () => {
187+
// GIVEN
188+
const stack = new cdk.Stack();
189+
190+
// WHEN
191+
// THEN
192+
expect(() => {
193+
new ecs.FargateTaskDefinition(stack, 'FargateTaskDef', {
194+
pidMode: ecs.PidMode.TASK,
195+
});
196+
}).toThrow(/'pidMode' can only be set to 'host' for Fargate containers, got: 'task'./);
197+
});
164198
});
165199
describe('When configuredAtLaunch in the Volume', ()=> {
166200
test('do not throw when configuredAtLaunch is false', () => {

0 commit comments

Comments
 (0)