How to Create a Container Using Apple's Container Runtime: CLI and Swift Guide
To create a container using Apple's container runtime, use the container create command to generate a runtime configuration and VM bundle without starting the process, or instantiate a RuntimeClient in Swift to bootstrap the sandbox via XPC.
The apple/container repository provides a lightweight container runtime that runs Linux containers as virtual machines (VMs) on macOS using the Virtualization framework. When you create a container, the runtime builds a persistent bundle and establishes a sandboxed environment, keeping the container in a "created" state until you explicitly start it. This design allows you to inspect, configure, and modify container resources before any user process executes.
Understanding the Container Creation Architecture
Creating a container using Apple's runtime involves a multi-step flow that separates environment setup from process execution. The architecture leverages XPC services for secure communication between the CLI and the backend runtime.
The creation flow follows these steps:
- CLI request parsing – The
container createcommand, documented indocs/command-reference.md, collects user-specified options like CPU count, memory limits, and volume mounts. - Runtime configuration generation –
ContainersService.swiftconstructs aRuntimeConfigurationobject containing the VM bundle path, kernel image, filesystem layers, and network settings. - XPC service connection – The
RuntimeClient.create(id:runtime:)method inRuntimeClient.swiftestablishes a connection tocom.apple.container.runtime.<runtime>.<id>. - Sandbox bootstrap – The client sends a
bootstraprequest to the runtime service, which launches a macOS Virtualization framework VM and prepares the root filesystem. - Persistent state – The container receives a unique ID and stores its configuration on disk, remaining in a created (stopped) state until started.
This separation of creation and startup allows you to use container inspect to review the configuration or adjust mounts before the container runs.
Creating Containers from the Command Line
Basic Syntax and Key Options
The container create command generates a VM-based sandbox without immediately executing a containerized process. According to the command reference in docs/command-reference.md, you can specify resource constraints and runtime behavior using these key options:
--name <name>– Assign a human-readable identifier that serves as the container ID.--cpu <cpus>– Allocate a specific number of virtual CPUs to the VM.--memory <memory>– Set RAM allocation (e.g.,2Gfor 2 gigabytes).--runtime <runtime>– Select a runtime plugin; defaults tocontainer-runtime-linux.--init– Enable an init process that handles signal forwarding and zombie reaping.--volume <volume>– Bind-mount host directories or named volumes into the container.--publish <spec>– Map container ports to the host system.
Practical CLI Examples
Create a container named "my-app" with specific resource constraints:
# Create a container from the Ubuntu image with 2GB RAM and 2 CPUs
container create \
--name my-app \
--memory 2G \
--cpu 2 \
ubuntu:latest
This command outputs a unique container ID (e.g., a1b2c3d4e5f6) and stores the VM bundle on disk. The container exists in a stopped state, ready for inspection or modification.
Start the created container later:
container start my-app
Alternatively, combine creation and startup in one step using container run, though this bypasses the ability to inspect the sandbox beforehand.
Creating Containers Programmatically with Swift
For applications requiring direct integration with the container runtime, you can create containers programmatically using the Swift APIs provided in the Sources/Services/Runtime/RuntimeClient/ directory.
Building the Runtime Configuration
First, construct a RuntimeConfiguration object that describes the VM environment. This mirrors the configuration generation performed by ContainersService.swift when processing CLI requests:
import Container
// Configure the VM bundle and filesystem
let runtimeConfig = RuntimeConfiguration(
path: URL(fileURLWithPath: "/tmp/container-bundle"),
initialFilesystem: "ubuntu:latest",
kernel: nil,
containerConfiguration: nil,
containerRootFilesystem: nil,
options: nil
)
// Serialize to JSON for the runtime service
try runtimeConfig.writeRuntimeConfiguration()
The RuntimeConfiguration struct, defined in Sources/Services/Runtime/RuntimeClient/RuntimeConfiguration.swift, handles JSON serialization and validates the bundle structure before the XPC connection occurs.
Bootstrapping via the RuntimeClient
After configuring the environment, establish an XPC connection and bootstrap the sandbox:
// Initialize the XPC client for the Linux runtime
let client = try await RuntimeClient.create(
id: "swift-example",
runtime: "container-runtime-linux"
)
// Bootstrap the VM without starting a user process
await client.bootstrap(
stdio: .inherit,
networkBootstrapInfos: [],
dynamicEnv: [:]
)
The RuntimeClient.create(id:runtime:) method, implemented in Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift, creates the XPC endpoint. The bootstrap method launches the Virtualization framework VM and prepares the root filesystem, leaving the container ready for a subsequent client.start(...) call.
Verifying and Managing Created Containers
Once created, containers persist on disk with their configuration files and VM bundles. Verify the creation status using the following commands:
# List all containers, including created but not running
container ls
# Inspect detailed configuration including bundle path and resources
container inspect my-app
The container inspect command outputs JSON containing the runtime configuration, mount points, and network settings defined during creation. This allows you to confirm that Sources/Services/ContainerAPIService/Server/Containers/ContainersService.swift correctly processed your resource limits and volume mounts before starting the container.
Summary
- Apple's container runtime runs Linux containers as lightweight VMs on macOS using the Virtualization framework.
- Creation vs. Execution – The
container createcommand andRuntimeClient.bootstrapmethod establish the sandbox without starting a user process, allowing pre-execution configuration. - Key Implementation Files – Container creation logic resides in
ContainersService.swift, XPC client communication inRuntimeClient.swift, and configuration serialization inRuntimeConfiguration.swift. - CLI Options – Specify resources using
--cpu,--memory, and--volumeflags documented indocs/command-reference.md. - Programmatic Access – Use
RuntimeConfigurationandRuntimeClientSwift APIs to integrate container creation into macOS applications.
Frequently Asked Questions
What is the difference between container create and container run?
container create generates a runtime configuration and VM bundle but leaves the container in a stopped state, allowing you to inspect or modify it before execution. container run combines creation and startup, immediately executing the containerized process without an intermediate inspection phase.
Where does Apple's container runtime store VM bundles and configuration?
The runtime stores container bundles in a directory specified by the RuntimeConfiguration.path property, typically within the macOS temporary directory or a user-specified location. The container inspect command reveals the exact bundle path and serialized JSON configuration for each container ID.
Can I create containers without using the command-line interface?
Yes, you can create containers programmatically by importing the Container framework and using RuntimeClient.create(id:runtime:) to establish an XPC connection to com.apple.container.runtime.<runtime>.<id>, then calling bootstrap to initialize the VM sandbox. This approach is implemented in Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift.
Why does the container runtime use XPC services for container creation?
The XPC architecture isolates the privileged Virtualization framework operations in a separate service process (container-runtime-linux), enhancing security by restricting the CLI's access to low-level VM management. The RuntimeClient in the CLI communicates with this service to request VM creation and resource allocation.
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 →