How Container Manages Resource Limits and Monitors Usage with Stats: A Complete Guide
Container uses a declarative Resources struct to define CPU, memory, and storage limits, propagates them to the runtime daemon for cgroup enforcement, and exposes live usage metrics through a dedicated stats endpoint.
The apple/container repository provides a lightweight sandboxing framework for isolating workloads on macOS and Linux. Understanding how to constrain compute resources and observe consumption patterns is critical for production deployments. This guide examines the data-driven model that translates high-level configuration into kernel-enforced limits while providing real-time observability via HTTP routes.
Defining Resource Limits in ContainerConfiguration
The foundation of resource management lies in the ContainerConfiguration.Resources struct defined in Sources/ContainerResource/Container/ContainerConfiguration.swift. This Codable structure allows developers to specify compute constraints through JSON, YAML, or native Swift code.
The Resources Struct Fields
The struct exposes four key parameters that control sandbox consumption:
cpus– Integer count of virtual CPU cores allocated to the sandbox.memoryInBytes– RAM limit expressed as an integer in bytes.storage– Optional persistent storage quota for the container filesystem.cpuOverhead– Additional cores reserved for VM overhead, such as guest agents and hypervisor processes.
Default Values and Configuration Sources
When unspecified, the framework applies sensible defaults: 4 CPU cores, 1 GiB of RAM, and 1 overhead core. Because the struct conforms to Codable, limits can be injected via configuration files, CLI flags, or programmatically in Swift before sandbox creation.
Propagating Limits to the Runtime Daemon
Configuration declarations transition to enforced limits through the runtime service layer. In Sources/Services/RuntimeLinux/Server/RuntimeService.swift, the container runtime constructs a low-level configuration object that maps directly to cgroup parameters.
The translation occurs through direct assignment to the czConfig object:
// RuntimeLinux/Server/RuntimeService.swift
czConfig.cpus = config.resources.cpus
czConfig.cpuOverhead = config.resources.cpuOverhead
czConfig.memoryInBytes = config.resources.memoryInBytes
The underlying Apple-Linux container-runtime daemon receives these values and configures the appropriate cgroup or hypervisor settings. This ensures the sandbox cannot exceed its allocated resources for the duration of its lifecycle.
Monitoring Usage with the Stats Endpoint
Live resource consumption is exposed through a dedicated HTTP route defined in Sources/Services/Runtime/RuntimeClient/RuntimeRoutes.swift. The runtime daemon collects per-sandbox metrics from operating system interfaces—primarily cgroup files on Linux—and returns them as structured JSON.
// Services/Runtime/RuntimeClient/RuntimeRoutes.swift
/// Get resource usage statistics for the sandbox.
/// Returns a `SandboxStats` JSON payload.
The SandboxStats Model
The response payload decodes into a SandboxStats model containing:
- CPU utilization percentages.
- Memory RSS (resident set size) and working-set size.
- I/O read/write counters.
These metrics reflect actual consumption against the declared limits, enabling capacity planning and runtime observability.
Querying Stats Programmatically
Swift clients retrieve statistics through the asynchronous API. The following example demonstrates configuring resources, launching a sandbox, and querying live metrics:
import ContainerResource
import ContainerAPI
// 1️⃣ Build a configuration with explicit limits
let resources = ContainerConfiguration.Resources(
cpus: 2,
memoryInBytes: 512.mib(), // 512 MiB
storage: 5.gib(), // 5 GiB persistent storage
cpuOverhead: 1
)
let cfg = ContainerConfiguration(
id: "my-app",
image: ImageDescription(name: "my-app:latest"),
process: ProcessConfiguration(entrypoint: ["/usr/bin/my-app"])
)
cfg.resources = resources // inject the limits
// 2️⃣ Launch the sandbox
let client = try await ContainerClient()
let sandbox = try await client.createSandbox(with: cfg)
// 3️⃣ Query live statistics
let stats = try await client.getStats(for: sandbox.id)
print("CPU %:", stats.cpuPercent)
print("Memory used:", stats.memoryUsage.bytes, "bytes")
print("IO read:", stats.ioRead.bytes, "bytes")
CLI Equivalent
For command-line workflows, the container CLI exposes flags that map directly to the same configuration struct:
# Create a container with explicit limits
container run \
--cpus 2 \
--memory 512m \
--storage 5g \
my-app:latest
# Retrieve live stats
container stats my-app
Machine-Level Resource Management
For container-machine objects, the framework mirrors this pattern using MachineResources defined in Sources/Services/MachineAPIService/Client/MachineBundle.swift. Machine creation APIs forward these limits to the runtime identically, and the same stats endpoint can be queried for a machine’s sandbox.
Summary
- Resource limits are declared through the
ContainerConfiguration.Resourcesstruct inContainerConfiguration.swift, supporting CPU, memory, storage, and overhead parameters. - Runtime enforcement occurs when
RuntimeService.swiftmaps configuration values to theczConfigobject, which the daemon translates into cgroup constraints. - Live monitoring is available via the stats endpoint defined in
RuntimeRoutes.swift, returningSandboxStatswith CPU, memory, and I/O metrics gathered from cgroup files. - Machine sandboxes use an identical resource model via
MachineBundle.swift, ensuring consistent behavior across standard containers and virtual machines.
Frequently Asked Questions
How do I set resource limits when creating a container?
You define a ContainerConfiguration.Resources struct with your desired cpus, memoryInBytes, storage, and cpuOverhead values, then assign it to your configuration's resources property before calling createSandbox. Alternatively, use the CLI flags --cpus, --memory, and --storage with the container run command according to the apple/container source code.
What metrics are available through the Container stats endpoint?
The SandboxStats model returned by the stats endpoint provides CPU utilization percentages, memory RSS (resident set size), working-set size, and I/O read/write counters. These metrics are gathered from cgroup files on Linux and exposed through the HTTP route defined in RuntimeRoutes.swift.
Where does Container enforce the resource limits?
Enforcement occurs in the underlying Apple-Linux container-runtime daemon. When RuntimeService.swift copies resource values to the czConfig object, the daemon translates these into appropriate cgroup or hypervisor settings that kernel-enforce the constraints for the entire sandbox lifecycle.
Do container machines use the same resource management approach?
Yes. Container machines utilize the MachineResources struct in MachineBundle.swift, which mirrors the standard Resources model. These limits propagate to the runtime identically, and you query machine statistics using the same getStats endpoint and CLI commands.
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 →