How Apple Container Implements Read‑Only Root Filesystems and tmpfs Mounts
Apple Container enables read‑only root filesystems and tmpfs mounts by translating CLI flags into OCI runtime specifications, delegating actual mount operations to the Linux kernel through runc‑compatible runtimes.
Apple Container is a Swift‑based container runtime developed by Apple that constructs OCI‑compliant container specifications for Linux environments. Understanding how it handles read‑only root filesystems and tmpfs mounts requires tracing the path from CLI argument parsing through the configuration model to the final runtime execution in RuntimeService.swift.
CLI Flag Parsing for Read‑Only and tmpfs Options
The implementation begins at the command line interface, where two distinct flags control these features.
In Sources/Services/ContainerAPIService/Client/Flags.swift, the tool defines:
@Flag(name: .long)for--read‑only(or-r), which mounts the container's root filesystem as read‑only@Option(name: .customLong("tmpfs"))for--tmpfs <path>, which adds a tmpfs mount at the specified container path
These values are stored in a ContainerManagement struct that merges into the final ContainerConfiguration.
Read‑Only Root Filesystem Implementation
Configuration Storage
The ContainerConfiguration struct in Sources/ContainerResource/Container/ContainerConfiguration.swift contains a readOnly: Bool property. When the --read‑only flag is present, this Boolean is set to true and persisted in the container's configuration state.
OCI Runtime Translation
When the container launches, Sources/Services/RuntimeLinux/Server/RuntimeService.swift assembles the OCI specification. If configuration.readOnly is true, the runtime sets the OCI root.readonly field to true, producing JSON similar to:
"root": {
"path": "/path/to/rootfs",
"readonly": true
}
The OCI runtime (such as runc) then mounts the root filesystem with the MS_RDONLY kernel flag. Any write operation to the root filesystem (for example, touch /newfile) fails with the EROFS (Read‑only filesystem) error.
tmpfs Mount Implementation
Parsing Arguments into Filesystem Objects
The --tmpfs flag is processed by Parser.tmpfsMounts(_:) in Sources/Services/ContainerAPIService/Client/Parser.swift (lines 340‑353). This method converts each supplied path into a Filesystem object of type .tmpfs.
Filesystem Model Definition
The Filesystem enum in Sources/ContainerResource/Container/Filesystem.swift defines the .tmpfs case with a static constructor Filesystem.tmpfs(destination:options:). This constructor automatically sets source: "tmpfs" and type: .tmpfs, creating a complete mount specification that is appended to ContainerConfiguration.mounts.
Runtime Integration
In Sources/Services/RuntimeLinux/Server/RuntimeService.swift (lines 1344‑1349), the mount list is iterated during container creation. For each entry where type == .tmpfs, the runtime emits an OCI mount entry:
{
"destination": "/tmp",
"type": "tmpfs",
"source": "tmpfs",
"options": []
}
The Linux kernel creates an anonymous tmpfs filesystem at the specified mount point. This in‑memory filesystem is writable during the container's lifetime but disappears completely when the container exits, never touching the underlying host storage.
Practical Usage Examples
The following Swift code demonstrates how to invoke these features via the Apple Container API:
// Enable a read-only root filesystem
let runArgs = ["--read-only"]
try container.run(name: "demo", image: "ubuntu:22.04", args: runArgs)
// Add a tmpfs mount at /tmp
let runArgs = ["--tmpfs", "/tmp"]
try container.run(name: "demo", image: "ubuntu:22.04", args: runArgs)
// Combine both for a read-only base with writable scratch space
let runArgs = ["--read-only", "--tmpfs", "/tmp", "--tmpfs", "/var/cache"]
try container.run(name: "demo", image: "ubuntu:22.04", args: runArgs)
Summary
- Apple Container delegates mount operations to the OCI runtime by constructing compliant specifications in
RuntimeService.swift. - Read‑only roots are enforced via the OCI
root.readonlyfield, which triggers theMS_RDONLYkernel flag. - tmpfs mounts are defined in
Filesystem.swiftand parsed viaParser.tmpfsMounts(), resulting in anonymous memory filesystems that vanish on container exit. - Both features can be combined to create secure, ephemeral container environments with immutable base images and temporary writable overlays.
Frequently Asked Questions
How do I enable a read‑only root filesystem in Apple Container?
Use the --read‑only or -r flag when running a container. This sets ContainerConfiguration.readOnly to true, which translates to the OCI root.readonly field and ultimately mounts the root filesystem with kernel‑level read‑only protection.
Where does Apple Container store tmpfs mount configurations?
tmpfs mounts are stored in the mounts: [Filesystem] array within ContainerConfiguration.swift. Each mount is represented as a Filesystem.tmpfs object created by Parser.tmpfsMounts(_:) in Parser.swift.
What happens if I try to write to a read‑only root filesystem?
The kernel returns an EROFS (Read‑only filesystem) error. The OCI runtime configures the mount with the MS_RDONLY flag, preventing any write operations to the root filesystem regardless of user permissions.
Can I use multiple tmpfs mounts with a read‑only root?
Yes. You can specify --tmpfs multiple times for different paths (for example, --tmpfs /tmp --tmpfs /var/run) simultaneously with --read‑only. This creates a secure configuration where the base image cannot be modified, but specific directories provide writable, ephemeral scratch space.
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 →