What Is Container Machine and How to Use It for Persistent Linux Environments

Container machine is a sub-command of Apple's container tool that creates persistent Linux virtual machines from standard OCI images, enabling full Linux environments with init systems, preserved filesystem state, and seamless macOS home directory integration.

Container machine is a sub-command of the Apple container tool that creates persistent Linux environments on macOS. Unlike traditional containers that run single processes, a container machine boots an entire Linux virtual machine from any OCI image containing /sbin/init, storing the root filesystem on disk for full state persistence between sessions.

Architecture and Persistence Model

The container machine command leverages the macOS Virtualization Framework to provide lightweight VM performance while maintaining the flexibility of container workflows. According to the technical overview, this architecture bridges the gap between ephemeral containers and traditional virtual machines.

OCI Image Format and Init System

Any OCI image containing /sbin/init can serve as a container machine base. The image is pulled, cached, and launched as a VM rather than a container process. As documented in docs/container-machine.md, this requirement ensures the image includes a proper init system capable of managing services and user sessions.

Host Integration and Filesystem Mounting

Container machines automatically integrate with the macOS host environment. The user's macOS username and $HOME directory are mounted inside the VM at /home/<username>, enabling seamless editing of source files on the Mac while building and running inside Linux. This mount behavior is configured through ContainerSystemConfig.swift and persists across machine restarts.

Networking and DNS Resolution

Each container machine receives a dedicated virtual network interface managed by the host. Machines are reachable via locally scoped DNS names using the pattern <name>.machine, with the DNS zone managed by container system dns. This configuration is demonstrated in the VS Code integration example at examples/container-machine-vscode/README.md.

Creating and Managing Container Machines

The container machine CLI provides comprehensive lifecycle management for persistent Linux environments.

Basic Creation and Startup

Create a new machine from any public or private OCI image:


# Create from Alpine image

container machine create alpine:latest --name dev

# Open interactive shell (automatically mounts $HOME)

container machine run -n dev

Default Machine Configuration

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

container machine set-default dev
container machine run

Lifecycle Management

Manage running machines through standard lifecycle commands:


# List all machines

container machine ls

# Inspect machine configuration

container machine inspect dev

# Stop and preserve state

container machine stop dev

# Remove machine and persistent storage

container machine rm dev

Custom Images and First-Boot Configuration

Container machines support custom images beyond standard distributions. Users can build specialized images (e.g., Ubuntu with systemd) and provide first-boot customization scripts.

Bring Your Own Image

Build and use custom images through the standard container workflow:


# Build custom Ubuntu image

container build -t local/ubuntu-machine:latest .

# Create machine from custom image

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

First-Boot Customization

Add a /etc/machine/create-user.sh script to your image for automatic user configuration on first boot. This script runs as root with the following environment variables available:

  • CONTAINER_USER
  • CONTAINER_UID
  • CONTAINER_GID
  • CONTAINER_HOME
  • CONTAINER_MACHINE_ID

According to docs/container-machine.md, this enables dynamic user creation and environment setup without manual intervention.

Configuration and Resource Management

Machine-level defaults are stored in ContainerSystemConfig.swift and loaded from config.toml. These settings persist across system restarts and control resource allocation and mount behavior.

Resource Allocation

Configure CPU count and memory size using the set subcommand. Changes take effect after the next stop and start cycle:


# Configure 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

Configuration Persistence

The Sources/ContainerPersistence/ContainerSystemConfig.swift file defines the on-disk configuration schema that drives persistence behavior. When you execute container machine set, the system updates the persisted JSON configuration stored alongside the machine's root filesystem.

Summary

  • Container machine creates persistent Linux VMs from OCI images using the macOS Virtualization Framework, as implemented in the apple/container repository.
  • State persistence is achieved by storing the root filesystem on disk, preserving users, installed packages, and services between stop and run operations.
  • Host integration automatically mounts macOS $HOME into the VM at /home/<username>, enabling seamless development workflows.
  • Custom images support any OCI format with /sbin/init, including first-boot customization via /etc/machine/create-user.sh with environment variables like CONTAINER_USER and CONTAINER_HOME.
  • Resource management through container machine set updates ContainerSystemConfig.swift configurations, with changes effective after the next restart cycle.

Frequently Asked Questions

What is the difference between container machine and Docker?

Container machine boots a full Linux virtual machine with an init system from an OCI image, whereas Docker runs isolated processes without a persistent VM layer. In apple/container, the machine persists filesystem state across restarts, maintains running services, and provides DNS resolution via <name>.machine, offering a complete Linux environment rather than a single-process container.

How does container machine persist data?

The VM's root filesystem is stored on disk according to the configuration in Sources/ContainerPersistence/ContainerSystemConfig.swift. When you execute container machine stop, the entire state—including installed packages, user accounts, and running services—is preserved. Running container machine run restores the exact same filesystem, unlike ephemeral containers that reset on restart.

Can I use custom Linux distributions?

Yes. Any OCI image containing /sbin/init can serve as a container machine base, as documented in docs/container-machine.md. You can build custom images with specific init systems (such as systemd) and optionally include a /etc/machine/create-user.sh script that runs once on first boot to customize the user account using environment variables like CONTAINER_UID and CONTAINER_HOME.

How do I configure CPU and memory resources?

Use the container machine set command to adjust resources, which updates the persisted configuration loaded from config.toml and defined in ContainerSystemConfig.swift. For example, container machine set -n dev cpus=4 memory=8G configures the machine to use 4 CPU cores and 8GB of RAM, with changes taking effect after the next container machine stop and container machine run cycle.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →