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_USERCONTAINER_UIDCONTAINER_GIDCONTAINER_HOMECONTAINER_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/containerrepository. - State persistence is achieved by storing the root filesystem on disk, preserving users, installed packages, and services between
stopandrunoperations. - Host integration automatically mounts macOS
$HOMEinto 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.shwith environment variables likeCONTAINER_USERandCONTAINER_HOME. - Resource management through
container machine setupdatesContainerSystemConfig.swiftconfigurations, 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →