Replacing Docker Desktop with Colima on macOS
Colima is one of the cleanest ways to run containers locally on macOS. It starts a Linux virtual machine through Lima, runs Docker, containerd, and optional k3s Kubernetes inside that VM, then exposes the result to host-side tools such as docker and kubectl. This note covers how Colima works on macOS, how to install it, which settings matter in practice, how to verify the setup, and which operational details usually trip people up.
Containers are not lightweight macOS processes. They depend on Linux kernel features such as namespaces, cgroups, and OverlayFS. macOS does not provide those interfaces, so Linux containers on macOS always run on top of a Linux virtual machine.
That is the right starting point for understanding Colima. It does not bypass virtualization. It makes that layer lighter and easier to work with. Lima manages the Linux VM. Colima configures the container runtime inside it and ties that runtime into the host command-line workflow.
Colima is best understood as a developer-friendly layer on top of Lima. Lima handles VM lifecycle, file sharing, and port forwarding. Colima takes care of the container runtime and exposes it to the tools you already use on the host.
Three properties matter most in day-to-day use:
- It gives macOS a local environment for Docker, containerd, and optional Kubernetes.
- It works with the host CLI instead of forcing everything through a desktop application workflow.
- It supports multiple profiles, with each profile backed by its own VM. That makes it easy to split a lightweight Docker setup from a heavier Kubernetes setup.
For local container development on macOS, the real question is usually not whether containers can run. They can. The question is whether the environment is easy to reason about. Colima is appealing for three simple reasons.
- The structure is clear. Host CLI, Linux VM, and container runtime are separate layers, which makes troubleshooting easier.
- The controls are explicit. CPU, memory, disk, architecture, Kubernetes, networking, and mount behavior can all be configured through flags or YAML.
- It fits an engineering workflow better than a GUI-first workflow. Scripts, profiles, and repeatable setup steps all work naturally.
If Docker Desktop is already installed, you do not necessarily have to remove it first. What matters more is knowing which Docker context is active, otherwise commands may end up talking to the wrong daemon.
On macOS, the simplest installation path is Homebrew. If you use the Docker runtime, you need the Docker CLI on the host. If you want local Kubernetes, you also need kubectl.
|
1 |
brew install colima docker kubectl |
The first startup can stay close to the defaults. The goal is just to confirm that the host CLI can talk to the VM-backed runtime.
|
1 2 3 |
colima start docker run --rm hello-world docker ps |
If you only need a Docker daemon, that is enough. If you also want local Kubernetes, enable it at startup:
|
1 2 |
colima start --kubernetes kubectl get nodes |
If more than one Docker daemon exists on the machine, check the active context before assuming anything is broken:
|
1 2 |
docker context ls docker context use colima |
Colima accepts both command-line flags and persistent YAML configuration. In practice, colima start --edit is usually the safest entry point because it opens the current profile configuration, lets you change it, and then starts the instance.
The example below is a sensible local-development baseline. It removes private registry assumptions and keeps only the settings that are useful in a public, general-purpose setup.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# Resource sizing. The defaults are fine for a single container, # but small once you run an app stack and k3s together. cpu: 4 memory: 8 disk: 100 # Immutable creation-time settings. Use the host architecture # and keep Docker as the container runtime. arch: host runtime: docker # Single-node k3s. Disable the default Traefik install so it # does not collide with whatever ingress stack you already use. kubernetes: enabled: true version: v1.35.0+k3s1 k3sArgs: - --disable=traefik # Give the VM a host-reachable address for debugging and direct checks. network: address: true mode: shared # On newer macOS versions, prefer Apple's virtualization framework. vmType: vz # On Apple Silicon, enable Rosetta for linux/amd64 userland binaries. rosetta: true # VZ plus virtiofs is a common high-performance combination on macOS. mountType: virtiofs # Make Docker and Kubernetes contexts active on startup. autoActivate: true # Install a small set of debugging tools inside the VM. # Provision scripts should stay idempotent. provision: - mode: system script: | apt-get update apt-get install -y vim curl htop git make dnsutils net-tools iputils-ping telnet |
The official documentation groups Colima settings into resources, VM settings, runtime settings, networking, mounts, SSH, provisioning, and environment variables. The table below summarizes the current upstream template, plus rootDisk, which is documented separately in the configuration guide.
| Key | Default | Meaning | Notes |
| cpu | 2 | Number of vCPUs assigned to the VM. | Resource setting |
| memory | 2 | Memory assigned to the VM, in GiB. | Resource setting |
| disk | 100 | Container data disk size, in GiB. | Can only be increased after creation |
| rootDisk | 20 | Root filesystem disk size for the VM, in GiB. | Documented in the config guide |
| arch | host | VM architecture, either the host architecture or an explicit override. | Immutable after creation |
| runtime | docker | Container runtime. | Immutable after creation |
| modelRunner | docker | Backend used for AI model execution. | AI workload setting |
| hostname | null | Custom VM hostname. | Defaults to colima or colima-<profile> |
| kubernetes.enabled | false | Turns the built-in k3s cluster on or off. | Kubernetes group |
| kubernetes.version | latest stable | k3s version, which must match an actual k3s release string. | Kubernetes group |
| kubernetes.k3sArgs | --disable=traefik | Extra arguments passed to the k3s server. | Kubernetes group |
| kubernetes.port | 0 | Kubernetes API listen port. A value of 0 means "pick a free port". | Kubernetes group |
| autoActivate | true | Makes Docker and Kubernetes contexts active on startup. | Client-side behavior |
| network.address | false | Assigns a host-reachable IP address to the VM. | macOS only |
| network.mode | shared | Network mode. The docs list shared and bridged. | macOS only |
| network.interface | en0 | Host network interface used in bridged mode. | Only used with bridged mode |
| network.preferredRoute | false | Uses the assigned VM IP as the preferred route. | Requires address=true |
| network.dns | [] | Custom DNS resolvers for the VM. | Network group |
| network.dnsHosts | host.docker.internal: host.lima.internal | Built-in DNS host mapping. | Network group |
| network.hostAddresses | false | Replicates host IP addresses into the VM for more specific port forwarding behavior. | Network group |
| network.gatewayAddress | 192.168.5.2 | Gateway address for the VM network. | Last octet must be 2 |
| forwardAgent | false | Forwards the host SSH agent into the VM. | SSH group |
| docker | {} | Configuration block mapped directly into Docker daemon.json. | Advanced setting |
| vmType | qemu | Virtualization backend. | Immutable after creation |
| portForwarder | ssh | Port forwarding mechanism. Valid values are ssh, grpc, and none. | Network group |
| rosetta | false | Enables amd64 userland emulation on Apple Silicon. | Requires VZ |
| binfmt | true | Enables foreign-architecture binary emulation. | Cross-architecture compatibility |
| nestedVirtualization | false | Turns nested virtualization on. | Requires newer Apple Silicon and VZ |
| mountType | sshfs on qemu, virtiofs on vz | Host-to-VM mount driver. | Immutable after creation |
| mountInotify | false | Propagates inotify file events into the VM. | Experimental |
| cpuType | host | CPU type used by QEMU. | QEMU only |
| provision | [] | Provision scripts executed during startup. | Should be idempotent |
| sshConfig | true | Controls whether the host ~/.ssh/config is updated automatically. | SSH group |
| sshPort | 0 | SSH server port inside the VM. A value of 0 means a random port. | SSH group |
| mounts | [] | Extra host directory mounts. Setting it to null disables mounts completely. | Mount group |
| diskImage | "" | Path to a custom VM disk image. | Advanced setting |
| env | {} | Environment variables injected into the VM. | Environment variable group |
The official docs effectively give Colima three configuration entry points. The first is colima start --edit, which edits the current instance configuration. The second is colima template, which edits the default template used by future instances. The third is environment variables such as COLIMA_HOME, COLIMA_PROFILE, and DOCKER_CONFIG, which change the config root, the active profile, and the Docker client config directory.
|
1 2 3 4 5 6 7 8 9 |
# Edit the current profile colima start --edit # Edit the default template colima template # Pick a specific editor colima start --edit --editor code colima template --editor code |
It also helps to remember the config file locations:
- Default profile: ~/.colima/default/colima.yaml
- Named profile: ~/.colima/<profile>/colima.yaml
- Default template: ~/.colima/_templates/default.yaml
The docs also call out four settings as immutable after instance creation: arch, runtime, vmType, and mountType. If you need to change any of them, restart is not enough. Delete the instance and recreate it with the new values.
Once the configuration is in place, start with the VM status:
|
1 |
colima status |
If network.address is enabled and jq is installed on the host, you can pull out the VM IP directly:
|
1 2 3 |
export COLIMA_VM_IP=$(colima status -j | jq -r .ip_address) echo "$COLIMA_VM_IP" ping "$COLIMA_VM_IP" |
Then verify both the Docker and Kubernetes control paths:
|
1 2 3 |
docker ps kubectl config get-contexts kubectl get nodes |
If you need to inspect the underlying VM directly, SSH into it:
|
1 |
colima ssh |
The official command reference has a clear shape. start handles creation and startup. Lifecycle commands handle stop, restart, and delete. Status and connection commands let you inspect and enter the VM. On top of that, Colima also exposes helper commands for Kubernetes, containerd, templates, upgrades, shell completion, and AI model runners.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# Start the default profile colima start # Start with Kubernetes enabled colima start --kubernetes # List all profiles colima list # Stop the current instance colima stop # Delete the current instance and its container data colima delete --data --force |
| Command | Typical form | Purpose |
| start | colima start [profile] | Creates or starts a profile. Most runtime and VM settings are applied here. |
| stop | colima stop [profile] | Stops an instance. |
| restart | colima restart [profile] | Restarts an instance. |
| delete | colima delete [profile] | Deletes an instance, with optional data removal. |
| status | colima status [profile] | Shows instance state, runtime, architecture, mount type, socket path, and related details. |
| list | colima list | Lists all profiles. |
| ssh | colima ssh [profile] -- command | Opens an SSH session or runs a single command inside the VM. |
| ssh-config | colima ssh-config [profile] | Prints the SSH configuration for the VM. |
| kubernetes start | colima kubernetes start [profile] | Enables Kubernetes on a running instance. |
| kubernetes stop | colima kubernetes stop [profile] | Stops Kubernetes. |
| kubernetes reset | colima kubernetes reset [profile] | Resets the built-in Kubernetes cluster. |
| model run | colima model run <model> | Runs an AI model. |
| model serve | colima model serve <model> | Serves an AI model through a web UI. |
| nerdctl | colima nerdctl -- <command> | Forwards nerdctl commands when the runtime is containerd. |
| nerdctl install | colima nerdctl install | Installs a standalone nerdctl binary for direct use. |
| template | colima template | Generates or edits the default configuration template. |
| update | colima update | Updates Colima itself. |
| prune | colima prune [profile] | Removes unused data to free disk space. |
| version | colima version | Prints version information. |
| completion | colima completion [shell] | Generates shell completion scripts. |
colima start is where most of the surface area lives. The official docs group its flags into nine categories: resources, runtime, VM, networking, mounts, Kubernetes, SSH, DNS, and configuration.
| Group | Flags | Description |
| Resources | --cpus, --memory, --disk, --root-disk | Sets CPU, memory, container data disk, and root disk size. |
| Runtime | --runtime, --activate | Selects the runtime and controls whether contexts are activated automatically. |
| VM | --arch, --vm-type, --cpu-type, --hostname, --disk-image, --vz-rosetta, --nested-virtualization, --binfmt, --foreground | Controls architecture, virtualization backend, CPU model, disk image, and foreground mode. |
| Networking | --network-address, --network-host-addresses, --network-mode, --network-interface, --network-preferred-route, --gateway-address, --port-forwarder | Controls reachable IPs, bridged mode, routing, gateway behavior, and port forwarding. |
| Mounts | --mount, --mount-type, --mount-inotify | Controls host directory mounts and file event propagation. |
| Kubernetes | --kubernetes, --kubernetes-version, --k3s-arg, --k3s-listen-port | Enables k3s, selects a version, and passes extra server arguments. |
| SSH | --ssh-agent, --ssh-config, --ssh-port | Controls SSH agent forwarding, host SSH config generation, and the SSH port. |
| DNS | --dns, --dns-host | Sets DNS resolvers and custom host mappings. |
| Configuration | --edit, --editor, --template, --save-config, --env | Controls config editing, editor choice, template use, persistence of flags, and VM environment variables. |
| Command | Flags | Meaning |
| delete | --data, --force | --data removes images, volumes, and related data. --force skips confirmation. |
| list | --json | Outputs the profile list as JSON. |
| ssh | -- command | Runs a single command in the VM instead of opening an interactive shell. |
| model run / serve | --profile, --runner, --port | Selects the profile, the model runner backend, and the web UI port for serve. |
| completion | bash, zsh, fish, powershell | Generates completion scripts for the selected shell. |
If a creation-time setting such as architecture, runtime, VM type, or mount driver does not change after a restart, that usually means nothing is wrong with the syntax. Those settings belong to instance creation, so the fix is to delete the instance and recreate it.
A large share of "Cannot connect to the Docker daemon" errors have nothing to do with Colima failing to start. The local docker CLI is often still attached to a different context. Check docker context ls first, then switch to colima if needed.
With the Docker runtime, images built or pulled inside one Colima instance are directly visible to Kubernetes in that same instance. That is one of the nicer parts of the setup because local builds do not need to be pushed to a remote registry just to test them. If you switch to the containerd runtime, the image workflow changes with it, and debugging should follow containerd namespaces rather than Docker assumptions.
network.address: true makes the VM reachable from the host, which is useful for debugging, but it should not become a substitute for normal service exposure. Application traffic should still use container port publishing with -p HOST:CONTAINER, or the usual Kubernetes Service and Ingress paths.
Leave a Reply