# How to Use Container Machine for VM-Based Workflows with Apple Container

> Learn how to use container machine with apple/container to run VM-based container workflows on macOS. Effortlessly convert OCI images into persistent Linux VMs.

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

---

**Apple Container provides a container machine abstraction that converts OCI images into persistent, lightweight Linux VMs on macOS, automatically mounting your macOS home directory and preserving state across restarts.**

The `apple/container` repository implements a unique virtualization layer that bridges traditional OCI containers with full Linux virtual machines. This container machine enables you to run long-lived Linux services, develop with native macOS editors while building inside Linux, and even experiment with nested virtualization—all from a standard container image.

## What is a Container Machine?

A **container machine** is a persistent VM managed by the Apple Container runtime that boots from any OCI image containing an init system (`/sbin/init`). Unlike ephemeral containers, these machines maintain their filesystem across stops and starts, while remaining fully integrated with macOS.

Key characteristics include:

- **Automatic home directory mounting** – Your macOS `$HOME` appears inside the VM at `/Users/<username>`
- **Persistent state** – The VM filesystem survives reboots and is stored in a dedicated machine directory
- **Nested virtualization support** – Available on Apple Silicon M3+ with macOS 15+ when using a kernel built with `CONFIG_KVM=y`
- **Resource flexibility** – CPU count, memory limits, and kernel paths are configurable via the `MachineConfig` API

## Core Architecture

The container machine implementation spans several key components in the codebase:

- **[`MachineCreate.swift`](https://github.com/apple/container/blob/main/MachineCreate.swift)** – The CLI entry point in [`Sources/ContainerCommands/Machine/MachineCreate.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Machine/MachineCreate.swift) that parses flags and invokes the Machine Service
- **`MachineConfig`** – The persistent data model in [`Sources/ContainerPersistence/MachineConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/MachineConfig.swift) that stores CPU count, memory size, home-mount mode, and kernel paths as a Codable structure
- **`MachinesService`** – The server-side logic in [`Sources/Services/MachineAPIService/Server/MachinesService.swift`](https://github.com/apple/container/blob/main/Sources/Services/MachineAPIService/Server/MachinesService.swift) handling create, inspect, stop, and remove operations
- **`RuntimeService`** – The low-level runtime that launches VMs using Apple's virtualization framework

When you execute `container machine create`, the CLI calls `MachineClient.machineConfigFromFlags` to resolve image layers and build a boot configuration, which the Machine Service persists to [`boot-config.json`](https://github.com/apple/container/blob/main/boot-config.json) before booting the VM.

## Creating and Managing Machines

### Quick Start

Create a persistent Linux environment from any OCI image with an init system:

```bash

# Create a machine named 'dev' from Alpine

container machine create alpine:latest --name dev

# Open an interactive shell (matches your macOS user)

container machine run -n dev

# Run a single command to verify home directory mounting

container machine run -n dev -- pwd

```

Set a default machine to omit the `-n` flag in subsequent commands:

```bash
container machine set-default dev
container machine run  # Operates on 'dev' by default

```

### Resource Configuration

Modify VM resources using the `set` command. Changes persist in `MachineConfig` and apply after the next stop/start cycle:

```bash

# Allocate 4 CPUs and 8GB RAM

container machine set -n dev cpus=4 memory=8G

# Restart to apply changes

container machine stop dev
container machine run -n dev -- nproc  # Verifies 4 CPUs

```

The configuration is validated via `MachineConfig.validateKernelPath` when specifying custom kernels, and stored in the machine's [`boot-config.json`](https://github.com/apple/container/blob/main/boot-config.json).

## Advanced Configuration

### Enabling Nested Virtualization

For workloads requiring KVM (such as running nested VMs), enable virtualization support when creating the machine:

```bash

# Requires Apple Silicon M3+, macOS 15+, and a kernel with CONFIG_KVM=y

container machine create \
    --virtualization \
    --kernel /path/to/vmlinux-kvm \
    --name kvm-dev \
    alpine:latest

# Verify KVM device exposure

container machine run -n kvm-dev -- ls -l /dev/kvm

```

This configuration sets the nested virtualization flag in `MachineConfig` and exposes `/dev/kvm` inside the guest.

### Building Custom Machine Images

Create OCI images with systemd for long-running services:

```dockerfile
FROM ubuntu:24.04
ENV container container
RUN apt-get update && \
    apt-get install -y dbus systemd openssh-server && \
    apt-get clean && rm -rf /var/lib/apt/lists/* && \
    yes | unminimize
RUN >/etc/machine-id && >/var/lib/dbus/machine-id
RUN systemctl set-default multi-user.target

```

Build and deploy the custom image:

```bash
docker build -t local/ubuntu-machine:latest .

container machine create local/ubuntu-machine:latest --name ubuntu

```

## Lifecycle Management

Manage machine states through the CLI:

```bash

# List all machines

container machine ls

# View detailed configuration JSON

container machine inspect dev

# Stop the VM (preserves state)

container machine stop dev

# Delete VM and persistent storage

container machine rm dev

```

The `inspect` command returns the decoded `MachineConfig` including current resource allocations and kernel paths.

## Summary

- Container machines transform OCI images into persistent Linux VMs with seamless macOS home directory integration
- Configuration persists in [`boot-config.json`](https://github.com/apple/container/blob/main/boot-config.json) via the `MachineConfig` Codable model, storing CPU, memory, and virtualization flags
- The Machine Service in [`MachinesService.swift`](https://github.com/apple/container/blob/main/MachinesService.swift) handles orchestration while the Runtime Service manages actual VM execution
- Nested virtualization requires Apple Silicon M3+, macOS 15+, and a custom kernel with `CONFIG_KVM=y`
- All machine state survives stops and starts, making them suitable for systemd-based workflows

## Frequently Asked Questions

### What is the difference between a container machine and a standard container?

A container machine is a persistent virtual machine that boots from an OCI image, whereas standard containers share the host kernel and are typically ephemeral. Machines maintain their filesystem across restarts, support init systems like systemd, and provide full Linux kernel isolation through Apple's virtualization framework.

### Can I use any Linux OCI image as a container machine?

Any OCI image containing `/sbin/init` or an alternative init system can function as a machine image. Minimal images without an init process will not boot properly since the VM expects a standard Linux initialization sequence.

### Where is the machine configuration stored?

Each machine's configuration is persisted as JSON in a [`boot-config.json`](https://github.com/apple/container/blob/main/boot-config.json) file within the machine's storage directory. This file stores the `MachineConfig` values including CPU count, memory allocation, home-mount settings, and optional kernel paths, encoded via Swift's `Codable` protocol.

### How does nested virtualization work with container machines?

Nested virtualization exposes the host's ARM virtualization extensions to the guest VM by setting the virtualization flag in `MachineConfig`. This requires Apple Silicon M3 or later running macOS 15+, along with a Linux kernel compiled with `CONFIG_KVM=y`. The feature allows running additional hypervisors like QEMU or firecracker inside the container machine.