# Apple Container Architecture: How macOS Runs OCI Containers in Lightweight VMs

> Discover Apple's container architecture. Learn how macOS runs OCI containers using lightweight VMs and hardware-level isolation for efficient workloads.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: architecture
- Published: 2026-06-16

---

**TLDR:** Apple's container architecture implements a layered system that combines a CLI frontend, XPC-based helper services, and per-container lightweight Linux VMs orchestrated by the macOS Virtualization framework to provide hardware-level isolation for OCI-compatible workloads.

The `apple/container` repository delivers a native macOS container runtime that bridges OCI standards with macOS frameworks. Unlike traditional container engines that share the host kernel, this architecture spins up a dedicated lightweight virtual machine for every container, ensuring complete kernel and filesystem isolation while maintaining fast startup times through efficient XPC communication. According to the technical documentation in [`docs/technical-overview.md`](https://github.com/apple/container/blob/main/docs/technical-overview.md), the system delegates specific responsibilities to specialized XPC helpers that interface with macOS-native services.

## CLI and API Server Layer

The user-facing component is the `container` command-line interface, which parses commands and communicates with the backend through GRPC-style APIs.

### The container Binary

The `container` binary handles argument parsing, user output, and XPC connections to the backend services. It serves as the primary entry point for all container operations.

### The container-apiserver Service

When you execute `container system start`, the tool launches `container-apiserver` as a launch agent that registers with `launchd`. This central server, implemented in [`Sources/Services/ContainerAPIService/Server/Containers/ContainersService.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Server/Containers/ContainersService.swift), exposes the primary API surface for container, image, and network management. It routes requests to appropriate XPC helpers and integrates with [`Sources/ContainerLog/ServiceLogger.swift`](https://github.com/apple/container/blob/main/Sources/ContainerLog/ServiceLogger.swift) for unified system logging.

## XPC Helper Services

The architecture delegates specialized tasks to three lightweight XPC services that run in their own sandboxes, communicating through protocols defined in [`Sources/ContainerXPC/XPCServerSession.swift`](https://github.com/apple/container/blob/main/Sources/ContainerXPC/XPCServerSession.swift).

### container-core-images

This helper handles image store operations and registry access, authenticating via the macOS Keychain. It fetches OCI image layers and prepares them for streaming into the VM.

### container-network-vmnet

This service configures virtual network interfaces using the `vmnet` framework. It creates a virtual Ethernet interface for each VM and manages NAT-style networking.

### container-runtime-linux

This helper manages the per-container lifecycle inside lightweight VMs. The implementation in `Sources/Plugins/RuntimeLinux/RuntimeLinuxHelper+Start.swift` requests VM creation from the Virtualization framework and coordinates the container init process.

## Virtualization and Isolation Layer

Each container runs inside a dedicated lightweight Linux VM orchestrated by the macOS **Virtualization** framework.

### VM Creation and Lifecycle

The `container-runtime-linux` helper requests VM creation from the framework, passing configuration parameters such as kernel images and memory limits. The VM isolates the container's kernel, networking stack, and filesystem from the host, exposing only explicitly mounted host paths to reduce the attack surface.

### Security Boundaries

The VMs use minimal runtime libraries to ensure fast startup while maintaining VM-level isolation. XPC sandboxing ensures that each helper operates with limited privileges, and only files explicitly mounted by the user are visible inside the VM.

## Networking Architecture

Network isolation relies on the **vmnet** framework available in macOS 15 and later. The `container-network-vmnet` helper creates a virtual Ethernet interface for each VM, connecting it to a NAT-style network with the default subnet `192.168.64.0/24`.

While macOS 15 offers limited isolation, macOS 26+ supports full VMnet-based networks with enhanced security boundaries. The CLI inspects these configurations by querying the XPC helper, which interfaces directly with the framework's virtual switch.

## Configuration Management

System defaults are managed by the `ContainerSystemConfig` Swift struct in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift). This structure reads TOML configuration files at startup to define VM kernel paths, memory limits, DNS settings, and networking parameters. The configuration persists across reboots and provides the central source of truth for the `container-apiserver` when creating new container instances.

## Request Lifecycle and Data Flow

A typical `container run` command traverses seven distinct layers:

1. The CLI parses arguments and sends a request to `container-apiserver` via XPC.
2. The API server validates the OCI image specification and creates an XPC client for `container-runtime-linux`.
3. The runtime helper requests VM creation from the Virtualization framework.
4. The framework launches a minimal Linux VM with the specified kernel and init process.
5. The VM's network interface attaches to `container-network-vmnet`, which configures the `vmnet` virtual Ethernet adapter.
6. `container-core-images` fetches image layers from the registry (using Keychain-stored credentials) and streams the filesystem into the VM.
7. The container process executes inside the VM, with stdout/stderr routed back through the XPC helpers to the CLI for display.

This flow ensures that heavy I/O operations like image pulling happen outside the VM, while the actual workload runs inside hardware-isolated boundaries.

## Practical Code Examples

### Starting a Container via Swift Client

The following Swift code demonstrates how the client library interacts with the API server, defined in [`Sources/Services/ContainerAPIService/Server/Containers/ContainersService.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Server/Containers/ContainersService.swift):

```swift
import ContainerAPIClient
import ContainerRuntimeClient
import ContainerXPC

let client = try ContainerAPIClient()
let spec = ContainerSpec(
    image: "docker.io/library/alpine:latest",
    command: ["/bin/sh", "-c", "echo Hello from container"]
)

// Ask the server to create and start the container
let containerID = try client.runContainer(spec: spec)

// Stream its output
let stream = try client.attach(to: containerID, stdOut: true, stdErr: true)
for try await line in stream.lines {
    print(line)
}

```

### Minimal XPC Server Implementation

The `container-runtime-linux` helper implements a protocol similar to this stub, based on the actual implementation in `Sources/Plugins/RuntimeLinux/RuntimeLinuxHelper+Start.swift`:

```swift
import ContainerXPC
import ContainerRuntimeLinuxServer

class RuntimeServer: NSObject, ContainerRuntimeLinuxServerProtocol {
    func startContainer(_ request: StartRequest,
                       withReply reply: @escaping (StartResponse) -> Void) {
        // Launch the lightweight VM via the Virtualization framework
        let vm = LightweightLinuxVM(configuration: request.vmConfig)
        vm.start()
        reply(StartResponse(success: true))
    }
}

// Register the service
let listener = XPCListener(serviceName: "com.apple.container.runtime.linux")
listener.delegate = RuntimeServer()
listener.resume()

```

### Inspecting Network Configuration

You can verify the vmnet-based network configuration using the CLI:

```bash
$ container network inspect
{
  "subnet": "192.168.64.0/24",
  "gateway": "192.168.64.1",
  "driver": "vmnet"
}

```

This command forwards the request to the `container-network-vmnet` XPC helper, which queries the **vmnet** framework for current interface states.

## Summary

- **Apple container architecture** uses a modular, XPC-driven design defined in [`Package.swift`](https://github.com/apple/container/blob/main/Package.swift) to orchestrate OCI containers inside lightweight Linux VMs.
- The **Virtualization framework** provides hardware-level isolation for each container, while **XPC helpers** (`container-core-images`, `container-network-vmnet`, `container-runtime-linux`) handle specialized tasks.
- Configuration is centralized in `ContainerSystemConfig` and persisted via TOML files in `Sources/ContainerPersistence/`.
- Networking leverages the **vmnet** framework with NAT-style subnets, requiring macOS 15 or later.
- Communication flows from CLI → API Server → XPC Helpers → VM, ensuring that only explicitly mounted host paths are visible inside containers.

## Frequently Asked Questions

### How does Apple Container architecture differ from Docker Desktop?

Unlike Docker Desktop, which uses a single Linux VM to host all containers, Apple's architecture creates a dedicated lightweight VM for each container. This provides stronger isolation at the kernel level, as each container runs with its own Linux kernel instance rather than sharing the VM's kernel. The XPC-based communication layer also integrates more deeply with macOS security frameworks like Keychain and Unified Logging.

### What macOS versions support the Apple Container architecture?

The architecture requires macOS 15 or later for basic functionality, specifically for the `vmnet` framework support. macOS 26 and later versions provide enhanced networking isolation with full VMnet-based network capabilities, while earlier versions have limited network isolation between containers.

### Where are the XPC service definitions located in the source code?

The core XPC session handling is implemented in [`Sources/ContainerXPC/XPCServerSession.swift`](https://github.com/apple/container/blob/main/Sources/ContainerXPC/XPCServerSession.swift), which defines the communication protocols used by all helpers. The `container-runtime-linux` specific implementation resides in `Sources/Plugins/RuntimeLinux/RuntimeLinuxHelper+Start.swift`, while the API server definitions are in [`Sources/Services/ContainerAPIService/Server/Containers/ContainersService.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Server/Containers/ContainersService.swift).

### How does the system handle registry authentication?

The `container-core-images` XPC helper retrieves registry credentials from the macOS Keychain, leveraging the platform's secure credential storage. This eliminates the need for plaintext credential files, with authentication handled transparently during image pull operations in step six of the request lifecycle.