Oxcart Download
Menu

Develop for AWS ECS, EKS, Fargate and Lambda locally on a Mac

To test AWS container workloads on an Apple silicon Mac, run the exact images you deploy: ECS and Fargate tasks as a Compose project, Lambda container images with AWS’s built-in Runtime Interface Emulator, and AWS APIs through LocalStack. Oxcart keeps that loop fast, with containers starting in 42 ms and amd64 images running through Rosetta.

Updated

What runs where

AWS container services and their local stand-ins on Oxcart
AWS serviceLocal stand-inYour local workflow
ECS task, Fargate taskDocker Compose with the task’s imagesRun your services together with healthchecks and published ports
Lambda (container image)Lambda base image with the Runtime Interface EmulatorInvoke your function over HTTP on native arm64
S3 and other AWS APIsLocalStackDevelop S3 bucket and object operations locally
EKSkubectl and k9s against the real cluster; kwok for a local APIBuild and test locally, then use kubectl and k9s with your cluster

ECS and Fargate tasks as a Compose project

An ECS task definition is a list of containers with images, environment, port mappings, health checks and start order. Compose describes the same things, so the translation is direct: one service per container definition.

Task definition fields and their Compose equivalents
Task definitioncompose.yaml
imageimage
environment, secretsenvironment, env_file (keep real secrets out of the file)
portMappingsports
healthCheckhealthcheck
dependsOn with HEALTHYdepends_on with condition: service_healthy
runtimePlatform.cpuArchitectureplatform: linux/amd64 or linux/arm64
services:
  api:
    image: ACCOUNT.dkr.ecr.us-east-1.amazonaws.com/api:1.4.0
    platform: linux/amd64          # match the task's cpuArchitecture
    environment:
      DATABASE_URL: postgres://postgres:dev@db:5432/app
    ports: ["8080:8080"]
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:17-alpine
    environment:
      POSTGRES_PASSWORD: dev
      POSTGRES_DB: app
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
      interval: 2s
      retries: 30
docker compose up -d --wait     # returns when db is healthy and api has started
curl localhost:8080/health
docker compose down -v

We verified this pattern on Oxcart with Postgres 17 and an nginx service gated on service_healthy: up --wait returned with both healthy and the published port answering on localhost. For amd64 images built on your Mac, pass the same platform when you run them; a locally built amd64-only image is found only when --platform linux/amd64 (or platform: in Compose) is set.

Run and invoke a Lambda container image locally

  1. Write the handler. Create app.py with a function handler(event, context) that returns a dict, for example {"statusCode": 200, "body": "hello"}.
  2. Write the Dockerfile. Start from an AWS Lambda base image, which includes the Runtime Interface Emulator: FROM public.ecr.aws/lambda/python:3.13, then COPY app.py ${LAMBDA_TASK_ROOT}/ and CMD ["app.handler"].
  3. Build the image. Run docker build -t my-lambda .. Add --platform linux/amd64 if your function is configured for x86_64.
  4. Run it. Run docker run -d -p 9000:8080 my-lambda. The emulator listens on port 8080 inside the container.
  5. Invoke it. Run curl -XPOST localhost:9000/2015-03-31/functions/function/invocations -d '{}'. The response is your handler’s return value, and docker logs shows the Lambda REPORT line with the duration.

In our run the function answered {"statusCode": 200, "body": "hello from lambda on aarch64"}, and the container log showed the Lambda REPORT line with a 19 ms duration. The emulator is AWS’s own: “a proxy for Lambda’s Runtime and Extensions APIs” that stands up the /2015-03-31/functions/function/invocations endpoint.

AWS APIs with LocalStack

LocalStack emulates AWS APIs in one container on port 4566. On Oxcart we ran the 4.9 image and exercised S3 end to end:

docker run -d --name localstack -p 4566:4566 localstack/localstack:4.9
curl -s localhost:4566/_localstack/health          # s3, lambda, dynamodb… "available"
curl -X PUT localhost:4566/my-bucket               # create a bucket
curl -X PUT --data-binary hello localhost:4566/my-bucket/hello.txt
curl localhost:4566/my-bucket/hello.txt            # hello

Know the licensing before you build on it. Since March 23, 2026, the latest LocalStack releases require a LocalStack account and auth token; without LOCALSTACK_AUTH_TOKEN, the latest image exits with “License activation failed”. LocalStack’s free Hobby plan is for non-commercial use, ECS is available from its Base plan and EKS from its Ultimate plan.

Push to ECR and deploy

aws ecr get-login-password --region us-east-1 \
  | docker login --username AWS --password-stdin ACCOUNT.dkr.ecr.us-east-1.amazonaws.com
docker buildx build --platform linux/amd64 --load -t ACCOUNT.dkr.ecr.us-east-1.amazonaws.com/api:1.4.0 .
docker push ACCOUNT.dkr.ecr.us-east-1.amazonaws.com/api:1.4.0

Oxcart keeps the registry password in the macOS Keychain, not in ~/.docker/config.json. Pushing a multi-platform image from Oxcart is not supported: push one tag per architecture, or publish multi-arch manifests from CI.

EKS from your Mac

aws eks update-kubeconfig --name my-cluster adds the cluster to your kubeconfig so you can use kubectl and k9s from macOS. Develop and test your services locally with Oxcart, then deploy the same images to EKS. For local manifest and controller testing, kwok provides a real Kubernetes API server with simulated nodes. The Kubernetes on a Mac guide explains how these workflows fit together.

Why the local loop is worth it

Every change you test locally skips a push, a deploy and a log search. Oxcart makes that loop short: 42 ms for docker run --rm, 0.69 s to create and start 20 containers, and 77 ms to stop and remove them, the fastest of the three runtimes we tested. Outbound connections from containers are opened by your Mac, so a VPN into your AWS network applies to them too.

Questions

How do I test an ECS or Fargate task locally on a Mac?

Run the task’s containers with Docker Compose: one service per container definition, with the same image, environment, port mappings, healthcheck and dependencies. docker compose up -d --wait returns when every service with a healthcheck is healthy. Oxcart runs the stack with healthcheck dependencies and published ports, so you can exercise the services together before deployment.

Can I run AWS Lambda container images locally on Apple silicon?

Yes. AWS Lambda base images include the Runtime Interface Emulator. On Oxcart we built a Python 3.13 function from public.ecr.aws/lambda/python:3.13, ran it with -p 9000:8080, and invoked it with curl: it answered HTTP 200 natively on arm64.

Does LocalStack work on Oxcart?

Yes, as a container. We verified S3 bucket create, put, get and list against localhost:4566 with the LocalStack 4.9 image. Current LocalStack releases need a LocalStack account and auth token, set as LOCALSTACK_AUTH_TOKEN; without one, the latest image exits. LocalStack documents ECS from its Base plan and EKS from its Ultimate plan.

How do I push an image to Amazon ECR from a Mac?

Log in with aws ecr get-login-password --region REGION | docker login --username AWS --password-stdin ACCOUNT.dkr.ecr.REGION.amazonaws.com, then tag and docker push. On Oxcart, docker login stores the password in the macOS Keychain.

Should I build amd64 or arm64 images for Fargate?

Match the task definition’s runtime platform. If it uses ARM64, build native arm64 images on your Mac; if it uses X86_64, build with --platform linux/amd64. Oxcart runs amd64 images locally through Rosetta, so you can test the exact image you deploy.

How do I develop for EKS on my Mac?

Build and test your app and its dependencies locally with Oxcart, then push the images to ECR. Use kubectl and k9s on the Mac to work with your EKS cluster, and kwok on Oxcart to check manifests against a local Kubernetes API. See the Kubernetes on a Mac guide.

Sources and method

  • Examples tested with Oxcart 0.1.2, Mac17,14, macOS 27.2, 2026-10-10 (Compose, Lambda base image with the emulator, LocalStack 4.9 S3, Buildx).
  • LocalStack auth: https://blog.localstack.cloud/localstack-single-image-next-steps/; plans: https://localstack.cloud/pricing/; ECS: https://docs.localstack.cloud/aws/services/ecs/; EKS: https://docs.localstack.cloud/aws/services/eks/.
  • Lambda Runtime Interface Emulator: https://github.com/aws/aws-lambda-runtime-interface-emulator. AWS SAM CLI and Docker: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-docker.html. ECS Local Container Endpoints: https://github.com/awslabs/amazon-ecs-local-container-endpoints. Checked 2026-10-10.
  • Container speed: Oxcart 0.1.2, 2026-10-10, Apple M5 Max, 8 CPUs and 12 GiB, medians of five samples; the other runtimes were measured earlier the same day on the same Mac and harness with the docker 29.4 client.

Try Oxcart on your own projects

Free for 60 days. Then $20 per user, per major version: not a subscription.

Apple silicon · macOS 26 or later

Read next

Release notes

Oxcart 0.1.4

Latest release

Licensing and refinements.

  • Secure email-link license activation.
  • License and Mac management from Settings.
  • Offline license verification.
  • Performance improvements, UI polish, and bug fixes.

Requires macOS 26.0 or later

Oxcart 0.1.3

Idle memory reclamation.

  • Reclaims VM memory when no containers are running.
  • Preserves containers, images, volumes, and networks.

Requires macOS 26.0 or later

Oxcart 0.1.2

Command-line tool integration.

  • Switch between Oxcart's bundled Docker tools and an existing installation.
  • UI polish.

Requires macOS 26.0 or later

Oxcart 0.1.1

Bundled Docker tools and agent controls.

  • Docker CLI 29.9, Compose 5.6, and Buildx 0.38 included.
  • Docker context integration and secure Keychain credentials.
  • MCP agent connections with per-agent permissions and blocking.

Requires macOS 26.0 or later

Oxcart 0.1.0

Docker-compatible containers for Apple silicon.

  • Docker CLI, Compose, and Buildx compatibility.
  • Offline setup with bundled runtime components.
  • Ports organized by project and Git branch.
  • MCP integration with read-only access by default.
  • Verified automatic updates.

Requires macOS 26.0 or later