How Container Uses Apple's Virtualization Framework to Run Linux Containers
Container creates a lightweight macOS-hosted virtual machine for each Linux container using Apple's Virtualization framework (VZVirtualMachineManager) and the vmnet subsystem to provide hardware-accelerated isolation with native networking.
The apple/container repository implements a runtime that leverages macOS-native virtualization to execute Linux containers in secure, sandboxed environments. By utilizing the Virtualization framework available on Apple Silicon and Intel Macs, Container eliminates the need for traditional hypervisors while providing near-native performance for Linux workloads.
VM Construction and Lifecycle Management
Container orchestrates virtual machine creation through a dedicated manager wrapper that abstracts the low-level VZVirtualMachine object. In Sources/Services/RuntimeLinux/Server/RuntimeService.swift, the bootstrap method instantiates a VZVirtualMachineManager with the container's kernel image, initial root filesystem, and optional Rosetta support.
let vmm = VZVirtualMachineManager(
kernel: kernel,
initialFilesystem: bundle.initialFilesystem.asMount,
rosetta: config.rosetta,
logger: self.log
)
This manager handles the complete VM lifecycle—including start, stop, and pause operations—while exposing a Swift-friendly API that integrates with the container runtime. The abstraction ensures that container processes run inside the VM rather than directly on the host macOS kernel.
Linux Container Configuration
The LinuxContainer class receives the VZVirtualMachineManager instance and a configuration struct describing CPU count, memory limits, sysctls, mounts, and sockets. This configuration occurs in RuntimeService.swift when constructing the container instance:
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
// ...
}
The LinuxContainer.Configuration struct bridges the Virtualization framework's capabilities with container-specific requirements, allowing each sandboxed Linux environment to maintain its own isolated process tree and resource limits.
Networking with vmnet and Virtualization
Container implements two network strategies using the Virtualization framework and the vmnet subsystem to provide connectivity for Linux containers.
Non-Isolated Network Interfaces
In Sources/Services/RuntimeLinux/Server/NonisolatedInterfaceStrategy.swift, Container supports custom network plugins available on macOS 26+. The strategy deserializes a vmnet network reference using vmnet_network_create_with_serialization and attaches it to the VM as a NATNetworkInterface:
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
)
This approach allows the Linux container to see a familiar Ethernet interface while the host manages the actual network topology through the vmnet framework.
Isolated Network Interfaces
For default NAT configurations, Container uses isolated interface strategies that create VZBridgedNetworkDevice or VZNetworkDevice instances backed by the system's NAT stack. This provides automatic network isolation without requiring custom network plugin configuration.
Storage and Filesystem Caching
When mounting block devices or volumes, Container interacts directly with the Virtualization-backed storage stack. In Sources/ContainerResource/Container/Filesystem.swift, the code defaults the cache mode to .on to work around a specific Linux-in-Virtualization framework bug:
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 {
// ...
}
This cache configuration ensures data consistency when the Linux guest kernel accesses virtualized storage devices through the Virtualization framework.
Summary
- VM Abstraction: Container uses
VZVirtualMachineManagerdefined inRuntimeService.swiftto wrap Apple'sVZVirtualMachineand manage container lifecycles. - Hardware Acceleration: Each Linux container runs in its own lightweight VM using the Virtualization framework for CPU, memory, and storage virtualization with minimal overhead.
- Native Networking: The
vmnetsubsystem andNonisolatedInterfaceStrategyprovide Ethernet interfaces to containers viaNATNetworkInterfaceor bridged devices. - Storage Workarounds: Default cache mode
.oninFilesystem.swiftaddresses Linux filesystem compatibility issues when running under Apple's virtualization. - Dependency Declaration: The project declares its Virtualization framework dependency in
Package.swiftto ensure proper linking against macOS system frameworks.
Frequently Asked Questions
What is VZVirtualMachineManager in Container?
VZVirtualMachineManager is a Swift wrapper class in the Container project that abstracts Apple's VZVirtualMachine APIs. It handles VM lifecycle operations including boot, shutdown, and snapshot management while providing a logger interface for debugging. The manager is instantiated in RuntimeService.swift with kernel images and filesystem mounts before being passed to LinuxContainer instances.
How does Container handle networking for Linux VMs?
Container supports two network models through the Virtualization framework. Non-isolated interfaces use vmnet_network_create_with_serialization to attach custom networks from plugins, creating NATNetworkInterface instances. Isolated interfaces use standard VZBridgedNetworkDevice or VZNetworkDevice configurations with the host's NAT stack. Both approaches provide Ethernet interfaces to the Linux guest while maintaining network isolation.
Why does Container use a specific cache mode for filesystems?
Container defaults to CacheMode.on in Filesystem.swift to work around a known bug where Linux filesystems running under Apple's Virtualization framework experience consistency issues with default caching. This explicit cache configuration ensures that block device mounts and volume mounts maintain data integrity between the macOS host and Linux guest.
Is each Linux container isolated in its own VM?
Yes. According to the architecture implemented in RuntimeService.swift and LinuxContainer.swift, Container creates a separate lightweight virtual machine for each Linux container using the Virtualization framework. This design provides secure isolation through macOS's hypervisor, ensuring that container processes cannot affect the host system or other containers, while reusing macOS kernel features for hardware acceleration.
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 →