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-sflag if both are provided.--opt journal=<mode>: Configures the ext4 journaling mode. Valid modes areordered,writeback, orjournal. You can optionally specify a journal size (e.g.,journal=writeback:64m).-s <size>: Explicit size in bytes (supports human-readable formats like10g).
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 byVolumeStorage.isValidVolumeName. - Create volumes using
container volume createwith--optflags forsize=andjournal=(supporting modesordered,writeback, andjournal). - 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →