Part 1 of 3
Install Apple Container & Run Your First Container
10 minutes from zero to working container. No Docker Desktop required.
Prerequisites
You need
- macOS 26 or later
- Apple Silicon Mac (M1/M2/M3/M4)
- Homebrew installed
- Terminal access
You don't need
- Docker Desktop (uninstall it now, or keep both — they coexist)
- Xcode or developer tools beyond what Homebrew requires
- A paid license — Apple Container is free
Step 1: Install Apple Container
brew install container
This installs the container CLI. Verify with:
container version
Expected output: version string with build info. If you see command not found, restart your terminal or run brew link container.
Step 2: Start the Container System
container system start
This initializes the Virtualization.framework backend. You'll be prompted for your password once — Apple Container needs it to create VMs. After the first run, it starts automatically on login (configurable via launchd).
Verify the system is running:
container system status
Step 3: Configure DNS
Apple Container uses its own DNS domain for inter-container communication. Set it once:
container system property set dns.domain dev.internal
This means containers can reach each other at container-name.dev.internal — no port mapping needed. Each container gets its own IP on the virtual network.
-p 8080:80 port mapping. In Apple Container, each container has its own IP. You access it directly at <container-ip>:80 or via DNS at <name>.dev.internal:80.
Step 4: Pull and Run Your First Container
Pull an image from Docker Hub (OCI compatible):
container pull nginx:latest
Run it:
container run --name my-nginx nginx:latest
Check it's running:
container ps
CONTAINER ID NAME IMAGE STATUS IP
abc123def456 my-nginx nginx:latest running 10.0.0.2
Access it at http://10.0.0.2 or http://my-nginx.dev.internal — you should see the Nginx welcome page.
Docker → Apple Container Command Cheat Sheet
| Action | Docker | Apple Container |
|---|---|---|
| List containers | docker ps | container ps |
| Run a container | docker run -d --name X image | container run --name X image |
| Stop a container | docker stop X | container stop X |
| Remove a container | docker rm X | container rm X |
| View logs | docker logs X | container logs X |
| Execute in container | docker exec -it X sh | container exec X sh |
| Pull an image | docker pull image | container pull image |
| List images | docker images | container images |
| Bind mount | -v /host/path:/container/path | --mount type=bind,src=/host/path,dst=/container/path |
| Named volume | -v vol_name:/path | --mount type=volume,src=vol_name,dst=/path |
| Environment variable | -e KEY=val | --env KEY=val |
Next: Solve the Compose Problem
You've got a single container running. Now let's handle multi-container setups — without compose.
Compose Alternative →