Local ECS for integration tests
Run local Amazon ECS for tests with fakecloud. Full 76-operation API, real Fargate-style task execution via Docker, rolling + CODE_DEPLOY blue/green deployments, daemons, ECS Exec. Free, AGPL-3.0.
Need local ECS for integration tests? Use fakecloud.
curl -fsSL https://fakecloud.dev/install.sh | bash
fakecloudPoint your AWS SDK at http://localhost:4566. Tasks really run — RunTask shells out to docker pull + docker run, captures the exit code, and forwards stdout/stderr to fakecloud CloudWatch Logs when the container declares logDriver=awslogs.
Why fakecloud for ECS
- Full API — 77 operations at 100% conformance. Clusters, task definitions, tasks, services, service deployments, task sets, container instances, attributes, capacity providers, task protection, daemons, ExpressGatewayService, ECS Exec, and the agent-side
Submit*/DiscoverPollEndpointsurface. - Real Fargate-style task execution.
RunTaskdoesdocker pull <image>->docker run -d->docker wait(blocks on exit) ->docker logs(captures stdout/stderr) ->docker rm. Exit code lands oncontainers[].exitCode;pullStartedAt/pullStoppedAttimestamps are recorded the way real ECS does. - Services with rolling deployments.
CreateServicespawns tasks to matchdesiredCountand tags each withstartedBy=ecs-svc/<name>.UpdateServiceflips the previous PRIMARY deployment toACTIVE, creates a new PRIMARY for the target revision, and drains old tasks while new ones come up.minimumHealthyPercent/maximumPercentand the deployment circuit breaker are honored. - CODE_DEPLOY blue/green task sets. Services with
deploymentController.type=CODE_DEPLOYskip the inline rolling deployment and let CodeDeploy-style external task-set churn drive the cutover viaCreateTaskSet/UpdateServicePrimaryTaskSet/DeleteTaskSet. - Placement constraints + strategies. Both
RunTaskandCreateServicehonourplacementConstraints[](distinctInstance,memberOf <expression>) andplacementStrategy[](random,spread,binpackbycpu/memory). - awsvpc networking. Task definitions with
networkMode=awsvpcallocate a per-task ENI from the supplied subnets; the ENI shows up onattachments[]withprivateIPv4Address,subnetId, andsecurityGroups[]. Subnet exhaustion fails the task withstopCode=TaskFailedToStart. - Daemons + ExpressGatewayService.
CreateDaemonspawns one task per matching capacity-provider host so the daemon scales with the cluster. The 2026 ExpressGatewayService deployment controller is wired end-to-end. - ECS Exec.
ExecuteCommandstarts the command in the task's running container withdocker exec(orpodman exec) and returns the session at once, as ECS does. The command runs detached, as given rather than through a shell (pass/bin/sh -c '...'for pipes), and stops when the task stops, or after 20 minutes in images that ship atimeoutbinary. Its output is not streamed back: the returned session has nostreamUrl, soaws ecs execute-command --interactivecannot attach a shell. Check the command's effects in the container instead. - awslogs -> CloudWatch Logs. Container definitions with
logDriver=awslogsget their captured output forwarded to fakecloud Logs, withawslogs-create-group=trueand<prefix>/<container-name>/<task-id>stream naming honored end-to-end. Buffered events are flushed synchronously before a task transitions to STOPPED, soGetLogEventsright after STOPPED sees every line. - Container definition fidelity.
ulimits,linuxParameters.capabilities/initProcessEnabled/sharedMemorySize/tmpfs,user,pseudoTerminal,readonlyRootFilesystem,stopTimeout, and per-task EBSvolumeConfigurations[]are all rendered into realdocker runflags. - Task metadata endpoints.
ECS_CONTAINER_METADATA_URI/ECS_CONTAINER_METADATA_URI_V4are injected into every container, pointing at fakecloud's task-metadata v3/v4 endpoints so SDKs and sidecars that read task metadata work out of the box. - Task role credentials. Tasks with a
taskRoleArnget the ECS agent's credentials path inAWS_CONTAINER_CREDENTIALS_RELATIVE_URI(/v2/credentials/<task-id>), served athttp://169.254.170.2inside the task's network, as on ECS. AWS SDKs inside the container pick this up via the default credential-provider chain, soaws sts get-caller-identityworks from inside the container and returnsassumed-role/<role>/<task-id>. If the task's network can't be set up (noNET_ADMIN), fakecloud falls back toAWS_CONTAINER_CREDENTIALS_FULL_URI, which the SDKs refuse; see task role credentials. - Secrets injection. Container
secrets[]ARNs (Secrets Manager + SSM Parameter Store) resolve at task launch and inject as environment variables beforedocker run. Missing values fail the task withstopCode=TaskFailedToStartmatching real ECS. - loadBalancers -> ELBv2. Service
loadBalancers[]register/deregister against the matching ELBv2 target group on task RUNNING/STOPPED transitions, inline with the rolling deployment. - Pulling from local ECR. AWS-private ECR URIs (
<account>.dkr.ecr.<region>.amazonaws.com/<repo>:<tag>) resolve to fakecloud's local OCI v2 endpoint. Push to the local registry, run the task, get the image — no external pulls. - EventBridge events. Task state transitions emit
aws.ecs/ECS Task State Changeevents on the default bus so EB rules can fan out to SQS / SNS / Lambda / Step Functions.
Smoke test (5 commands)
# Start fakecloud.
fakecloud &
# Create a cluster + register a task definition.
aws --endpoint-url http://localhost:4566 ecs create-cluster --cluster-name demo
aws --endpoint-url http://localhost:4566 ecs register-task-definition \
--family hello \
--container-definitions '[{"name":"app","image":"busybox:latest","essential":true,"command":["echo","hello from ecs"]}]'
# Run it. The container actually executes.
aws --endpoint-url http://localhost:4566 ecs run-task --cluster demo --task-definition hello
# Inspect captured output.
curl http://localhost:4566/_fakecloud/ecs/tasksAssert on what was run (first-party SDKs)
import { FakeCloud } from "fakecloud";
const fc = new FakeCloud();
const { tasks } = await fc.ecs.getTasks({ cluster: "demo" });
const { logs, exitCode } = await fc.ecs.getTaskLogs(tasks[0].taskArn);
expect(exitCode).toBe(0);
expect(logs).toContain("hello from ecs");Same API in Python, Go, Java, PHP, and Rust. See the SDKs page for per-language examples.
What about LocalStack?
LocalStack's ECS support is paid-only since the March 2026 Community switch. fakecloud is free, AGPL-3.0, and ships the full 60-operation API plus real container execution.
Running inside Kubernetes
Running fakecloud itself inside Kubernetes? Set FAKECLOUD_ECS_BACKEND=k8s (or the global FAKECLOUD_CONTAINER_BACKEND=k8s) and ECS tasks run as native Pods instead of Docker containers — no docker-in-docker. See the Kubernetes backend guide.
Read the docs
- Kubernetes backend — run ECS tasks (and Lambda / RDS / ElastiCache) as native Pods.
- ECS service page — full operation list, introspection endpoints, awslogs / secrets / task-role wiring.
- Cross-service integration guide — every ECR / ECS / Logs / Secrets / SSM / EventBridge wiring fakecloud actually executes.
crates/fakecloud-ecssource.