How to Create a Persistent Container Machine with Custom Resources in macOS
To create a persistent container machine with custom resources, use container machine create to provision the machine from an OCI image, then container machine set to write CPU and memory limits to disk, and restart to apply the changes.
A container machine is a core feature of the apple/container repository that lets you run a full Linux environment on macOS. These machines are built from standard OCI images and provide persistent storage that survives stop/start cycles, while automatically mapping your macOS user and $HOME into the Linux environment. This guide demonstrates how to provision a machine and configure custom CPU and memory resources that persist across reboots.
Understanding Container Machine Architecture
Container machines follow a simple initialization flow: an OCI image feeds into the container-machine init process (managed by systemd), which mounts a persistent storage directory on your host. When you modify resources, the container machine set command writes a JSON configuration file to ~/.container/machines/<name>/config.json. The container runtime reads this configuration on every start, applying the requested CPU count, memory allocation, home-mount mode, and optional kernel overrides.
Because the configuration lives alongside the machine’s data in your home directory, these resource limits are fully persistent. You can stop the machine, reboot your Mac, and later run container machine run -n <name> to access the same environment with identical CPU and memory constraints, as documented in the quick-start examples in [docs/container-machine.md](https://github.com/apple/container/blob/main/docs/container-machine.md).
Creating a Persistent Container Machine
The first step provisions the persistent storage and establishes the home directory mapping. You create the machine from any OCI image, such as alpine:latest or ubuntu:latest.
Run the following command to create a machine named dev:
container machine create alpine:latest --name dev
After creation, verify that the host integration works correctly:
container machine run -n dev whoami # Outputs your macOS username
container machine run -n dev pwd # Shows /home/<username> with mounted $HOME
Configuring Custom Resources
Once the machine exists, you modify its resource allocation using the set subcommand. According to the command reference in [docs/command-reference.md](https://github.com/apple/container/blob/main/docs/command-reference.md), this writes the new configuration to disk, but the changes only take effect after a stop/start cycle.
Setting CPU and Memory Limits
Use the cpus and memory settings to allocate hardware resources. For example, to assign 4 CPUs and 8 GiB of RAM to the dev machine:
container machine set -n dev cpus=4 memory=8G
This updates the JSON configuration stored at ~/.container/machines/dev/config.json. The settings include:
cpus: Integer number of virtual CPUsmemory: Memory limit with unit suffix (Gfor GiB,Mfor MiB)
Applying Configuration Changes
Restart the machine so the Linux kernel sees the new allocations:
container machine stop dev
container machine run -n dev
After restart, the machine retains these custom resources across future stops and starts because the configuration is stored persistently on disk, not in volatile runtime state.
Verifying Resource Allocation
Confirm that the resource limits are active by checking inside the container environment:
container machine run -n dev -- nproc # Should report 4 CPUs
container machine run -n dev -- free -h # Should show approximately 8 GiB RAM
These commands execute inside the persistent container machine and reflect the values stored in the machine’s configuration file.
Advanced Configuration Options
Beyond CPU and memory, you can customize the home directory mount behavior and kernel parameters. For example, to make your home directory read-only inside the machine:
container machine set -n dev home-mount=ro
container machine stop dev
container machine run -n dev
Now attempts to write to $HOME will fail, as demonstrated in the practical examples found in [examples/container-machine-vscode/README.md](https://github.com/apple/container/blob/main/examples/container-machine-vscode/README.md).
Summary
- Create a persistent machine with
container machine create <image> --name <name>to provision OCI-based Linux environments that survive reboots. - Configure custom resources using
container machine setwith parameters likecpus=4andmemory=8G, which writes to~/.container/machines/<name>/config.json. - Restart the machine to apply resource changes, as the Linux kernel only reads CPU and memory limits during initialization.
- Verify allocations with standard Linux tools like
nprocandfreeexecuted viacontainer machine run.
Frequently Asked Questions
What makes a container machine "persistent"?
A container machine is persistent because its filesystem and configuration are stored in a directory on your host at ~/.container/machines/<name>/. Unlike ephemeral containers, the data survives container machine stop commands and host reboots. When you restart the machine, it mounts the same storage and applies the same resource limits defined in config.json.
Where is the container machine configuration stored?
The configuration is stored as a JSON file at ~/.container/machines/<name>/config.json. This file contains the CPU count, memory limit, home-mount mode, and optional kernel overrides. The container machine set command modifies this file directly, ensuring settings persist across system restarts.
Do I need to recreate the machine to change resources?
No, you do not need to recreate the machine. Use container machine set to update the configuration on disk, then stop and restart the machine. The resource changes take effect on the next start because the runtime reads the updated config.json during initialization. This allows you to tune resources without losing existing data in the machine's filesystem.
Can I use any OCI image for a container machine?
Yes, you can use any standard OCI-compatible Linux image, such as alpine:latest, ubuntu:latest, or custom images. The container machine create command pulls and provisions the image into the persistent storage structure. The image must support the container machine's initialization system (systemd) to properly boot the Linux environment.
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 →