How Apple's Container Runtime Uses the Virtualization Framework: A Deep Dive into the Implementation
Apple's container runtime creates a lightweight macOS-hosted virtual machine for each Linux container using the Virtualization framework (VZVirtualMachineManager) and the vmnet subsystem, providing hardware-accelerated isolation with native networking support.
The apple/container repository implements a Linux container runtime that leverages macOS native virtualization capabilities. Unlike traditional container runtimes that rely on shared kernel architectures, this implementation uses the Virtualization framework to spawn isolated virtual machines for each container, ensuring secure sandboxing while maintaining performance through hardware acceleration. The runtime is defined in Package.swift with a direct dependency on Apple's Virtualization framework.
VM Construction with VZVirtualMachineManager
In Sources/Services/RuntimeLinux/Server/RuntimeService.swift, the runtime instantiates a VZVirtualMachineManager to manage the VM lifecycle. This manager abstracts the low-level VZVirtualMachine object and provides a Swift-friendly API for booting, stopping, and pausing containers.
The manager is initialized with the container's kernel image, root filesystem, optional Rosetta support for x86_64 translation, and a logger:
let vmm = VZVirtualMachineManager(
kernel: kernel,
initialFilesystem: bundle.initialFilesystem.asMount,
rosetta: config.rosetta,
logger: self.log
)
This setup ensures that each container runs inside its own hardware-accelerated VM rather than sharing the host kernel.
Linux Container Configuration
The LinuxContainer class receives the VZVirtualMachineManager instance and a configuration struct defining CPU, memory, sysctls, mounts, and network interfaces. In RuntimeService.swift, the runtime configures these parameters before launching the container:
let container = try LinuxContainer(id, rootfs: rootfs, vmm: vmm, logger: self.log) { czConfig in
try Self.configureContainer(czConfig: &czConfig, config: config, dynamicEnv: dynamicEnv, log: self.log)
czConfig.interfaces = interfaces
// Additional configuration...
}
This architecture binds the container's processes to the specific VM instance created by the Virtualization framework.
Network Interface Strategies
The runtime supports two distinct networking models through the Virtualization framework, implemented in separate strategy files.
Non-Isolated Interfaces with vmnet
For macOS 26+ custom networks, Sources/Services/RuntimeLinux/Server/NonisolatedInterfaceStrategy.swift imports both Virtualization and vmnet frameworks. It deserializes a vmnet network reference using vmnet_network_create_with_serialization and attaches it to the VM:
import Virtualization
import vmnet
guard let networkRef = vmnet_network_create_with_serialization(
additionalData.underlying,
&status
) else {
throw ContainerizationError(.invalidState, message: "cannot deserialize custom network")
}
let iface = NATNetworkInterface(
ipv4Address: attachment.ipv4Address,
ipv4Gateway: ifaceIdx == 0 ? attachment.ipv4Gateway : nil,
reference: networkRef,
macAddress: attachment.macAddress,
mtu: attachment.mtu ?? 1280
)
Isolated NAT Interfaces
The default isolated strategy creates a VZBridgedNetworkDevice or VZNetworkDevice backed by the system's NAT stack, providing network isolation without requiring custom network plugins.
Filesystem Integration and Caching
When mounting block devices or volumes, the Filesystem class in Sources/ContainerResource/Container/Filesystem.swift defaults the cache mode to .on to address a known Linux filesystem bug when running under Virtualization:
public static func block(
format: String,
source: String,
destination: String,
options: MountOptions,
cache: CacheMode = .on, // default fixes Linux FS issue when using Virtualization
sync: SyncMode = .fsync
) -> Filesystem {
// Implementation...
}
This direct interaction with the Virtualization-backed storage stack ensures data consistency.
Summary
- VM per container: Each Linux container runs in its own isolated virtual machine created via
VZVirtualMachineManager - Hardware acceleration: The Virtualization framework provides native CPU, memory, and storage virtualization with minimal overhead
- Flexible networking: Supports both non-isolated custom networks (via vmnet) and isolated NAT interfaces
- Storage optimization: Default filesystem caching works around Linux-in-Virtualization bugs
- Lifecycle management: All VM operations (boot, shutdown, snapshots) are mediated through the manager abstraction
Frequently Asked Questions
Does each container run in its own VM?
Yes. According to the apple/container source code, the runtime creates a dedicated VZVirtualMachine for each container through the VZVirtualMachineManager abstraction. This provides true hardware-level isolation rather than the process-level isolation found in traditional Linux containers.
What macOS version is required for custom network plugins?
Non-isolated network interfaces using vmnet_network_create_with_serialization require macOS 26 (or later) and the custom network plugin infrastructure. This allows containers to integrate with existing network topologies while maintaining VM-level isolation.
How does the runtime handle x86_64 containers on Apple Silicon?
The runtime supports optional Rosetta translation when configuring the VM. The VZVirtualMachineManager accepts a rosetta parameter during initialization, enabling x86_64 Linux binaries to run inside the Virtualization framework-backed VM on Apple Silicon Macs.
Why is filesystem caching set to "on" by default?
When running Linux under the Virtualization framework, certain filesystem operations exhibit specific behaviors that require aggressive caching. The Filesystem.swift implementation defaults to CacheMode.on to work around these Linux-in-Virtualization bugs, ensuring stable block device and volume mounts.
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 →