How to Mount Volumes in Container: Bind, Named, and Tmpfs Configuration
Apple Container supports three mount types—bind mounts, named volumes, and tmpfs—using Docker-compatible --mount syntax parsed by Parser.swift and applied via RuntimeService.swift to configure the Linux VM filesystem.
The apple/container repository provides a Swift-based container runtime that handles volume mounting through a strict validation pipeline. Whether you are sharing host directories or allocating temporary memory filesystems, the mount configuration follows a standardized parsing flow from CLI arguments to low-level VM configuration.
Supported Mount Types
Apple Container implements three distinct mount strategies, each handled differently by the internal VolumeOrFilesystem abstraction.
Bind Mounts
Bind mounts map a host directory into the container using virtiofs. When you specify type=bind, the parser in Sources/ContainerCLIService/Parser.swift converts this internally to a virtiofs filesystem type. The source path must exist as a directory on the host, and the parser resolves relative paths against the current working directory using URL(fileURLWithPath:) resolution.
Named Volumes
Named volumes provide persistent storage managed by the container runtime. When parsing type=volume, the source directive is validated against the VolumeStorage.volumeNamePattern defined in VolumeConfiguration.swift. If you omit the src parameter, VolumesService.swift automatically generates an anonymous volume name using VolumeStorage.generateAnonymousVolumeName().
Tmpfs Mounts
Tmpfs mounts create temporary in-memory filesystems that do not persist after container shutdown. These mounts accept size (in MiB) and mode (octal) options. The parser explicitly rejects any src directive for tmpfs mounts, as they exist only in memory without a backing host path.
CLI Syntax and Examples
The --mount flag accepts comma-separated key-value pairs following Docker conventions. The parser normalizes shorthand directives (src to source, dst to destination, ro to read-only).
Bind Mount Example
Mount a host directory as read-only:
container run \
--name myapp \
--mount type=bind,src=./src,dst=/app/src,ro \
myimage:latest
In Parser.swift, the Parser.mount(_:,relativeTo:) function validates that ./src exists and is a directory before converting it to an absolute URL.
Named Volume Example
Attach a persistent volume to a database container:
container run \
--name db \
--mount type=volume,src=dbdata,dst=/var/lib/mysql \
mysql:8
If dbdata does not exist, VolumesService.swift creates it before the container starts.
Tmpfs Mount Example
Create a 512 MiB temporary filesystem:
container run \
--mount type=tmpfs,dst=/tmp,size=512,mode=1777 \
alpine:latest
Parsing and Validation Pipeline
Understanding how to mount volumes in container environments requires insight into the three-stage internal pipeline.
Parser.swift Implementation
The Parser.mount(_:,relativeTo:) method in Sources/ContainerCLIService/Parser.swift splits the input string on commas and builds a directives dictionary with default type=virtiofs. For bind mounts, it verifies directory existence using FileManager.fileExists(atPath:isDirectory:). For volume mounts, it validates names against the storage pattern or triggers anonymous volume creation.
RuntimeService.swift Conversion
After parsing, RuntimeService.swift receives [VolumeOrFilesystem] objects and constructs the low-level mount table for the Linux VM. This service handles special cases such as /dev/shm size configuration by stripping existing size options and injecting user-specified values:
if czConfig.mounts[i].destination == "/dev/shm" {
czConfig.mounts[i].options.removeAll { $0.hasPrefix("size=") }
czConfig.mounts[i].options.append("size=\(shmSize)")
}
Volume Management
VolumesService.swift tracks the lifecycle of named and anonymous volumes. When a container stops, this service ensures proper unmounting and cleanup, as demonstrated in Tests/CLITests/Subcommands/Volumes/TestCLIAnonymousVolumes.swift.
Programmatic Usage in Swift
You can leverage the parsing logic directly in Swift applications using the Container API service.
Using Parser.mounts()
Process multiple mount strings programmatically:
import ContainerAPIService
let rawMounts = [
"type=bind,src=./assets,dst=/app/assets",
"type=volume,src=logs,dst=/var/log/app"
]
// Parse and validate the mounts
let mounts = try Parser.mounts(rawMounts, relativeTo: URL(fileURLWithPath: FileManager.default.currentDirectoryPath))
for mount in mounts {
switch mount {
case .filesystem(let fs):
print("Filesystem mount: \(fs.type) from \(fs.source) → \(fs.destination)")
case .volume(let vol):
print("Volume mount: \(vol.name) → \(vol.destination) (anonymous: \(vol.isAnonymous))")
}
}
This approach validates paths and volume names before container initialization, catching ContainerizationError exceptions for invalid specifications.
Special Cases and Configuration
/dev/shm Size Configuration
The runtime normalizes shared memory mounts automatically. As shown in RuntimeService.swift, the service detects /dev/shm destinations and manages size options explicitly, ensuring the container receives the correct allocation regardless of duplicate specifications in the mount string.
Summary
- Apple Container supports bind mounts (via virtiofs), named volumes, and tmpfs through Docker-compatible
--mountsyntax. - The
Parser.mountfunction inParser.swiftvalidates source directories, resolves relative paths, and distinguishes between filesystem and volume mounts. - Anonymous volumes are generated automatically when volume mounts omit the
srcdirective, managed byVolumesService.swift. - Tmpfs mounts accept
sizeandmodeoptions but reject source paths, creating temporary in-memory storage. RuntimeService.swifthandles low-level VM configuration, including special normalization for/dev/shmsize options.
Frequently Asked Questions
What is the difference between bind mounts and named volumes in Apple Container?
Bind mounts directly map host directories into the container via virtiofs, requiring the source path to exist before container start. Named volumes are managed by VolumesService.swift and provide persistent storage that survives container deletion, with automatic creation if the volume name does not exist.
How are anonymous volumes created when no source is specified?
When you specify type=volume without a src directive, Parser.swift triggers VolumeStorage.generateAnonymousVolumeName() to create a unique identifier. VolumesService.swift then provisions this storage automatically, as verified in Tests/CLITests/Subcommands/Volumes/TestCLIAnonymousVolumes.swift.
Can I use tmpfs mounts for temporary container storage?
Yes. Tmpfs mounts create memory-backed filesystems that do not persist after the container stops. Specify type=tmpfs with dst, size, and optional mode parameters. The parser rejects any src value for tmpfs mounts since they exist only in memory without host directory backing.
How does the runtime handle special mounts like /dev/shm?
RuntimeService.swift detects /dev/shm destinations during configuration and normalizes size options by removing existing size= entries and injecting the user-specified value. This ensures consistent shared memory sizing regardless of how the mount string was constructed.
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 →