Skip to content

Build1 publisher3 min readPublished

Apple's macOS 26 container runtime boots a separate VM for every container

Apple Container on macOS 26 boots a lightweight VM for each container, where Podman runs them all in one shared Fedora VM. Leaving Podman gets each container its own kernel boundary and moves the VM boot cost onto every run.

The Engineer · Build desk

Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

Illustration accompanying Apple's macOS 26 container runtime boots a separate VM for every container
Generated illustration

What happened

  • Apple's runtime is driven by a launchd service, com.apple.container.apiserver, and builds its VMs with Virtualization.framework.
  • Apple's container inspect reports each container's own hardware allocation, 4 CPUs and 1,073,741,824 bytes of memory in the post's sample.
  • Apple's CLI follows Docker and Podman conventions and adds a --rosetta flag for running amd64 images on Apple Silicon.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • cost Each extra container now brings its own VM boot and memory allocation. On Podman that boot happens once, when the machine starts.
  • exposure A kernel-level compromise in one container would have to cross a VM boundary to reach another, where Podman Machine puts every container on one shared guest kernel.
  • constraint Scripts and dashboards that parse Docker-style inspect fields such as State.Status or NetworkSettings have to be rewritten before Apple's runtime can replace Podman underneath them.

A `container run -d --name web nginx` goes to the com.apple.container.apiserver daemon, which `container system start` brings up under launchd [1][5]. The run boots a dedicated VM through Virtualization.framework and starts nginx inside it [5]. The post reports the guest kernel as a Kata Containers build, version 3.32.0-debug [2].

Podman on a Mac splits the work differently. It runs daemonless on the host, and `podman machine start` boots one Fedora VM [3][5]. Each `podman run` after that forks a process inside that VM through conmon and crun or runc [3][5]. Podman pays for a VM boot once per machine start. Apple Container pays for one on every run [2].

The boot buys isolation. The post contrasts hardware-enforced per-container VM boundaries with Podman's shared Linux namespace architecture [15]. Under Podman Machine, every container on the laptop sits on one guest kernel [3]. Under Apple Container, each container has its own [2].

Memory splits the same way. In the post's sample, `container inspect` reports 4 CPUs and a memoryInBytes of 1073741824 for one container [8]. That is exactly 1 GiB [1]. A five-container stack at that allocation comes to 5 GiB of allocated guest memory [3]. Podman's sample shows Memory and NanoCpus as 0 under HostConfig [9]. Its containers all draw on the one machine VM [3].

The post's container-compare tool sets out to measure execution timing and memory overhead on both runtimes [16]. It drives each CLI through a Go wrapper and collects timing statistics alongside inspect-schema data [4]. The wrapper is well built. User strings are checked against allowlists, and arguments reach exec.Command as a []string with no shell in between [13]. The material supplied does not include the measured results. Any number the tool produces describes Apple Container v1.3.1, released 2026-08-29, running a guest kernel tagged debug [11][2]. For that number to carry over to another team, its images, container count and macOS version would need to match. I'd expect the per-run boot to cost most in test suites that start many short-lived containers. It should cost least in a dev stack left up all day.

The CLI maps closely to Docker and Podman conventions [5]. The inspect JSON uses a different schema. Apple's puts status, networks and configuration at the top level. Podman's follows the OCI/Docker-compatible layout, with status under State and networking under NetworkSettings [8][9]. A script that reads `.State.Status` will find out on its first run.

Networking moves too. The sample Apple container gets 192.168.64.3/24 behind gateway 192.168.64.1, with the hostname my-container.test., bridged through vmnet [10]. Podman's sample container sits at 10.88.0.2 on its podman network [9]. Full network isolation needs macOS 26 [12]. Apple's CLI also adds `--rosetta` for running amd64 images on Apple Silicon and `container logs --boot` for reading a VM's boot log [6][7]. According to the post's author, Podman Desktop handles both engines [14]. A team can run the side-by-side test from one tool before it uninstalls anything.

What to watch

  • The container-compare timing and memory results for Apple Container v1.3.1, and whether they were taken on the 3.32.0-debug guest kernel.
  • Whether a later Apple Container release ships a guest kernel without the debug tag or changes the per-container allocation that inspect reports.
  • Whether Apple's inspect output gains a Docker-compatible mode that lets existing tooling read State and NetworkSettings unchanged.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories