docker — compatibility shim for apple's container CLI
A drop-in docker replacement for macOS systems that use Apple's
container CLI instead of Docker.
It accepts docker-style invocations, translates them to container calls, and fails
loudly — never silently — on docker features that container does not have.
Install
Requirements: bash (any version from macOS' built-in 3.2 up), container on the system.
git clone <this repo> ~/dev/docker-wrapper
ln -s ~/dev/docker-wrapper/docker.sh ~/bin/docker
The file name does not matter — the name of the symlink in your PATH does.
docker.sh resolves its own lib/ directory through symlinks, so the repo
can live anywhere.
Usage
docker — compatibility shim for apple's `container` CLI
usage: docker [docker-style arguments]
Translated 1:1 to container:
run build ps images exec logs pull push login logout inspect rm rmi
volume network system prune
Passed through untouched (container-only):
builder machine registry system start|stop|logs|dns|kernel
Anything docker-only exits 125 with an explanation on stderr.
Everything you type keeps docker syntax; the shim rewrites flags and forwards
the result to container:
docker ps # container ps
docker ps -aq # container ps -a -q
docker run -itd --name web nginx # container run -i -t -d --name web nginx
docker run --cpus 2 --platform linux/arm64 alpine
# container run -c 2 --arch arm64 alpine
docker logs --tail 20 web # container logs -n 20 web
docker login -u me reg.example.com # container login --username me reg.example.com
Everything after the first positional argument — image name, container command,
its arguments — is copied verbatim, so docker run -it img sh -c "ls -la"
reaches the container untouched.
Flag translation
Clustered short flags (-itd), attached values (-w/app, -eFOO=1) and
--flag=value are handled generically.
| docker | container | Notes |
|---|---|---|
-w, --workdir |
--cwd |
rename |
-e, --env |
--env |
identical |
--cpus N |
-c N |
rename; container -c is the CPU count |
--platform linux/arm64 |
--arch arm64 |
value rewritten (OS prefix stripped) |
--env-file F |
repeated --env … |
file expanded into --env records |
logs --tail N |
logs -n N |
rename |
-v, --volume, -t, -i, -d, --name, -u, -f |
identical | pass-through |
Deliberately rejected — these would silently mean something different or
don't exist in container:
| docker | Why rejected |
|---|---|
run -a / --attach |
container run -a means --arch — use docker logs to follow output |
run -c / --cpu-shares |
container -c is the CPU count — use --cpus N |
run -p / --publish |
no port publishing in Apple container |
run --network, --restart, --gpus |
not supported by container |
ps --format, images --format |
container prints a fixed table |
rm -v |
no anonymous-volume cleanup — use docker volume rm |
Anything else docker-only — compose, stop, start, cp, stats, swarm,
network connect, client flags like -H/--host, … — exits 125 with a hint at
the closest alternative on stderr.
Testing
bash run_tests.sh
The suite is fully offline: it stubs container via CONTAINER_BIN and
asserts the exact argv reaching it, exit 125 plus a stderr notice for
unsupported features, and that container is never invoked in rejected
cases. 111 tests, no network, no Apple container installation required.
It finds the wrapper under test automatically:
SHIM=/path/to/docker.sh— explicit override, always wins.dockerinPATH— if it identifies itself with the shim's usage banner ("compatibility shim"), the suite tests through the symlink, which also verifies the install. Real Docker prints a different banner and is ignored../docker.shnext to the suite.
Notes and quirks
- Exit codes: unsupported features exit 125 (docker's CLI-error
convention); no arguments prints usage and exits 64; anything else is the
exit code of the underlying
containercall. - macOS bash 3.2 works: the scripts run under the stock
/bin/bash. - No daemon assumptions: client flags like
-H/--hostare rejected — Apple container is a local CLI with no remote API.