# How to Run a Linux Container on macOS with Apple's Container Runtime

> Learn to run Linux containers on macOS using Apple's container runtime. Achieve VM isolation and near-native performance with this lightweight solution.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: how-to-guide
- Published: 2026-06-26

---

**Apple's `container` CLI provisions a lightweight Virtual Machine for each Linux container using the native Virtualization framework, enabling you to run Linux workloads on macOS with VM-level isolation and near-native performance.**

Apple open-sourced its native container runtime in the `apple/container` repository, providing a way to run Linux containers on macOS without relying on third-party virtualization layers. This tool leverages Apple's **Virtualization** and **vmnet** frameworks to create isolated, per-container VMs that boot a minimal Linux kernel. Here's how to run a Linux container on macOS with Apple's container runtime, from installation to advanced configuration.

## Architecture and Components

### Core Runtime Components

According to the [`docs/technical-overview.md`](https://github.com/apple/container/blob/main/docs/technical-overview.md) file, the runtime consists of several specialized processes that communicate via XPC:

- **`container` CLI**: The front-end binary that parses user commands and communicates with the daemon.
- **`container-apiserver`**: A launch agent started by `container system start` that implements client-side APIs for container, image, and network management.
- **XPC Helpers**: Separate processes owning specific subsystems:
  - `container-core-images`: Manages the OCI image store and cache
  - `container-network-vmnet`: Handles virtual network interfaces using the vmnet framework
  - `container-runtime-linux`: Executes the container runtime inside each VM

The configuration is defined in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift), which loads defaults from **`~/.config/container/config.toml`**.

### The Container Lifecycle

When you execute `container run`, the following occurs as implemented in [`Sources/ContainerCommands/Container/ContainerRun.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Container/ContainerRun.swift):

1. **System Initialization**: `container system start` (implemented in [`Sources/ContainerCommands/System/SystemStart.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/System/SystemStart.swift)) registers the `container-apiserver` launch agent and creates the default vmnet network.
2. **VM Provisioning**: The CLI requests a new lightweight VM from the daemon, created via the Virtualization framework.
3. **Image Mounting**: The VM pulls the OCI image via `container-core-images`, or uses a local cache.
4. **Container Execution**: The `container-runtime-linux` helper runs the container's PID 1 process inside a Kata-Containers VM.
5. **Resource Attachment**: Options like `--publish` and `--volume` are translated into virtio-fs mounts and NAT rules on the VM's network interface.

## Installation and Setup

### Installing the Container Package

Download the signed installer from the GitHub releases page and install it using the macOS installer command:

```bash
curl -L -o container.pkg https://github.com/apple/container/releases/latest/download/container-installer-signed.pkg
sudo installer -pkg container.pkg -target /

```

### Starting the Container System

Before running containers, start the background services. This loads the `ContainerSystemConfig` and initializes the default network:

```bash
container system start

```

This command registers the launch agents and creates the vmnet interface described in [`docs/technical-overview.md`](https://github.com/apple/container/blob/main/docs/technical-overview.md).

## Running Linux Containers

### Basic Container Execution

Run an interactive Alpine Linux shell using the `container run` command. This creates a new VM, downloads the image if needed, and executes your command:

```bash
container run -it --rm alpine:latest /bin/sh

```

Inside the container, verify you are running Linux on Apple Silicon:

```bash
uname -a

# Output: Linux <uuid> 6.1.68 ... aarch64 GNU/Linux

```

### Networking and Storage

Expose container ports to the host using the `--publish` flag. The runtime configures NAT rules through the vmnet framework:

```bash
container run -d -p 127.0.0.1:8080:80 nginx:latest
curl http://127.0.0.1:8080

```

Mount host directories into the container using virtio-fs:

```bash
container run --volume $HOME/Projects:/src node:latest ls /src

```

### Resource Configuration

Tune VM resources per container using flags that map to the `ContainerSystemConfig` parameters:

```bash
container run --cpus 2 --memory 4g ubuntu:latest

```

## Advanced Configuration

### Nested Virtualization and Custom Init

For specialized workloads, you can enable nested virtualization (requires Apple Silicon M3+ and appropriate kernel configuration):

```bash
container run --virtualization kvm ubuntu:latest

```

Run a custom initialization binary before the container starts:

```bash
container run --init-image /path/to/vminitd alpine:latest

```

### Network Isolation

Create separate network namespaces for container isolation (requires macOS 26+):

```bash
container network create isolated
container run --network isolated alpine:latest

```

## Programmatic Control with Swift

You can interact with the runtime programmatically using the `ContainerCommands` Swift package. The following example demonstrates starting the system and running a container equivalent to the CLI commands:

```swift
import ContainerCommands

// Start the container system programmatically
let system = try await System.start()
print("Container system started: \(system)")

// Load configuration from ~/.config/container/config.toml
let config = try await Application.loadContainerSystemConfig()

// Pull an image via the container-core-images helper
let image = try await Image.pull(
    reference: "alpine:latest",
    containerSystemConfig: config
)

// Run a container with the container-runtime-linux helper
let container = try await Container.run(
    name: "my-shell",
    image: image,
    args: ["/bin/sh"],
    options: .init(interactive: true),
    containerSystemConfig: config
)
print("Container started with ID \(container.id)")

```

This leverages the `ConfigurationLoader.load` mechanism and the XPC communication defined in the `ContainerAPIService` server implementation.

## Summary

- **Apple's `container` runtime** uses the native Virtualization framework to provision per-container VMs, providing stronger isolation than traditional container approaches.
- **Installation** requires the signed PKG installer from the GitHub releases, followed by `container system start` to initialize the `container-apiserver` and vmnet network.
- **Configuration** is managed through `ContainerSystemConfig` in `~/.config/container/config.toml`, with per-container overrides for CPU, memory, and networking.
- **Standard OCI workflows** work out of the box: `container run`, `container build`, and `container push` operate like their Linux counterparts.
- **Advanced features** include nested virtualization on M3+ chips, custom init images, and isolated networks on macOS 26+.

## Frequently Asked Questions

### How does Apple's container runtime differ from Docker Desktop?

Apple's runtime creates a **dedicated lightweight VM for each container** using the Virtualization framework, whereas Docker Desktop typically runs a single Linux VM hosting all containers. This architecture provides stronger isolation boundaries and leverages native macOS frameworks like vmnet and launchd rather than relying on a LinuxKit-based VM.

### What are the system requirements for running Linux containers?

The runtime requires a Mac with Apple Silicon (ARM64 architecture) and a recent macOS version. Specific features like isolated networks require macOS 26 or later. The container VMs boot a Kata-Containers static kernel (version 6.1.68 as shown in the reference implementation), so your Mac must support the Virtualization framework introduced in macOS 11.

### How do I configure default resources for all containers?

Default CPU, memory, and network settings are controlled by the `ContainerSystemConfig` structure loaded from `~/.config/container/config.toml`. As defined in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift), these values serve as defaults for all newly created containers, though you can override them per-container using the `--cpus` and `--memory` flags.

### Is nested virtualization supported on Apple Silicon?

Yes, but with specific requirements. According to the configuration options in the how-to documentation, you can enable KVM inside containers using the `--virtualization` flag on Apple Silicon M3 chips or newer. This requires a kernel built with the appropriate virtualization configuration options and only works on newer hardware generations.