How Apple Container Runtime Works on Apple Silicon: Architecture and Implementation
Apple's container runtime executes Linux containers inside lightweight, hardware-accelerated virtual machines using the macOS Virtualization framework, orchestrated by the RuntimeService actor via secure XPC service calls.
The apple/container repository provides Apple's open-source container runtime, which leverages Apple Silicon's hardware-assisted virtualization capabilities to run Linux workloads. Unlike traditional container engines that share the host kernel, this runtime boots a full Linux VM for each container, providing enhanced isolation while maintaining near-native performance through the Virtualization framework. The architecture centers on the RuntimeService actor, which manages the entire lifecycle from VM creation to process execution.
Core Architecture
Virtualization Framework Integration
At the foundation of the Apple container runtime is the VZVirtualMachineManager from the macOS Virtualization framework. According to the source code in Sources/Services/RuntimeLinux/Server/RuntimeService.swift, the runtime instantiates this manager to boot a Linux kernel and mount the container's root filesystem. This approach provides hardware-accelerated virtualization on Apple Silicon, utilizing the M-series CPU's virtualization extensions (KVM) to run the guest Linux environment.
XPC Service Layer
The runtime operates as an XPC service named container-runtime-linux, launched by the container-apiserver launch agent. As implemented in Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift, the service registers a Mach service (com.apple.container.runtime.<runtime>.<id>) to enable secure, sandboxed inter-process communication between the container CLI and the runtime backend. This design isolates the VM management logic from the user-facing CLI, improving security and stability.
RuntimeService Actor
The RuntimeService actor serves as the heart of the runtime. Located in Sources/Services/RuntimeLinux/Server/RuntimeService.swift, this Swift actor handles critical XPC routes including createEndpoint, start, stop, state, and statistics. The bootstrap method (lines 31-53) performs the following sequence:
- Verifies the bundle exists or creates it.
- Reads the kernel and initial filesystem configuration.
- Instantiates
VZVirtualMachineManagerwith the specified resources. - Uses
lock.withLockto enforce atomic state transitions from created to booting. - Allocates network attachments via
ContainerNetworkClient. - Registers the XPC endpoint and starts the VM.
Networking and Persistence
Network connectivity is established through the ContainerNetworkClient, which obtains a virtual network attachment from the container-network-vmnet helper and wires it to the host's vmnet framework. This creates a virtual NIC inside the guest VM.
Configuration persistence is handled by ContainerPersistence and defined in Sources/Services/Runtime/RuntimeClient/RuntimeConfiguration.swift. The runtime stores VM settings—including kernel path, memory allocation, CPU count, and filesystem location—in a runtime-configuration.json file, enabling state recovery across service restarts.
Apple Silicon Requirements
Hardware Prerequisites
Running the Apple container runtime with full virtualization features requires Apple Silicon M3 or later with macOS 15 or later. According to docs/container-machine.md (line 79), these requirements are mandatory for nested virtualization support, which allows the guest Linux VM to run its own KVM workloads.
Nested Virtualization Implementation
When the user specifies the --virtualization flag (documented in docs/command-reference.md, lines 1087-1221), the runtime performs additional setup:
- Passes the KVM device (
/dev/kvm) into the guest VM. - Sets kernel command-line arguments to enable KVM (
"oops=panic"and"lsm=lockdown,capability,landlock,yama,apparmor"). - Verifies the host kernel supports KVM before exposing the device.
The guest kernel must be compiled with CONFIG_KVM=y. The default runtime kernel does not include this configuration, so users must supply a custom kernel path via the --kernel flag.
Rosetta Configuration
On Apple Silicon, the runtime respects Rosetta settings for x86_64 binary translation. Users can disable Rosetta for builds by modifying ~/.config/container/config.toml, as noted in docs/how-to.md (line 676). This allows native ARM64 execution without translation overhead.
Container Lifecycle Flow
Bootstrap Sequence
The lifecycle begins when the user executes container machine create or similar commands:
- CLI → XPC: The
containerCLI initializes aRuntimeClientand connects to the Mach service. - Bundle Creation:
RuntimeService.bootstrapchecks for the existence of the bundle at the configured path and creates it if necessary. - VM Instantiation: The service reads
runtime-configuration.jsonand initializesVZVirtualMachineManagerwith the specified kernel and root filesystem. - Network Setup:
ContainerNetworkClientacquires a network attachment from the vmnet helper. - Initialization: The VM boots, and the service registers the XPC endpoint for receiving further commands.
Process Execution
To run a command inside the container, the CLI sends a createProcess XPC request. RuntimeService creates a ProcessInfo record, spawns the process inside the running VM, and returns a PID to the caller. This mechanism allows the host CLI to interact with processes running inside the isolated Linux environment.
Shutdown
The shutdown method in RuntimeService handles teardown by stopping the VM, releasing network resources, and cleaning up temporary files. This ensures proper resource deallocation and prevents orphaned virtual machines.
Code Examples
Swift Client Implementation
The following Swift code demonstrates creating a RuntimeClient and establishing communication with the runtime service:
import ContainerXPC
import ContainerRuntimeClient
let client = try await RuntimeClient.create(
id: "myContainer", // Unique container ID
runtime: "linux-sandboxd" // Runtime name used in Mach service label
)
// Ask the runtime service to create an XPC endpoint
let endpointMessage = XPCMessage()
let reply = try await client.createEndpoint(endpointMessage)
let endpoint = reply.get(key: RuntimeKeys.runtimeServiceEndpoint.rawValue)
// Now you can send further commands (e.g., start a process) over this endpoint.
This mirrors the logic in RuntimeClient.create and RuntimeService.createEndpoint.
CLI with Nested Virtualization
To create a container machine with KVM support on Apple Silicon M3 or later:
# Create a container machine with KVM support
container machine create \
--virtualization \
--kernel /path/to/vmlinux-kvm \
--name kvm-dev \
alpine:latest
# Verify that /dev/kvm is present inside the VM
container machine run -n kvm-dev -- ls -l /dev/kvm
Documentation source: docs/container-machine.md.
Runtime Configuration File
The runtime persists settings in runtime-configuration.json:
{
"path": "/var/containers/myContainer",
"initialFilesystem": "/var/containers/myContainer/rootfs",
"kernel": "/path/to/vmlinux-kvm",
"containerConfiguration": { "rosetta": false, "ssh": true },
"runtimeData": null
}
This file is read by RuntimeConfiguration.readRuntimeConfiguration and written by writeRuntimeConfiguration in Sources/Services/Runtime/RuntimeClient/RuntimeConfiguration.swift.
Summary
- Apple container runtime runs each container inside a dedicated Linux VM using the macOS Virtualization framework and
VZVirtualMachineManager. - Communication occurs via the
container-runtime-linuxXPC service, with theRuntimeServiceactor managing VM lifecycle, networking, and process execution. - Apple Silicon M3 or later with macOS 15+ is required for nested virtualization, which passes
/dev/kvminto the guest when using the--virtualizationflag. - Configuration persists in
runtime-configuration.json, while network attachments are managed throughContainerNetworkClientand thevmnetframework. - The
bootstrapmethod inRuntimeService.swift(lines 31-53) orchestrates VM creation, state transitions, and endpoint registration.
Frequently Asked Questions
What hardware is required to run Apple's container runtime with nested virtualization?
Nested virtualization requires Apple Silicon M3 or later running macOS 15 or later. These specifications ensure the host supports the Virtualization framework features necessary for passing the KVM device (/dev/kvm) into the guest VM. The guest kernel must also be compiled with CONFIG_KVM=y.
How does the container CLI communicate with the runtime service?
The CLI communicates through XPC (Inter-Process Communication). The RuntimeClient class in Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift constructs a Mach service label (com.apple.container.runtime.<runtime>.<id>) and sends messages to the container-runtime-linux XPC service. The RuntimeService actor receives these calls and manages the VM accordingly.
Where does the runtime store VM configuration and state?
Configuration is stored in runtime-configuration.json within the container bundle. The ContainerPersistence class and RuntimeConfiguration struct in Sources/Services/Runtime/RuntimeClient/RuntimeConfiguration.swift handle reading and writing this file, preserving settings such as kernel path, memory limits, CPU count, and filesystem locations across restarts.
Can I disable Rosetta translation for builds on Apple Silicon?
Yes. You can disable Rosetta translation by setting the appropriate option in ~/.config/container/config.toml, as documented in docs/how-to.md (line 676). This forces the runtime to use native ARM64 execution paths instead of x86_64 emulation, potentially improving build performance for native Apple Silicon workloads.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →