The aws:ecs/taskDefinition:TaskDefinition resource, part of the Pulumi AWS provider, defines an ECS task definition revision: container specifications, resource requirements, volumes, and runtime platform. This guide focuses on four capabilities: container definitions with port mappings, Fargate and Windows runtime configuration, EFS volume mounting, and App Mesh proxy integration.
Task definitions reference IAM roles, EFS file systems, and App Mesh configuration that must exist separately. They’re used by ECS services to launch tasks. The examples are intentionally small. Combine them with your own IAM roles, networking, and service definitions.
Define containers with port mappings and volumes
Most ECS deployments start by defining containers that run your application code, specifying resource requirements and network ports.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const service = new aws.ecs.TaskDefinition("service", {
family: "service",
containerDefinitions: JSON.stringify([
{
name: "first",
image: "service-first",
cpu: 10,
memory: 512,
essential: true,
portMappings: [{
containerPort: 80,
hostPort: 80,
}],
},
{
name: "second",
image: "service-second",
cpu: 10,
memory: 256,
essential: true,
portMappings: [{
containerPort: 443,
hostPort: 443,
}],
},
]),
volumes: [{
name: "service-storage",
hostPath: "/ecs/service-storage",
}],
placementConstraints: [{
type: "memberOf",
expression: "attribute:ecs.availability-zone in [us-west-2a, us-west-2b]",
}],
});
import pulumi
import json
import pulumi_aws as aws
service = aws.ecs.TaskDefinition("service",
family="service",
container_definitions=json.dumps([
{
"name": "first",
"image": "service-first",
"cpu": 10,
"memory": 512,
"essential": True,
"portMappings": [{
"containerPort": 80,
"hostPort": 80,
}],
},
{
"name": "second",
"image": "service-second",
"cpu": 10,
"memory": 256,
"essential": True,
"portMappings": [{
"containerPort": 443,
"hostPort": 443,
}],
},
]),
volumes=[{
"name": "service-storage",
"host_path": "/ecs/service-storage",
}],
placement_constraints=[{
"type": "memberOf",
"expression": "attribute:ecs.availability-zone in [us-west-2a, us-west-2b]",
}])
package main
import (
"encoding/json"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ecs"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
tmpJSON0, err := json.Marshal([]interface{}{
map[string]interface{}{
"name": "first",
"image": "service-first",
"cpu": 10,
"memory": 512,
"essential": true,
"portMappings": []map[string]interface{}{
map[string]interface{}{
"containerPort": 80,
"hostPort": 80,
},
},
},
map[string]interface{}{
"name": "second",
"image": "service-second",
"cpu": 10,
"memory": 256,
"essential": true,
"portMappings": []map[string]interface{}{
map[string]interface{}{
"containerPort": 443,
"hostPort": 443,
},
},
},
})
if err != nil {
return err
}
json0 := string(tmpJSON0)
_, err = ecs.NewTaskDefinition(ctx, "service", &ecs.TaskDefinitionArgs{
Family: pulumi.String("service"),
ContainerDefinitions: pulumi.String(json0),
Volumes: ecs.TaskDefinitionVolumeArray{
&ecs.TaskDefinitionVolumeArgs{
Name: pulumi.String("service-storage"),
HostPath: pulumi.String("/ecs/service-storage"),
},
},
PlacementConstraints: ecs.TaskDefinitionPlacementConstraintArray{
&ecs.TaskDefinitionPlacementConstraintArgs{
Type: pulumi.String("memberOf"),
Expression: pulumi.String("attribute:ecs.availability-zone in [us-west-2a, us-west-2b]"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var service = new Aws.Ecs.TaskDefinition("service", new()
{
Family = "service",
ContainerDefinitions = JsonSerializer.Serialize(new[]
{
new Dictionary<string, object?>
{
["name"] = "first",
["image"] = "service-first",
["cpu"] = 10,
["memory"] = 512,
["essential"] = true,
["portMappings"] = new[]
{
new Dictionary<string, object?>
{
["containerPort"] = 80,
["hostPort"] = 80,
},
},
},
new Dictionary<string, object?>
{
["name"] = "second",
["image"] = "service-second",
["cpu"] = 10,
["memory"] = 256,
["essential"] = true,
["portMappings"] = new[]
{
new Dictionary<string, object?>
{
["containerPort"] = 443,
["hostPort"] = 443,
},
},
},
}),
Volumes = new[]
{
new Aws.Ecs.Inputs.TaskDefinitionVolumeArgs
{
Name = "service-storage",
HostPath = "/ecs/service-storage",
},
},
PlacementConstraints = new[]
{
new Aws.Ecs.Inputs.TaskDefinitionPlacementConstraintArgs
{
Type = "memberOf",
Expression = "attribute:ecs.availability-zone in [us-west-2a, us-west-2b]",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ecs.TaskDefinition;
import com.pulumi.aws.ecs.TaskDefinitionArgs;
import com.pulumi.aws.ecs.inputs.TaskDefinitionVolumeArgs;
import com.pulumi.aws.ecs.inputs.TaskDefinitionPlacementConstraintArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var service = new TaskDefinition("service", TaskDefinitionArgs.builder()
.family("service")
.containerDefinitions(serializeJson(
jsonArray(
jsonObject(
jsonProperty("name", "first"),
jsonProperty("image", "service-first"),
jsonProperty("cpu", 10),
jsonProperty("memory", 512),
jsonProperty("essential", true),
jsonProperty("portMappings", jsonArray(jsonObject(
jsonProperty("containerPort", 80),
jsonProperty("hostPort", 80)
)))
),
jsonObject(
jsonProperty("name", "second"),
jsonProperty("image", "service-second"),
jsonProperty("cpu", 10),
jsonProperty("memory", 256),
jsonProperty("essential", true),
jsonProperty("portMappings", jsonArray(jsonObject(
jsonProperty("containerPort", 443),
jsonProperty("hostPort", 443)
)))
)
)))
.volumes(TaskDefinitionVolumeArgs.builder()
.name("service-storage")
.hostPath("/ecs/service-storage")
.build())
.placementConstraints(TaskDefinitionPlacementConstraintArgs.builder()
.type("memberOf")
.expression("attribute:ecs.availability-zone in [us-west-2a, us-west-2b]")
.build())
.build());
}
}
resources:
service:
type: aws:ecs:TaskDefinition
properties:
family: service
containerDefinitions:
fn::toJSON:
- name: first
image: service-first
cpu: 10
memory: 512
essential: true
portMappings:
- containerPort: 80
hostPort: 80
- name: second
image: service-second
cpu: 10
memory: 256
essential: true
portMappings:
- containerPort: 443
hostPort: 443
volumes:
- name: service-storage
hostPath: /ecs/service-storage
placementConstraints:
- type: memberOf
expression: attribute:ecs.availability-zone in [us-west-2a, us-west-2b]
The containerDefinitions property accepts a JSON document describing each container: its image, CPU and memory allocation, and port mappings. The portMappings array exposes container ports to the host or load balancer. The volumes array defines storage that containers can mount, and placementConstraints control which EC2 instances can run the task.
Run Windows containers on Fargate
Teams running Windows workloads can use Fargate to avoid managing EC2 instances while specifying the exact OS and architecture.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const test = new aws.ecs.TaskDefinition("test", {
family: "test",
requiresCompatibilities: ["FARGATE"],
networkMode: "awsvpc",
cpu: "1024",
memory: "2048",
containerDefinitions: `[
{
"name": "iis",
"image": "mcr.microsoft.com/windows/servercore/iis",
"cpu": 1024,
"memory": 2048,
"essential": true
}
]
`,
runtimePlatform: {
operatingSystemFamily: "WINDOWS_SERVER_2019_CORE",
cpuArchitecture: "X86_64",
},
});
import pulumi
import pulumi_aws as aws
test = aws.ecs.TaskDefinition("test",
family="test",
requires_compatibilities=["FARGATE"],
network_mode="awsvpc",
cpu="1024",
memory="2048",
container_definitions="""[
{
"name": "iis",
"image": "mcr.microsoft.com/windows/servercore/iis",
"cpu": 1024,
"memory": 2048,
"essential": true
}
]
""",
runtime_platform={
"operating_system_family": "WINDOWS_SERVER_2019_CORE",
"cpu_architecture": "X86_64",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ecs"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := ecs.NewTaskDefinition(ctx, "test", &ecs.TaskDefinitionArgs{
Family: pulumi.String("test"),
RequiresCompatibilities: pulumi.StringArray{
pulumi.String("FARGATE"),
},
NetworkMode: pulumi.String("awsvpc"),
Cpu: pulumi.String("1024"),
Memory: pulumi.String("2048"),
ContainerDefinitions: pulumi.String(`[
{
"name": "iis",
"image": "mcr.microsoft.com/windows/servercore/iis",
"cpu": 1024,
"memory": 2048,
"essential": true
}
]
`),
RuntimePlatform: &ecs.TaskDefinitionRuntimePlatformArgs{
OperatingSystemFamily: pulumi.String("WINDOWS_SERVER_2019_CORE"),
CpuArchitecture: pulumi.String("X86_64"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var test = new Aws.Ecs.TaskDefinition("test", new()
{
Family = "test",
RequiresCompatibilities = new[]
{
"FARGATE",
},
NetworkMode = "awsvpc",
Cpu = "1024",
Memory = "2048",
ContainerDefinitions = @"[
{
""name"": ""iis"",
""image"": ""mcr.microsoft.com/windows/servercore/iis"",
""cpu"": 1024,
""memory"": 2048,
""essential"": true
}
]
",
RuntimePlatform = new Aws.Ecs.Inputs.TaskDefinitionRuntimePlatformArgs
{
OperatingSystemFamily = "WINDOWS_SERVER_2019_CORE",
CpuArchitecture = "X86_64",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ecs.TaskDefinition;
import com.pulumi.aws.ecs.TaskDefinitionArgs;
import com.pulumi.aws.ecs.inputs.TaskDefinitionRuntimePlatformArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var test = new TaskDefinition("test", TaskDefinitionArgs.builder()
.family("test")
.requiresCompatibilities("FARGATE")
.networkMode("awsvpc")
.cpu("1024")
.memory("2048")
.containerDefinitions("""
[
{
"name": "iis",
"image": "mcr.microsoft.com/windows/servercore/iis",
"cpu": 1024,
"memory": 2048,
"essential": true
}
]
""")
.runtimePlatform(TaskDefinitionRuntimePlatformArgs.builder()
.operatingSystemFamily("WINDOWS_SERVER_2019_CORE")
.cpuArchitecture("X86_64")
.build())
.build());
}
}
resources:
test:
type: aws:ecs:TaskDefinition
properties:
family: test
requiresCompatibilities:
- FARGATE
networkMode: awsvpc
cpu: 1024
memory: 2048
containerDefinitions: |
[
{
"name": "iis",
"image": "mcr.microsoft.com/windows/servercore/iis",
"cpu": 1024,
"memory": 2048,
"essential": true
}
]
runtimePlatform:
operatingSystemFamily: WINDOWS_SERVER_2019_CORE
cpuArchitecture: X86_64
When requiresCompatibilities includes “FARGATE”, you must set networkMode to “awsvpc” and specify cpu and memory values from Fargate’s supported combinations. The runtimePlatform block defines the operating system family and CPU architecture. Fargate manages the underlying infrastructure, so you don’t configure placement constraints or host volumes.
Mount EFS file systems for persistent storage
Applications that need shared persistent storage across tasks or availability zones can mount EFS file systems directly into containers.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as std from "@pulumi/std";
const service = new aws.ecs.TaskDefinition("service", {
family: "service",
containerDefinitions: std.file({
input: "task-definitions/service.json",
}).then(invoke => invoke.result),
volumes: [{
name: "service-storage",
efsVolumeConfiguration: {
fileSystemId: fs.id,
rootDirectory: "/opt/data",
transitEncryption: "ENABLED",
transitEncryptionPort: 2999,
authorizationConfig: {
accessPointId: test.id,
iam: "ENABLED",
},
},
}],
});
import pulumi
import pulumi_aws as aws
import pulumi_std as std
service = aws.ecs.TaskDefinition("service",
family="service",
container_definitions=std.file(input="task-definitions/service.json").result,
volumes=[{
"name": "service-storage",
"efs_volume_configuration": {
"file_system_id": fs["id"],
"root_directory": "/opt/data",
"transit_encryption": "ENABLED",
"transit_encryption_port": 2999,
"authorization_config": {
"access_point_id": test["id"],
"iam": "ENABLED",
},
},
}])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ecs"
"github.com/pulumi/pulumi-std/sdk/go/std"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
invokeFile, err := std.File(ctx, &std.FileArgs{
Input: "task-definitions/service.json",
}, nil)
if err != nil {
return err
}
_, err = ecs.NewTaskDefinition(ctx, "service", &ecs.TaskDefinitionArgs{
Family: pulumi.String("service"),
ContainerDefinitions: pulumi.String(invokeFile.Result),
Volumes: ecs.TaskDefinitionVolumeArray{
&ecs.TaskDefinitionVolumeArgs{
Name: pulumi.String("service-storage"),
EfsVolumeConfiguration: &ecs.TaskDefinitionVolumeEfsVolumeConfigurationArgs{
FileSystemId: pulumi.Any(fs.Id),
RootDirectory: pulumi.String("/opt/data"),
TransitEncryption: pulumi.String("ENABLED"),
TransitEncryptionPort: pulumi.Int(2999),
AuthorizationConfig: &ecs.TaskDefinitionVolumeEfsVolumeConfigurationAuthorizationConfigArgs{
AccessPointId: pulumi.Any(test.Id),
Iam: pulumi.String("ENABLED"),
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
using Std = Pulumi.Std;
return await Deployment.RunAsync(() =>
{
var service = new Aws.Ecs.TaskDefinition("service", new()
{
Family = "service",
ContainerDefinitions = Std.File.Invoke(new()
{
Input = "task-definitions/service.json",
}).Apply(invoke => invoke.Result),
Volumes = new[]
{
new Aws.Ecs.Inputs.TaskDefinitionVolumeArgs
{
Name = "service-storage",
EfsVolumeConfiguration = new Aws.Ecs.Inputs.TaskDefinitionVolumeEfsVolumeConfigurationArgs
{
FileSystemId = fs.Id,
RootDirectory = "/opt/data",
TransitEncryption = "ENABLED",
TransitEncryptionPort = 2999,
AuthorizationConfig = new Aws.Ecs.Inputs.TaskDefinitionVolumeEfsVolumeConfigurationAuthorizationConfigArgs
{
AccessPointId = test.Id,
Iam = "ENABLED",
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ecs.TaskDefinition;
import com.pulumi.aws.ecs.TaskDefinitionArgs;
import com.pulumi.aws.ecs.inputs.TaskDefinitionVolumeArgs;
import com.pulumi.aws.ecs.inputs.TaskDefinitionVolumeEfsVolumeConfigurationArgs;
import com.pulumi.aws.ecs.inputs.TaskDefinitionVolumeEfsVolumeConfigurationAuthorizationConfigArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.FileArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var service = new TaskDefinition("service", TaskDefinitionArgs.builder()
.family("service")
.containerDefinitions(StdFunctions.file(FileArgs.builder()
.input("task-definitions/service.json")
.build()).result())
.volumes(TaskDefinitionVolumeArgs.builder()
.name("service-storage")
.efsVolumeConfiguration(TaskDefinitionVolumeEfsVolumeConfigurationArgs.builder()
.fileSystemId(fs.id())
.rootDirectory("/opt/data")
.transitEncryption("ENABLED")
.transitEncryptionPort(2999)
.authorizationConfig(TaskDefinitionVolumeEfsVolumeConfigurationAuthorizationConfigArgs.builder()
.accessPointId(test.id())
.iam("ENABLED")
.build())
.build())
.build())
.build());
}
}
resources:
service:
type: aws:ecs:TaskDefinition
properties:
family: service
containerDefinitions:
fn::invoke:
function: std:file
arguments:
input: task-definitions/service.json
return: result
volumes:
- name: service-storage
efsVolumeConfiguration:
fileSystemId: ${fs.id}
rootDirectory: /opt/data
transitEncryption: ENABLED
transitEncryptionPort: 2999
authorizationConfig:
accessPointId: ${test.id}
iam: ENABLED
The efsVolumeConfiguration block connects a volume to an EFS file system by ID. The transitEncryption property secures data in transit, and authorizationConfig enables IAM-based access control through an EFS access point. Containers reference the volume by name in their mount points.
Route traffic through App Mesh service mesh
Service mesh architectures use sidecar proxies to handle service-to-service communication and observability without changing application code.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as std from "@pulumi/std";
const service = new aws.ecs.TaskDefinition("service", {
family: "service",
containerDefinitions: std.file({
input: "task-definitions/service.json",
}).then(invoke => invoke.result),
proxyConfiguration: {
type: "APPMESH",
containerName: "applicationContainerName",
properties: {
AppPorts: "8080",
EgressIgnoredIPs: "169.254.170.2,169.254.169.254",
IgnoredUID: "1337",
ProxyEgressPort: "15001",
ProxyIngressPort: "15000",
},
},
});
import pulumi
import pulumi_aws as aws
import pulumi_std as std
service = aws.ecs.TaskDefinition("service",
family="service",
container_definitions=std.file(input="task-definitions/service.json").result,
proxy_configuration={
"type": "APPMESH",
"container_name": "applicationContainerName",
"properties": {
"AppPorts": "8080",
"EgressIgnoredIPs": "169.254.170.2,169.254.169.254",
"IgnoredUID": "1337",
"ProxyEgressPort": "15001",
"ProxyIngressPort": "15000",
},
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ecs"
"github.com/pulumi/pulumi-std/sdk/go/std"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
invokeFile, err := std.File(ctx, &std.FileArgs{
Input: "task-definitions/service.json",
}, nil)
if err != nil {
return err
}
_, err = ecs.NewTaskDefinition(ctx, "service", &ecs.TaskDefinitionArgs{
Family: pulumi.String("service"),
ContainerDefinitions: pulumi.String(invokeFile.Result),
ProxyConfiguration: &ecs.TaskDefinitionProxyConfigurationArgs{
Type: pulumi.String("APPMESH"),
ContainerName: pulumi.String("applicationContainerName"),
Properties: pulumi.StringMap{
"AppPorts": pulumi.String("8080"),
"EgressIgnoredIPs": pulumi.String("169.254.170.2,169.254.169.254"),
"IgnoredUID": pulumi.String("1337"),
"ProxyEgressPort": pulumi.String("15001"),
"ProxyIngressPort": pulumi.String("15000"),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
using Std = Pulumi.Std;
return await Deployment.RunAsync(() =>
{
var service = new Aws.Ecs.TaskDefinition("service", new()
{
Family = "service",
ContainerDefinitions = Std.File.Invoke(new()
{
Input = "task-definitions/service.json",
}).Apply(invoke => invoke.Result),
ProxyConfiguration = new Aws.Ecs.Inputs.TaskDefinitionProxyConfigurationArgs
{
Type = "APPMESH",
ContainerName = "applicationContainerName",
Properties =
{
{ "AppPorts", "8080" },
{ "EgressIgnoredIPs", "169.254.170.2,169.254.169.254" },
{ "IgnoredUID", "1337" },
{ "ProxyEgressPort", "15001" },
{ "ProxyIngressPort", "15000" },
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ecs.TaskDefinition;
import com.pulumi.aws.ecs.TaskDefinitionArgs;
import com.pulumi.aws.ecs.inputs.TaskDefinitionProxyConfigurationArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.FileArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var service = new TaskDefinition("service", TaskDefinitionArgs.builder()
.family("service")
.containerDefinitions(StdFunctions.file(FileArgs.builder()
.input("task-definitions/service.json")
.build()).result())
.proxyConfiguration(TaskDefinitionProxyConfigurationArgs.builder()
.type("APPMESH")
.containerName("applicationContainerName")
.properties(Map.ofEntries(
Map.entry("AppPorts", "8080"),
Map.entry("EgressIgnoredIPs", "169.254.170.2,169.254.169.254"),
Map.entry("IgnoredUID", "1337"),
Map.entry("ProxyEgressPort", "15001"),
Map.entry("ProxyIngressPort", "15000")
))
.build())
.build());
}
}
resources:
service:
type: aws:ecs:TaskDefinition
properties:
family: service
containerDefinitions:
fn::invoke:
function: std:file
arguments:
input: task-definitions/service.json
return: result
proxyConfiguration:
type: APPMESH
containerName: applicationContainerName
properties:
AppPorts: '8080'
EgressIgnoredIPs: 169.254.170.2,169.254.169.254
IgnoredUID: '1337'
ProxyEgressPort: 15001
ProxyIngressPort: 15000
The proxyConfiguration block wires App Mesh into your task. The containerName identifies which container acts as the Envoy proxy, and the properties map configures port routing: AppPorts lists application ports, ProxyIngressPort and ProxyEgressPort define where the proxy listens. App Mesh intercepts traffic between containers and external services.
Beyond these examples
These snippets focus on specific task definition features: container definitions and resource allocation, volume mounting (EFS, Docker, FSx), Fargate and Windows runtime configuration, and App Mesh proxy integration. They’re intentionally minimal rather than full ECS deployments.
The examples may reference pre-existing infrastructure such as ECS clusters, IAM execution and task roles, EFS file systems and access points, App Mesh virtual nodes and service mesh configuration, and VPC subnets and security groups for awsvpc mode. They focus on configuring the task definition rather than provisioning everything around it.
To keep things focused, common task definition patterns are omitted, including:
- IAM role configuration (executionRoleArn, taskRoleArn)
- Network mode selection and VPC configuration
- Logging configuration (awslogs driver)
- Health checks and container dependencies
- Secrets management and environment variables
- Ephemeral storage allocation
These omissions are intentional: the goal is to illustrate how each task definition feature is wired, not provide drop-in ECS modules. See the ECS TaskDefinition resource reference for all available configuration options.
Let's create AWS ECS Task Definitions
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Immutability
containerDefinitions, family, networkMode, cpu, memory, volumes, and others. Changing these forces resource replacement.trackLatest to true to track the latest ACTIVE revision on AWS instead of the one stored in state. Default is false.skipDestroy to true to retain the old revision when the resource is destroyed or replaced. Default is false.Container Definitions & JSON
\" when directly in JSON (e.g., "value": "I \"love\" quotes"), or \\\" in variables (e.g., value = "I \\\"love\\\" quotes").JSON.stringify with an array of container definitions, each specifying name, image, cpu, memory, essential, and other properties like portMappings.IAM Roles & Permissions
executionRoleArn is for the ECS container agent and Docker daemon to pull images and write logs. taskRoleArn allows your container tasks to make calls to other AWS services.Fargate & Launch Types
requiresCompatibilities to FARGATE, networkMode to awsvpc, and specify both cpu (in units) and memory (in MiB). These fields are required for Fargate.requiresCompatibilities to FARGATE, networkMode to awsvpc, and configure runtimePlatform with operatingSystemFamily (e.g., WINDOWS_SERVER_2019_CORE) and cpuArchitecture (e.g., X86_64).Networking & Fault Injection
awsvpc, bridge, host, and none. The networkMode property is required.awsvpc or host network modes and isn’t available on Windows. Set enableFaultInjection to true and ensure your networkMode is compatible.Storage & Volumes
dockerVolumeConfiguration (for Docker volumes and NFS), efsVolumeConfiguration (for Amazon EFS with optional encryption), and fsxWindowsFileServerVolumeConfiguration (for FSX Windows File Server).arn includes the full ARN with the revision number. arnWithoutRevision omits the revision and always refers to the latest ACTIVE revision, useful when you want the most recent version.Using a different cloud?
Explore containers guides for other cloud providers: