Profile
Back to NewsBack
GitHub Trending 9 min
Reader Mode
us/mocker: Docker-compatible container CLI built on Apple's Containerization framework. Same commands, same flags, mocker run, ps, stop, build, compose, stats, all working on macOS 26.

us/mocker: Docker-compatible container CLI built on Apple's Containerization framework. Same commands, same flags, mocker run, ps, stop, build, compose, stats, all working on macOS 26.

9 hours ago

Mocker

A Docker-compatible container management tool built on Apple's Containerization framework

Swift</a> Platform</a> License</a> Swift Package Manager</a> GitHub Sponsors</a>

English · 简体中文

If Mocker saves you from Docker Desktop, sponsor the project on GitHub — it directly funds development.


Mocker is a Docker-compatible CLI + Compose tool that runs natively on macOS using Apple's Containerization framework (macOS 26+). It speaks the same language as Docker — same commands, same flags, same output format — so your existing scripts and muscle memory just work.

Just replace docker with mocker

# Before
docker compose up -d
docker ps
docker logs my-app
docker exec -it my-app sh

After — same commands, native Apple runtime, no Docker Desktop

mocker compose up -d mocker ps mocker logs my-app mocker exec -it my-app sh

Your existing docker-compose.yml works as-is.

What's New

See the CHANGELOG for the full, always-current release history — it is regenerated automatically on every release.

Features

  • Docker CLI compatible — run, ps, stop, rm, exec, logs, build, pull, push, images, tag, rmi, inspect, stats
  • Network management — network create/ls/rm/inspect, and compose networks:
  • Volume management — volume create/ls/rm/inspect
  • Docker Compose v2 — compose up/down/ps/logs/restart with dependency ordering
  • MenuBar GUI — Native SwiftUI app (coming soon)
  • JSON state persistence — All metadata stored in ~/.mocker/
  • Swift 6 concurrency — Full actor-based thread safety throughout
Compatibility note: Mocker parses all Docker CLI flags for drop-in compatibility, but some flags are not supported by Apple's Containerization runtime and will produce a warning or error. See COMMANDS.md for details on which commands are fully functional vs unsupported.

Requirements

| Component | Version | |-----------|---------| | macOS | 26.0+ (Sequoia) | | Swift | 6.0+ | | Xcode | 16.0+ |

Note: The Apple Containerization framework requires macOS 26 on Apple Silicon. Intel Macs are not supported.

Installation

Homebrew (Recommended)

brew tap us/tap
brew install mocker

Build from Source

git clone https://github.com/us/mocker.git
cd mocker
swift build -c release
cp .build/release/mocker /usr/local/bin/mocker

Quick Start

# Pull an image
mocker pull nginx:1.25

Run a container

mocker run -d --name webserver -p 8080:80 nginx:1.25

List running containers

mocker ps

View logs

mocker logs webserver

Stop and remove

mocker stop webserver mocker rm webserver

Usage

Container Lifecycle

# Run with environment variables and volumes
mocker run -d \
  --name myapp \
  -p 8080:80 \
  -e APP_ENV=production \
  --env-file .env \
  -v /host/data:/app/data \
  myimage:latest

Run interactively (foreground)

mocker run --name temp alpine:latest

Force remove a running container

mocker rm -f myapp

Execute a command inside a running container

mocker exec myapp env

Follow logs

mocker logs -f myapp

Images

# Pull specific tag
mocker pull postgres:15

List images

mocker images

List image IDs only

mocker images -q

Tag an image

mocker tag alpine:latest my-registry.io/alpine:v1

Remove an image

mocker rmi my-registry.io/alpine:v1

Build from Dockerfile

mocker build -t myapp:latest .

Multi-platform build (repeats --platform per architecture)

mocker build --platform linux/amd64 --platform linux/arm64 -t myapp:latest .

Push to registry

mocker push my-registry.io/myapp:latest

Manifest Lists (multi-arch images)

# Inspect an OCI image index
mocker manifest inspect myrepo/multi:latest

Assemble a manifest list from existing per-arch images

mocker manifest create myrepo/multi:latest myrepo/app:amd64 myrepo/app:arm64

Splice a child image's platform into an existing list (replaces same-platform entry)

mocker manifest add myrepo/multi:latest myrepo/app:arm64

Drop an entry by platform spec or digest

mocker manifest rm myrepo/multi:latest linux/amd64 mocker manifest rm myrepo/multi:latest sha256:cb96058800ca…

Override platform metadata on an entry

mocker manifest annotate myrepo/multi:latest myrepo/app:arm64 --variant v8

Push the assembled list to the registry

mocker manifest push myrepo/multi:latest

Building for exotic architectures

mocker build --platform linux/ppc64le|s390x|riscv64 works for layer-only Dockerfiles (FROM / COPY / CMD) but fails with Exec format error on any RUN instruction. Apple's container build BuildKit VM is an arm64 Linux VM with **no QEMU binfmt_misc handlers** for non-arm64/non-amd64 architectures. linux/amd64 works only because Apple Silicon ships hardware Rosetta 2 translation. Tracking upstream: apple/container#1496.

Until Apple ships QEMU support, three workarounds exist:

| Path | Tradeoff | |------|----------| | Remote builder. Point mocker at a Linux host that already has QEMU binfmt registered: mocker build --builder --platform linux/ppc64le …. The --builder value is forwarded to container build --builder, which can target a remote BuildKit node (e.g. one registered via docker buildx create --driver remote ssh://host). The RUN steps then execute on the remote host's emulation, not the local arm64 VM. | Needs a reachable remote Linux host (native ppc64le, or x86/arm with qemu-user-static) and a one-time builder registration. | | Run a Podman machine alongside mocker. Its Fedora CoreOS VM has qemu-user-static registered, so podman build --platform linux/ppc64le handles RUN steps. Use mocker manifest create afterwards to assemble per-arch images into a list. | Requires a persistent QEMU VM — extra memory and reliability surface. | | container run --virtualization a Linux VM, install qemu-user-static + Docker inside, build there, then container image save / mocker manifest add the result. | Manual setup; one-time per arch you need. |

For arm64 and amd64 (Rosetta 2) the native path is faster and supported — exotic-arch emulation is a workaround until upstream lands.

Inspect & Stats

# Inspect container (JSON output)
mocker inspect myapp

Inspect multiple targets, or constrain discovery by type

mocker inspect container1 container2 alpine:latest mocker inspect --type image alpine:latest

Docker-compatible ImageInspect JSON array; select a platform when needed

mocker image inspect --platform linux/amd64 alpine:latest

Resource usage stats

mocker stats --no-stream

Networks

# Create a network
mocker network create mynet

List networks

mocker network ls

Attach a container at run time

mocker run --network mynet nginx

Inspect

mocker network inspect mynet

Remove

mocker network rm mynet

Volumes

# Create a named volume
mocker volume create pgdata

List volumes

mocker volume ls

Inspect (shows mountpoint)

mocker volume inspect pgdata

Remove

mocker volume rm pgdata

Docker Compose

# Start all services (detached)
mocker compose -f docker-compose.yml up -d

List compose containers

mocker compose -f docker-compose.yml ps

View logs for a service

mocker compose -f docker-compose.yml logs web

Restart a service

mocker compose -f docker-compose.yml restart api

Tear down

mocker compose -f docker-compose.yml down

Example docker-compose.yml:

version: "3.8"

services: web: image: nginx:1.25 ports: - "8080:80" depends_on: - api

api: image: myapp:latest environment: - DB_HOST=db - DB_PORT=5432 depends_on: - db

db: image: postgres:15 environment: POSTGRES_PASSWORD: secret POSTGRES_DB: myapp volumes: - pgdata:/var/lib/postgresql/data

volumes: pgdata:

System

# System information
mocker system info

Remove stopped containers and unused resources

mocker system prune -f

Architecture

mocker/
├── Sources/
│   ├── MockerKit/          # Shared core library
│   │   ├── Models/         # Data types (ContainerInfo, ImageInfo, ...)
│   │   ├── Config/         # MockerConfig (~/.mocker/ paths)
│   │   ├── Container/      # ContainerEngine + ContainerStore (actor)
│   │   ├── Image/          # ImageManager + ImageStore (actor)
│   │   ├── Network/        # NetworkManager (actor)
│   │   ├── Volume/         # VolumeManager (actor)
│   │   └── Compose/        # ComposeFile parser + ComposeOrchestrator
│   ├── Mocker/             # CLI executable
│   │   ├── Commands/       # One file per command group
│   │   └── Formatters/     # TableFormatter, JSON output
│   └── MockerApp/          # SwiftUI MenuBar app (macOS 26+)
│       ├── MenuBar/
│       ├── ViewModels/
│       └── Views/
└── Tests/
    ├── MockerKitTests/     # Unit tests for core library
    └── MockerTests/        # CLI integration tests

Key Design Decisions

| Concern | Approach | |---------|----------| | Thread safety | All engines/managers are actor types | | Persistence | JSON files in ~/.mocker/{containers,images,volumes}/; networks live in the container runtime itself | | CLI parsing | swift-argument-parser with AsyncParsableCommand | | YAML parsing | Yams library | | Compose naming | Docker v2 convention: projectName-serviceName-1 (hyphen separator) | | JSON output | Always wrapped in array [{...}], matching Docker's inspect format |

Data Directory

Mocker stores all state in ~/.mocker/:

~/.mocker/
├── containers/   # Container metadata (one JSON file per container)
├── images/       # Image metadata
└── volumes/      # Directory volumes (shared by compose services, or from earlier releases)

Other named volumes live in Apple's container runtime as ext4 images, so images whose entrypoint changes ownership of their data directory (redis, postgres) run on them.

Docker Compatibility

Mocker aims for full CLI compatibility with Docker. Key behaviors matched:

  • Error messages: Error response from daemon: ...
  • inspect always returns a JSON array, even for a single object
  • pull idempotency: re-pulling an existing image shows "Image is up to date"
  • Compose container naming: project-service-1 (hyphen, not underscore)
  • stop and rm echo back the identifier provided by the user
  • Short IDs are 12 characters (first 12 of full 64-char hex ID)

Building & Testing

# Build all targets
swift build

Run all tests

swift test

Run specific test suite

swift test --filter MockerKitTests

Run CLI directly

swift run mocker --help

Performance

Benchmarks run on Apple M-series, macOS 26 (hyperfine --warmup 5 --runs 15):

| Tool | Container startup | vs Docker | |------|:-----------------:|:---------:| | Docker Desktop | 320 ms | baseline | | Apple container CLI | 1,030 ms | 3.2× slower | | Mocker | 1,153 ms | 3.6× slower |

Apple's VM-per-container model trades startup time for stronger isolation — every container gets its own lightweight Linux VM. Mocker adds only ~120 ms of management overhead on top of Apple's runtime.

CPU & Memory throughput (sysbench inside container, 30s run):

| Metric | Docker | Apple Container | |--------|:------:|:---------------:| | CPU events/s | 7,958 | 7,894 | | Memory throughput | 13,340 MiB/s | 13,119 MiB/s |

Raw compute performance is equivalent — the VM boundary has negligible overhead for CPU and memory workloads.

How It Works

Mocker delegates to Apple's container CLI for container lifecycle (run, stop, exec, logs, build). Image operations (pull, list, tag, rmi) use Containerization.ImageStore directly. This hybrid approach gives you a fully working Docker-compatible tool on macOS 26 today:

| Operation | Backend | |-----------|---------| | run, stop, exec, logs | /usr/local/bin/container subprocess | | build | container build with live streaming output | | pull, push, tag, rmi | Containerization.ImageStore (direct framework) | | images | Apple CLI image store (shows all pulled + built images) | | stats | VM process RSS/CPU via ps (VirtualMachine.xpc matching) | | Port mapping -p | Persistent mocker __proxy subprocess per port |

Roadmap

  • [x] Full Docker CLI flag compatibility (111 commands)
  • [x] Docker Compose v2 support
  • [x] Network & Volume management
  • [ ] MenuBar GUI
  • [x] Real container execution on macOS 26 (via Apple container CLI)
  • [x] mocker build — delegates to container build with live output
  • [x] mocker stats — real CPU% and memory from VM process
  • [x] Port mapping (-p) — userspace TCP proxy subprocess
  • [x] Registry authentication (mocker login / mocker logout, keychain-backed)
  • [ ] mocker compose --scale
  • [ ] MenuBar live container metrics (CPU, memory, logs)
  • [ ] Image layer size reporting
  • [ ] Direct Containerization framework integration (pending vminit compatibility)

Contributing

Contributions are welcome! Please read docs/contributing.md for guidelines.

# Fork and clone
git clone https://github.com/yourname/mocker.git

Create a feature branch

git checkout -b feat/my-feature

Make changes and test

swift test

Commit with Conventional Commits

git commit -m "feat: add my feature"

License

AGPL-3.0 — see LICENSE for details.


Built with Swift on macOS · Powered by Apple Containerization

Chat with me