macOS guests and containers¶
Two questions come up often: can a macOS guest be "containerized", and can a guest run containers or devcontainers. The short answers are no and yes. Both follow from how Apple silicon virtualization works, not from a RhubarbTart choice.
| Question | Answer |
|---|---|
Run a macOS guest as an OS-level container (shared kernel, docker run) |
No. macOS runs only as a full VM. |
| Package and distribute a macOS guest like a container image | Yes. Images are OCI artifacts, signed and pushed to a registry. |
| Spin up cheap, throwaway copies of a guest | Yes. Clones are copy-on-write and disposable. |
| Run Linux containers or devcontainers inside a Linux guest | Yes, on any Apple silicon. |
| Run containers inside a macOS guest | Only on an M3 or newer host (needs nested virtualization). |
Why a macOS guest is a VM, not a container¶
A container shares the host's kernel and isolates a process tree. macOS has no such mode: Apple runs macOS only as a full virtual machine, through Virtualization.framework, on Apple hardware. Tart (which RhubarbTart builds on) uses that framework, so every macOS guest is a complete OS with its own kernel, booted as a VM.
There is no macOS container runtime, and there is no shared-kernel "macOS container". Tools that
claim to "run macOS in a container" run a QEMU VM inside a Linux container on non-Apple hardware,
which is a different thing and is outside Apple's licence for macOS. Apple's own
container tool (introduced with macOS 26) runs Linux containers on a Mac; it does not make
macOS itself a container.
So when people ask to "containerize" a macOS guest, the useful parts of what they want, a small distributable artifact and cheap throwaway instances, are things RhubarbTart already provides in the two sections below. The one thing that is not possible is a shared-kernel macOS container.
What "containerized" does mean here¶
Images are OCI artifacts (packaged and signed like container images)¶
Tart can push a VM image to any OCI registry as an OCI artifact,
the same object format a container registry holds, and pull it back. A macOS image is therefore
distributed like a container image: a content-addressed artifact you can host,
mirror, and pull by name. It is booted as a VM rather than docker run, but the packaging and
supply chain are the container-registry ones.
RhubarbTart wraps this so the supply chain is verifiable:
scripts/publish.sh publishpushes a smoke-passed image to a registry (a local zot by default), then signs it and its provenance record with cosign, offline.scripts/publish.sh verify(and, for macOS,rhubarbtart new --from-registry) checks that signature before use.
See Publishing and stacked clones for the full flow.
Clones are cheap, disposable instances¶
You never boot the sealed image. rhubarbtart new makes an APFS clone: a copy-on-write copy that
is near-instant and takes almost no extra disk until it is written to. You work in the clone and
delete it when done, and rhubarbtart reset swaps in a fresh one from the image.
This is the container-like part: fast to create, isolated and throwaway, but for full VMs. It is how RhubarbTart keeps the "spin up, use, discard" model for macOS guests without any container runtime. See Key concepts (clone) and Using your VMs.
Running containers inside a guest¶
A different question: not containerizing the guest, but running containers (including devcontainers) inside one. This depends on where the container's kernel comes from.
Linux guests: native, on any Apple silicon¶
A Linux container needs a Linux kernel, and a Linux guest already has one. With a runtime
(docker, podman) in a Linux guest, containers run directly on that guest's kernel, with no
extra virtualization. This works on any Apple silicon Mac, including M1 and M2.
This is the natural home for devcontainers in RhubarbTart: the container runs inside a hardened,
provenance-pinned, disposable Linux clone. The package catalog has no container runtime today. To
add one, create a catalog entry in config/packages/ with a kali (distro) or nixos (nix)
variant, list it in a Linux profile, and rebuild (see Define your own guest). On
NixOS, Docker and Podman are enabled through virtualisation.* options, which the package mapping
in guest/nixos/nix/modules/packages.nix does not cover yet, so that part is a build-code change.
macOS guests: only with nested virtualization (M3 or newer)¶
A macOS guest has an XNU kernel, not a Linux one, so any Linux container engine on macOS (Docker
Desktop, Colima, or Apple's container tool) first starts a lightweight Linux VM to hold the
containers. Starting a VM inside a VM is nested virtualization, which Apple silicon supports
only on M3 and newer chips (and the host must expose it).
Consequences:
- On an M1 or M2 host, containers cannot run inside a macOS guest at all, because nested
virtualization is unavailable. Check with
sysctl hw.optional.arm.FEAT_NV(absent or0means no nested virtualization). - On an M3 or newer host it is possible. Tart exposes the switch as
tart run --nested("enable nested virtualization if possible"). Two things are still needed: rhubarbtart rundoes not pass--nestedtoday, so a profile option to request it would have to be added and recorded in the clone's lineage.- A container runtime must be in the macOS image, which means a new catalog entry. Apple's
containertool (macOS 26+) is open source and has no Docker Desktop subscription terms.