How to Create and Manage Named Volumes with Apple's Container Runtime

Apple's container runtime stores named volumes as sparse disk images under /volumes/<name>/ and validates names against the regex ^[A-Za-z0-9][A-Za-z0-9_.-]*$, supporting creation via the container volume create command with options for size, ext4 journaling mode, and labels.

Apple's open-source container runtime (available in the apple/container repository) implements volumes as first-class resources that persist data outside the container's root filesystem. Unlike ephemeral container layers, named volumes survive container restarts and can be mounted into multiple containers simultaneously. Understanding how to create and manage named volumes with Apple's container runtime is essential for running stateful workloads and maintaining data persistence across container lifecycles.

Understanding Volume Storage and Naming Constraints

Volume Storage Implementation

The runtime treats each volume as a sparse disk image (volume.img) stored in a dedicated host directory under /volumes/<name>/. This design keeps volume data isolated from the container's root filesystem while maintaining efficient storage allocation through sparseness.

Name Validation Rules

Volume names must conform to strict validation rules enforced by VolumeStorage.volumeNamePattern in Sources/ContainerResource/Volume/VolumeConfiguration.swift (lines 36-45). The pattern ^[A-Za-z0-9][A-Za-z0-9_.-]*$ requires names to start with an alphanumeric character, permits periods, hyphens, and underscores in subsequent characters, and limits the total length to 255 bytes. Both the client-side Parser (lines 457-459) and the server-side VolumesService invoke VolumeStorage.isValidVolumeName to enforce these constraints before any creation operation.

Creating Named Volumes with the CLI

When you execute container volume create, the CLI forwards the request to the daemon's VolumesService, which validates the name and generates the backing image via createVolumeImage(for:name:sizeInBytes:journal:) (lines 290-322 in Sources/Services/ContainerAPIService/Server/Volumes/VolumesService.swift).

Basic Volume Creation

Create a simple named volume with default parameters:

container volume create myvolume

Configuring Size and Journaling Options

The runtime supports several create-time options for the default local driver:

  • --label <key=value>: Attaches arbitrary metadata to the volume.
  • --opt size=<size>: Specifies the volume size (e.g., 10g). Overridden by the -s flag if both are provided.
  • --opt journal=<mode>: Configures the ext4 journaling mode. Valid modes are ordered, writeback, or journal. You can optionally specify a journal size (e.g., journal=writeback:64m).
  • -s <size>: Explicit size in bytes (supports human-readable formats like 10g).

Create a 10 GiB volume with ordered journaling:

container volume create \
    --opt journal=ordered \
    --opt size=10g \
    myvolume

Create a volume with writeback journaling and a 64 MiB journal:

container volume create \
    --opt journal=writeback:64m \
    myvolume

Working with Anonymous Volumes

When you mount a path without specifying a volume name (e.g., container run -v /data), the runtime generates an anonymous volume name via VolumeStorage.generateAnonymousVolumeName() (lines 52-55 in Sources/ContainerResource/Volume/VolumeConfiguration.swift). These names follow the pattern anon-<uuid> and persist after the container exits. They are not automatically garbage collected and require manual deletion.

Create and reuse an anonymous volume:


# Creates an anonymous volume automatically

container run -v /data alpine

# Retrieve the generated name

VOL=$(container volume list -q | grep anon)

# Mount the same anonymous volume in a new container

container run -v $VOL:/data alpine

Managing Volume Lifecycle

Listing and Inspecting Volumes

List all volumes in human-readable format:

container volume list

Inspect a specific volume's metadata and configuration in JSON:

container volume inspect myvolume --format json

Deleting and Pruning Unused Volumes

Delete a specific volume permanently:

container volume delete myvolume

Note: Deletion fails if the volume is currently attached to any container, regardless of whether the container is running or stopped.

Remove all unused volumes (those not attached to any container) with a single command:

container volume prune

Programmatic Volume Creation with Swift

You can also create volumes programmatically using the ContainerAPIService client. The Swift API accepts a JournalConfig enum for journaling modes and handles the underlying validation and image creation:

import ContainerAPIService

let client = ContainerAPIClient()
do {
    try client.createVolume(
        name: "myvolume",
        sizeInBytes: 10 * 1024 * 1024 * 1024,  // 10 GiB
        journal: .ordered                       // EXT4.JournalConfig
    )
    print("Volume created successfully")
} catch {
    print("Failed to create volume: \(error)")
}

This client method invokes the same createVolumeImage validation logic (lines 319-320) and sparse image generation used by the CLI.

Summary

  • Volumes are stored as sparse disk images (volume.img) under /volumes/<name>/ on the host.
  • Name validation uses the regex ^[A-Za-z0-9][A-Za-z0-9_.-]*$ with a 255-byte limit, enforced by VolumeStorage.isValidVolumeName.
  • Create volumes using container volume create with --opt flags for size= and journal= (supporting modes ordered, writeback, and journal).
  • Anonymous volumes (generated via generateAnonymousVolumeName) persist after container exit and must be deleted manually.
  • Deletion requires the volume to be unattached from all containers, verified by the VolumesService before removal.

Frequently Asked Questions

What is the naming convention for volumes in Apple's container runtime?

Volume names must match the pattern ^[A-Za-z0-9][A-Za-z0-9_.-]*$ and cannot exceed 255 bytes. This means names must start with a letter or number, can contain periods, hyphens, and underscores, but cannot contain spaces or other special characters. The validation is implemented in Sources/ContainerResource/Volume/VolumeConfiguration.swift and enforced by both the client parser and server-side VolumesService.

How do I configure ext4 journaling when creating a volume?

Use the --opt journal=<mode> flag where <mode> is ordered, writeback, or journal. You can optionally specify a journal size by appending :<size> (e.g., journal=writeback:64m). This configuration is processed by the createVolumeImage method in Sources/Services/ContainerAPIService/Server/Volumes/VolumesService.swift when formatting the underlying sparse image.

Are anonymous volumes automatically deleted when a container stops?

No. Anonymous volumes—generated via VolumeStorage.generateAnonymousVolumeName() with the anon-<uuid> prefix when using -v /path without a named volume—persist on the host after the container exits. You must manually delete them using container volume delete or container volume prune if they are no longer needed.

Why does volume deletion fail with an error about attached containers?

The runtime prevents deletion of volumes that are currently mounted by any container, including stopped containers. This safety check is enforced by the VolumesService before executing the delete operation. You must first remove all containers using the volume (running or stopped) before the delete command will succeed.

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 →