How to Configure Memory and CPU for Containers in Apple's Container Runtime
Configure memory and CPU for containers using command-line flags (--cpus, --memory), the config.toml configuration file, or the Swift API, with defaults defined in ContainerSystemConfig.swift and validated at runtime in ContainersService.swift.
The apple/container repository provides a Swift-based container runtime that allows precise control over resource allocation. Understanding how to configure memory and CPU settings ensures optimal performance for both development environments and production workloads.
Configuration Layers
The container runtime applies CPU and memory settings through three distinct layers, defined in ContainerSystemConfig.swift and enforced across the system.
Default Values
When no overrides are specified, the runtime uses hard-coded defaults defined in the ContainerConfig and BuildConfig structs within Sources/ContainerPersistence/ContainerSystemConfig.swift. Regular containers default to 4 CPUs and "1g" (1 GiB) of memory, while the builder VM defaults to 2 CPUs and "2048mb" (2 GiB) of memory.
These values are loaded from the [container] and [build] sections of the config.toml file if present, falling back to the code-defined constants when keys are missing.
Command-Line Overrides
Per-container overrides take precedence through the --cpus and --memory flags. In Sources/Services/ContainerAPIService/Client/Flags.swift, the Resource struct parses these flags as Int64? and String? respectively. The Parser.swift file then converts memory strings to byte counts using Parser.memoryStringAsMiB and Parser.memoryStringAsBytes, which rely on Measurement.parse from Measurement+Parse.swift.
Runtime Validation
Before launching, ContainersService.swift validates that requested memory meets the minimum threshold of 200 MiB. If configuration.resources.memoryInBytes is below this value, the service returns an explicit error and prevents container creation.
Memory Format Specification
Memory values use a MemorySize format parsed by Measurement.parse in Sources/ContainerPersistence/Measurement+Parse.swift. The format accepts binary units (powers of 1024) with these case-insensitive suffixes:
"b"– bytes"k"– KiB (1024 bytes)"mb"– MiB (1024 KiB)"g"– GiB (1024 MiB)"t"– TiB (1024 GiB)
Plain integers without suffixes are interpreted as bytes. For example, "4g" converts to approximately 4,294,967,296 bytes (4 × 1024³).
CPU Handling
CPU allocation uses plain integers representing virtual CPUs. The --cpus flag maps directly to an Int64 value with no unit suffix required. The system stores this as configuration.resources.cpus and applies it to the container's cgroup limits. Unlike memory, CPU values undergo only basic integer parsing without additional runtime validation beyond type checking.
Practical Configuration Examples
1. Command-Line Resource Allocation
Use the --cpus and --memory flags to set resources for a specific container run:
container run --cpus 2 --memory 4g myimage:latest
This command allocates 2 vCPUs and 4 GiB of RAM, overriding any default settings.
2. Permanent Defaults in config.toml
Set system-wide defaults by editing $HOME/.config/container/config.toml:
[container]
cpus = 6
memory = "8g"
[build]
cpus = 4
memory = "4096mb"
The runtime reads this file via ContainerSystemConfig, applying these values to all new containers and builder VMs unless overridden by flags.
3. Swift API Configuration
Programmatically configure resources using the ContainerAPI module:
import ContainerAPI
let resources = Resources(
cpus: 3,
memoryInBytes: try MemorySize("2g").measurement.converted(to: .bytes).value
)
let config = ContainerConfiguration(resources: resources)
try client.create(config)
The MemorySize initializer uses the same parsing logic as the CLI, ensuring consistency between programmatic and command-line interfaces.
4. Inspecting Resource Usage
Monitor actual resource consumption against configured limits:
container stats mycontainer
Output displays current CPU percentage and memory usage against limits (e.g., Memory usage: 1.2 GiB / 8 GiB), sourced from ContainerStats.swift which tracks memoryUsageBytes and memoryLimitBytes.
Summary
- Defaults: 4 CPUs and 1 GiB memory for containers, 2 CPUs and 2 GiB for builder VMs, defined in
ContainerSystemConfig.swift - Configuration methods: Command-line flags (
--cpus,--memory),config.tomlsettings, or Swift APIResourcesstruct - Memory format: Binary units (b, k, mb, g, t) parsed by
Measurement.parsewith a 200 MiB minimum enforced byContainersService.swift - CPU format: Plain integers representing vCPUs, stored as
Int64without additional validation
Frequently Asked Questions
What is the minimum memory requirement for containers?
The runtime enforces a minimum memory allocation of 200 MiB (approximately 209,715,200 bytes). If you specify a value below this threshold through any configuration method, ContainersService.swift rejects the request with a validation error before creating the container.
How does the memory suffix parsing work in container configuration?
The runtime uses Measurement.parse from Measurement+Parse.swift to interpret memory strings as binary units (powers of 1024). Suffixes are case-insensitive: "k" represents KiB, "mb" represents MiB, "g" represents GiB, and "t" represents TiB. Plain integers without suffixes are interpreted as raw bytes, ensuring flexibility across different configuration interfaces.
Where are the default CPU and memory values defined?
Default values reside in Sources/ContainerPersistence/ContainerSystemConfig.swift within the ContainerConfig and BuildConfig structs. Regular containers default to 4 CPUs and "1g" memory, while the builder VM uses 2 CPUs and "2048mb" memory. These hard-coded values serve as fallbacks when the config.toml file lacks explicit entries or when command-line flags are omitted.
Can I configure resources programmatically instead of using CLI flags?
Yes, the Swift API exposed in ContainerAPI allows direct configuration of the Resources struct. You can specify CPU counts as integers and memory as parsed MemorySize objects converted to bytes. This approach uses the same underlying validation and parsing logic as the command-line interface, ensuring consistent behavior across automation scripts and manual operations.
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 →