TaskDefinition
Source:
src/AWS/ECS/TaskDefinition.ts
A standalone ECS task definition for bring-your-own-container workloads.
Unlike the Effect-native AWS.ECS.Task (which bundles an inline program and
builds/pushes a Docker image), TaskDefinition registers user-supplied
containerDefinitions — any image URI from ECR, public.ecr.aws, or an
external registry — with full control over Fargate/EC2 compatibility,
volumes, runtime platform, and IAM roles.
Task definitions are immutable revisions under a family:
- reconcile registers a new revision only when the definition content
changed (compared against the observed latest
ACTIVErevision), so a no-op redeploy keeps the same revision; - changing the
familyreplaces the resource; - destroy deregisters and hard-deletes every revision of the family. ECS
may retain referenced revisions in
DELETE_IN_PROGRESSuntil their tasks and services terminate; that is a successful terminal state.
Layering — why TaskDefinition is deliberately not a Platform. ECS
splits “what runs” from “how it runs”: a task definition is the immutable
container spec, while Task (runs to completion) and Service
(long-running) are
the execution vehicles. The effectful Platform abstraction requires
Alchemy to own the container image and entrypoint so it can bundle the
inline Effect program — that is exactly what AWS.ECS.Task does (bundle →
Docker build/push → register definition → serve the program). Making
TaskDefinition also a Platform would duplicate Task while
contradicting this resource’s purpose: user-supplied images whose
entrypoint Alchemy must not rewrite. So the effectful path is
AWS.ECS.Task; the bring-your-own-container path is TaskDefinition.
Both surface taskDefinitionArn / containerName / port, so either
plugs into AWS.ECS.Service’s task prop unchanged.
Creating a Task Definition
Section titled “Creating a Task Definition”Public Image on Fargate
const taskDef = yield* TaskDefinition("Nginx", { containerDefinitions: [ { name: "nginx", image: "public.ecr.aws/nginx/nginx:stable", essential: true, portMappings: [{ containerPort: 80, protocol: "tcp" }], }, ],});With IAM Roles and CloudWatch Logs
const taskDef = yield* TaskDefinition("Api", { cpu: 512, memory: 1024, taskRoleArn: taskRole, // AWS.IAM.Role resource or raw ARN executionRoleArn: executionRole, // needed for awslogs / private images awslogs: true, // creates /ecs/{family} and injects awslogs config containerDefinitions: [ { name: "api", image: image.imageUri, essential: true, portMappings: [{ containerPort: 8080 }], environment: [{ name: "STAGE", value: "prod" }], }, ],});Running with a Service
Section titled “Running with a Service”const service = yield* Service("ApiService", { cluster, task: taskDef, // exposes taskDefinitionArn / containerName / port vpcId: vpc.vpcId, subnets: [subnet.subnetId], assignPublicIp: true,});EC2 Launch Type
Section titled “EC2 Launch Type”const taskDef = yield* TaskDefinition("Agent", { requiresCompatibilities: ["EC2"], networkMode: "bridge", volumes: [{ name: "docker-sock", host: { sourcePath: "/var/run/docker.sock" } }], containerDefinitions: [ { name: "agent", image: "public.ecr.aws/docker/library/busybox:stable", memory: 128, essential: true, mountPoints: [{ sourceVolume: "docker-sock", containerPath: "/var/run/docker.sock" }], }, ],});