Skip to content

How Apple container Runs Linux Containers: Per-Container VM Architecture Explained

Problem

I had been using Docker Desktop on my Mac for years. It works, but I always wondered: how does it actually run Linux containers on macOS? The answer is a shared Linux VM. Every container runs inside that single VM, sharing one kernel.

This works, but it has a fundamental trade-off: isolation is at the namespace level, not the VM level. A container escape in one container could theoretically affect others in the same VM.

Apple container takes a different approach entirely.

Diagram comparing Docker Desktop's shared-VM architecture (one VM hosting all containers) with Apple container's per-container-VM architecture (each container gets its own dedicated VM)

The Architecture Overview

When I run container system start, here is what happens:

┌──────────────┐ ┌──────────────────────────────────────┐
│ CLI/Client │────→│ container-apiserver │
│ (container) │ │ (launchd-managed launch agent) │
└──────────────┘ └───┬──────────┬────────────┬─────────┘
│ │ │
▼ ▼ ▼
┌────────────┐ ┌──────────┐ ┌────────────────┐
│core-images │ │network- │ │runtime-linux │
│(XPC helper)│ │vmnet │ │(XPC helper) │
│Image store │ │(vmnet │ │Per-container VM│
│management │ │framework)│ │lifecycle │
└────────────┘ └──────────┘ └────────────────┘
  1. The CLI (container) sends commands to container-apiserver, a launch agent managed by launchd
  2. The apiserver starts XPC helpers on boot:
    • container-core-images: manages the local OCI image store
    • container-network-vmnet: handles virtual networking via vmnet.framework
  3. Each container run creates a new container-runtime-linux XPC helper that manages a dedicated VM

Per-Container VM vs Shared VM

The fundamental difference:

AspectDocker Desktop (Shared VM)Apple container (Per-Container VM)
VMs running1 VM for all containers1 VM per container
IsolationNamespace-levelVM-level (hardware backed)
Kernel sharingAll containers share one Linux kernelEach container gets its own kernel
Container escape riskOne escape affects all containersEscaped container is contained in its VM
Startup timeFast (container just starts as process)Comparable (optimized VM boot)
Resource overheadOne VM’s base overhead + containersPer-VM overhead, but lightweight

How the VM Boots So Fast

Each container runs a minimal Linux kernel with a small init system. The vminitd process handles early boot and then launches the OCI container’s process as PID 1.

The boot sequence for each container is:

Container boot sequence
1. container-apiserver receives container run request
2. Spawns container-runtime-linux XPC helper
3. Helper creates a VM via Virtualization.framework
4. VM boots minimal Linux kernel (optimized config)
5. vminitd starts as PID 1
6. vminitd launches the container's OCI entrypoint
7. Container process is running

This whole sequence completes in seconds, comparable to starting a container in a shared-VM setup.

macOS Framework Integration

Apple container is deeply integrated with native macOS frameworks:

  • Virtualization.framework: creates and manages Linux VMs
  • vmnet.framework: configures virtual network interfaces
  • XPC: inter-process communication between the apiserver and its helpers
  • launchd: manages the apiserver lifecycle (starts on demand, restarts on crash)
  • Keychain: securely stores registry credentials
  • Unified Logging: system-level logs for debugging

This native integration is a key advantage over cross-platform tools that run their own Linux VM with their own service management.

Why This Architecture Matters

The per-container VM design addresses real pain points:

  1. Security: A vulnerability in one container’s runtime cannot compromise another container. Each is isolated at the VM level.
  2. Privacy: When mounting data, only the target VM sees it. No need to mount everything into a shared VM.
  3. Performance: VMs are intentionally minimal — no unnecessary kernel modules, no extra services. Boot times stay fast.
  4. Resource control: Each VM manages its own CPU and memory allocation independently.

Summary

In this post, I explained how Apple container’s architecture differs from traditional shared-VM approaches. The key point is that by giving each container its own lightweight VM backed by macOS Virtualization.framework, Apple container provides VM-level isolation with container-level startup speed.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments