# How the Apple Container Tool Leverages the Virtualization Framework on Apple Silicon

> Discover how the Apple container tool uses the Virtualization framework on Apple Silicon to run Linux VMs with hardware isolation and low overhead via nested virtualization and memory ballooning.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: internals
- Published: 2026-07-12

---

**The Apple container tool uses the macOS Virtualization framework to run each container in its own lightweight Linux VM, providing hardware-isolated workloads with low overhead through nested virtualization and memory ballooning on Apple Silicon.**

The `container` command-line tool in the [apple/container](https://github.com/apple/container) repository abstracts Apple's low-level Virtualization framework into a high-level container API. By running OCI-compatible containers inside individual Linux VMs, the tool delivers strong isolation comparable to full virtualization while maintaining the startup speed and memory efficiency expected of modern container runtimes. This architecture is specifically optimized for Apple Silicon, leveraging hardware-accelerated nested virtualization and dynamic memory management.

## VM Creation and the LinuxContainer Abstraction

When a container starts, the tool constructs a `VZVirtualMachineManager` instance configured with a Linux kernel, initial filesystem, and optional Rosetta support. In [`Sources/Services/RuntimeLinux/Server/RuntimeService.swift`](https://github.com/apple/container/blob/main/Sources/Services/RuntimeLinux/Server/RuntimeService.swift) (lines 165-170), the manager is instantiated and immediately passed to the `LinuxContainer` abstraction, which applies container-specific configuration including network interfaces and process I/O streams.

The `LinuxContainer` wrapper translates high-level container operations into low-level Virtualization framework calls. It mounts the container's root filesystem using virtual block device APIs and binds the VM's network stack to the macOS `vmnet` framework, enabling seamless container-to-host and container-to-container communication.

## Nested Virtualization Requirements

Apple Silicon devices require specific hardware and software capabilities to support containerized workloads. Before creating any VM, the tool executes a pre-flight check in [`Sources/ContainerCommands/Machine/MachineCapabilities.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Machine/MachineCapabilities.swift) (lines 22-30) that queries `VZGenericPlatformConfiguration.isNestedVirtualizationSupported`.

**Nested virtualization**—the ability to run a VM inside another VM—is mandatory for the container tool's architecture. This feature requires Apple Silicon M3 or later running macOS 15 or newer. If the host fails this check, the tool throws an informative error and prevents VM creation, ensuring users receive clear hardware compatibility feedback.

## Memory Ballooning and Device Integration

The Virtualization framework provides a partial memory-ballooning implementation that the container tool leverages for efficient resource utilization. According to [`docs/technical-overview.md`](https://github.com/apple/container/blob/main/docs/technical-overview.md) (line 36), the VM's memory consumption tracks the container's active memory usage rather than static allocation limits, significantly reducing the host footprint for idle containers.

For storage and networking, the tool utilizes the framework's device attachment APIs. Virtual block devices mount the container's root filesystem through `VZVirtualMachineManager`, while network interfaces bridge to the host's `vmnet` stack. This integration allows the Linux VM to operate with near-native performance while remaining fully isolated from the host kernel.

## Lifecycle Management via XPC

All VM lifecycle operations—create, start, stop, and cleanup—are orchestrated by the `container-apiserver` daemon. The daemon receives XPC requests from the CLI and forwards them to a runtime helper process. This helper directly manipulates the underlying `VZVirtualMachine` objects, ensuring that privileged virtualization operations occur in a controlled, sandboxed context separate from the user's shell.

## Implementation Example

The following Swift snippets illustrate the core steps performed when launching a container, corresponding to the production code in [`RuntimeService.swift`](https://github.com/apple/container/blob/main/RuntimeService.swift):

```swift
import Virtualization
import ContainerizationError

// Verify the host supports nested virtualization (Apple Silicon M3+ / macOS 15+)
do {
    try MachineCapabilities.requireNestedVirtualizationSupported()
} catch {
    print("This Mac cannot run container VMs: \(error)")
}

// Initialize the VM manager with Linux kernel and root filesystem
let vmm = VZVirtualMachineManager(
    kernel: linuxKernel,
    initialFilesystem: rootFS.asMount,
    rosetta: config.rosetta,
    logger: logger
)

// Create the LinuxContainer wrapper with network and I/O configuration
let linuxContainer = try LinuxContainer(
    id,
    rootfs: rootFS.asMount,
    vmm: vmm,
    logger: logger
) { czConfig in
    czConfig.interfaces = netInterfaces
    czConfig.process.stdout = stdoutWriter
    czConfig.process.stdin = stdinHandle
}

```

This sequence demonstrates how the tool bridges the Virtualization framework's low-level primitives with container-specific runtime configuration.

## Summary

- The `container` tool runs each container in a dedicated Linux VM using `VZVirtualMachineManager` for hardware-level isolation on Apple Silicon.
- **Nested virtualization** is mandatory and requires Apple Silicon M3 or later with macOS 15+, validated via [`MachineCapabilities.swift`](https://github.com/apple/container/blob/main/MachineCapabilities.swift).
- Memory usage is optimized through the Virtualization framework's partial **memory-ballooning**, tracking active rather than allocated memory.
- The `LinuxContainer` abstraction in [`RuntimeService.swift`](https://github.com/apple/container/blob/main/RuntimeService.swift) translates container configuration into VM setup, including network bridging via `vmnet`.
- Lifecycle operations are managed by `container-apiserver` through XPC communication with the runtime helper.

## Frequently Asked Questions

### What hardware is required to run the Apple container tool?

The tool requires Apple Silicon M3 or later running macOS 15 or newer. This hardware baseline is necessary to support nested virtualization, which allows the tool to run Linux VMs inside the host virtualization layer. Older Apple Silicon chips or Intel Macs cannot satisfy the `VZGenericPlatformConfiguration.isNestedVirtualizationSupported` check performed in [`MachineCapabilities.swift`](https://github.com/apple/container/blob/main/MachineCapabilities.swift).

### How does the container tool manage memory for containers?

The tool leverages the Virtualization framework's partial memory-ballooning implementation to allocate only the memory actively used by the container workload. As documented in [`docs/technical-overview.md`](https://github.com/apple/container/blob/main/docs/technical-overview.md), the VM's footprint scales dynamically with the container's actual memory consumption rather than reserving the full static request size, allowing for higher density on host machines.

### Can I run the container tool on an Intel-based Mac?

No. The tool explicitly checks for nested virtualization support using `MachineCapabilities.requireNestedVirtualizationSupported()`, which will fail on Intel Macs. This requirement is architectural: the container tool depends on the ability to run lightweight Linux VMs as containers, which requires the nested virtualization features only available on Apple Silicon M3 and later.

### What is the role of the `LinuxContainer` abstraction?

`LinuxContainer` acts as a bridge between the high-level container API and the low-level Virtualization framework. Instantiated in [`RuntimeService.swift`](https://github.com/apple/container/blob/main/RuntimeService.swift), this abstraction wraps the `VZVirtualMachineManager` and applies container-specific configurations such as network interfaces, process I/O streams, and filesystem mounts. It allows developers to interact with OCI images while the framework handles VM isolation and device management.