brew install limaSave as ~/lima-default.yaml:
minimumLimaVersion: 2.0.0
base:
- template:_images/ubuntu-24.04
- template:_default/mounts
vmType: vz
cpus: 4
memory: 8GiB
disk: 40GiB
mountType: virtiofs
mountInotify: true
vmOpts:
vz:
rosetta:
enabled: true
binfmt: true
containerd:
system: true
user: true
hostResolver:
enabled: true
hosts:
host.docker.internal: host.lima.internallimactl create --name=default ~/lima-default.yaml
limactl start defaultlima sudo nerdctl run --privileged --rm tonistiigi/binfmt --install allsudo ln -s /opt/homebrew/bin/nerdctl.lima /usr/local/bin/nerdctl# Container runtime: Lima + containerd + nerdctl + BuildKit
nerdctl() {
/opt/homebrew/bin/limactl shell --preserve-env "${LIMA_INSTANCE:-default}" sudo nerdctl "$@"
}
export -f nerdctl
nerdctl-rootless() {
/opt/homebrew/bin/limactl shell --preserve-env "${LIMA_INSTANCE:-default}" nerdctl "$@"
}
export -f nerdctl-rootless
docker() {
/opt/homebrew/bin/limactl shell --preserve-env "${LIMA_INSTANCE:-default}" sudo nerdctl "$@"
}
export -f docker
docker-compose() {
/opt/homebrew/bin/limactl shell --preserve-env "${LIMA_INSTANCE:-default}" sudo nerdctl compose "$@"
}
export -f docker-composeInstall ms-azuretools.vscode-docker extension, then add to settings:
{
"docker.dockerPath": "/usr/local/bin/nerdctl"
}source ~/.bashrc
nerdctl run --rm alpine echo "it works"
docker run --rm --platform=amd64 alpine uname --machine # x86_64┌─ macOS (Apple Silicon) ──────────────────────────────┐
│ │
│ nerdctl() → lima sudo nerdctl (rootful) │
│ nerdctl-rootless → lima nerdctl (rootless) │
│ docker() → lima sudo nerdctl (compat alias) │
│ docker-compose() → lima sudo nerdctl compose │
│ │
└───────────────────────┬───────────────────────────────┘
│ SSH (limactl shell)
┌───────────────────────▼───────────────────────────────┐
│ Lima VM "default" │
│ Ubuntu 24.04 · vz · virtiofs · 4 CPU · 8 GB · 40 GB │
│ │
│ containerd (system + user) │
│ nerdctl · BuildKit │
│ │
│ Multi-arch: │
│ arm64 → native │
│ x86_64 → Rosetta (near-native speed) │
│ arm/v7, s390x, ppc64le → QEMU binfmt │
│ │
│ Mounts: ~/ (virtiofs, read-only by default) │
│ DNS: host.docker.internal → host machine │
└────────────────────────────────────────────────────────┘
# Pull / run / stop / rm — same as docker
nerdctl pull alpine:latest
nerdctl run --detach --name myapp --publish 8080:80 nginx:latest
nerdctl stop myapp
nerdctl rm myapp
# List
nerdctl ps
nerdctl images
# Build (BuildKit)
nerdctl build --tag myimage:latest .
# Compose
nerdctl compose up --detach
nerdctl compose down
# docker alias works identically
docker run --rm alpine echo "works"
docker-compose up --detach# Default: native arm64
nerdctl run --rm alpine uname --machine
# aarch64
# Force amd64 (Rosetta — fast)
nerdctl run --rm --platform=amd64 alpine uname --machine
# x86_64
# Other architectures (QEMU — slower)
nerdctl run --rm --platform=linux/arm/v7 alpine uname --machine
# armv7l
# Multi-platform build
nerdctl build --platform=linux/amd64,linux/arm64 --tag myimage:latest .Container binary (any arch)
↓
Linux kernel (arm64) — binfmt_misc
↓ reads ELF header → determines architecture
↓
┌─ arm64 → runs natively
├─ x86_64 → Rosetta (VZ framework passthrough, near-native)
└─ arm/v7+ → QEMU user-mode emulation (slower)
QEMU binfmt registrations don't survive VM reboot. Re-register after limactl stop/start:
lima sudo nerdctl run --privileged --rm tonistiigi/binfmt --install allRosetta survives reboots — it's provided by the VM framework.
# Rootful (default) — maximum compatibility
nerdctl run --rm alpine id
# uid=0(root)
# Rootless — better security, some limitations
nerdctl-rootless run --rm alpine id
# uid=0(root) inside user namespaceRootful is the default because most images expect root. Use rootless for untrusted workloads.
limactl list # status
limactl stop default # stop VM
limactl start default # start VM
lima # SSH into VM
lima sudo nerdctl version # run command inside VMVM config: ~/.lima/default/lima.yaml
Home directory (~/) is mounted via virtiofs (read-only by default):
nerdctl run --rm --volume "${HOME}/project:/app:ro" alpine ls /appPaths outside ~/ (like /tmp) are NOT mounted. Use ~/ for build contexts and volume mounts.
| Feature | Docker | nerdctl |
|---|---|---|
| CLI | docker |
nerdctl (aliased as docker) |
| Runtime | Docker Engine (dockerd) | containerd |
| Build | BuildKit via dockerd | BuildKit standalone |
| Socket | /var/run/docker.sock |
No socket (CLI only) |
| Compose | docker compose |
nerdctl compose |
| Image format | OCI / Docker | OCI |
| What | Where |
|---|---|
| VM config | ~/.lima/default/lima.yaml |
| VM disk | ~/.lima/default/ |
| nerdctl symlink | /usr/local/bin/nerdctl → nerdctl.lima |
| Shell functions | ~/.bashrc (bottom of file) |
| VS Code settings | docker.dockerPath = /usr/local/bin/nerdctl |
| Lima binary | /opt/homebrew/bin/limactl |
# VM won't start
limactl list # check status
limactl stop default # force stop
limactl start default # restart
# containerd issues inside VM
lima sudo systemctl status containerd
lima sudo systemctl restart containerd
# Disk full
lima df --human-readable # check disk usage
lima sudo nerdctl system prune --all # clean images/containers
# binfmt lost after reboot
lima sudo nerdctl run --privileged --rm tonistiigi/binfmt --install all