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 CPUs
  • memory: Memory limit with unit suffix (G for GiB, M for 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 set with parameters like cpus=4 and memory=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 nproc and free executed via container 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:

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 →