How to Create and Manage Container Machines with Apple Container
Apple Container treats container machines as persistent Linux environments managed through a Swift-based Machine API Service, allowing you to create, run, configure, and delete VMs using the container machine CLI commands.
Apple Container provides a native macOS solution for running persistent Linux environments known as container machines. Unlike ephemeral containers, these machines maintain a root filesystem on disk and run an init system, mapping your host macOS user into the virtual machine. According to the apple/container repository, the architecture relies on a Machine API Service that tracks state and exposes a JSON-over-HTTP interface, while the container machine CLI commands handle the full lifecycle from creation to deletion.
Architecture of Container Machines
Machine API Service
The Machine API Service is a Swift-based server that tracks container-machine state, stores configuration artifacts, and exposes a JSON-over-HTTP API. In Sources/Services/MachineAPIService/Server/MachinesService.swift, the service handles create, delete, list, inspect, and configuration update operations. This service validates that images contain /sbin/init before creating a machine, generates unique IDs, and writes MachineConfig artifacts to disk via Sources/ContainerPersistence/MachineConfig.swift.
Machine Client
The Machine Client acts as a thin Swift wrapper that communicates with the API. Defined in Sources/Services/MachineAPIService/Client/MachineClient.swift, this client serializes requests, parses responses, and surfaces errors to the CLI. All user-facing commands delegate to this client, ensuring consistent error handling and request formatting.
Container Commands
The container machine subcommands parse arguments, resolve target machines (default or explicit via -n), and invoke the client. Key implementations include:
MachineCreate.swift– Handles creation logic and--set-defaultflag processingMachineRun.swift– Manages booting stopped machines and executing shells or binariesMachineSet.swift– Modifies persistent configuration resourcesMachineStop.swift– Gracefully shuts down VMs and clears container IDsMachineDelete.swift– Removes configurations, root filesystems, and OCI bundlesMachineList.swiftandMachineInspect.swift– Query state and metadata
All commands share logic in Sources/ContainerCommands/Machine/MachineHelpers.swift to resolve IDs, check default presence, and format error messages.
Creating a Container Machine
Creating a machine requires an image with /sbin/init. The service validates this requirement, generates a unique ID, and writes a MachineConfig specifying boot-time resources (CPUs, memory, home-mount) to disk. If you pass --set-default, the new ID is stored in the user defaults file for subsequent commands.
# Create a machine from Alpine and set it as default
container machine create --name dev --set-default alpine:3.22
# List machines to verify creation (default is marked)
container machine ls
Running and Managing Container Machines
Starting and Running Commands
The container machine run command first resolves the target machine using the default or the -n flag. If the machine is stopped, MachinesService.swift boots it via the container runtime. The command either opens an interactive login shell as the host user or executes the supplied binary inside the VM.
# Interactive shell in default machine
container machine run
# Execute command in named machine
container machine run -n dev uname -a
Configuring Resources
Use container machine set to mutate MachineConfig on disk. Changes only apply after the next stop/start cycle, guaranteeing consistency. For example, to allocate 4 CPUs and 8GB of memory:
container machine set -n dev cpus=4 memory=8G
You must stop the machine before the changes take effect.
Stopping and Deleting
Stop gracefully shuts down the VM and clears the container ID, while delete removes the configuration, persistent root filesystem, and associated OCI bundles.
# Stop the machine
container machine stop dev
# Verify auto-boot on next run
container machine run -n dev -- cat /proc/cpuinfo
# Remove permanently
container machine rm dev
Programmatic Management with Swift
You can manage machines programmatically using the MachineClient Swift API. This is useful for building automation tools or integrating with macOS applications.
import MachineAPIService
let client = MachineClient()
let config = MachineConfiguration(
id: "dev",
image: "alpine:3.22",
platform: .linux,
resources: MachineResources(cpus: 2, memory: "4G")
)
try await client.createMachine(configuration: config, setDefault: true)
To inspect a machine's state and storage location:
let snapshot = try await client.inspectMachine(id: "dev")
print("Status:", snapshot.state) // e.g. "running"
print("Rootfs path:", snapshot.rootfsPath) // persistent location on disk
Summary
- Container machines are persistent Linux environments running an init system with macOS user mapping, managed through the Machine API Service in
MachinesService.swift - The CLI delegates to
MachineClient.swift, with command implementations inSources/ContainerCommands/Machine/includingMachineCreate.swift,MachineRun.swift, andMachineDelete.swift - Creation validates
/sbin/init, generates a unique ID, and persists configuration viaMachineConfig.swift - The
container machine runcommand auto-boots stopped machines and supports both interactive shells and binary execution - Configuration changes via
container machine setapply only after the next stop/start cycle - Swift developers can use
MachineClientto programmatically create, inspect, and manage machines
Frequently Asked Questions
What is the difference between a container and a container machine in Apple Container?
A container machine is a persistent Linux environment that runs an init system and maintains its root filesystem on disk between restarts, whereas standard containers are typically ephemeral. According to the source code in MachinesService.swift, machines specifically require an image containing /sbin/init and map the host macOS user into the VM.
How do I change the CPU and memory allocation for an existing container machine?
Use container machine set -n <name> cpus=<value> memory=<value> to update the MachineConfig stored on disk. As implemented in MachineSet.swift, these changes only take effect after you stop and restart the machine, ensuring configuration consistency.
Can I use Apple Container machines for development environments like VS Code?
Yes. The repository includes a complete example in examples/container-machine-vscode/README.md demonstrating how to configure a container machine as a remote development environment. You can SSH into the machine or use the container machine run command to execute development tools.
Where does Apple Container store machine configuration and persistent data?
Machine configurations are persisted via Sources/ContainerPersistence/MachineConfig.swift, which stores boot-time resources and the unique machine ID. The root filesystem and associated OCI bundles are stored on disk at paths exposed through the inspect command's rootfsPath property.
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 →