How Sandbox Resource Right-Sizing Works for Actors in Agent Substrate
Agent Substrate performs sandbox resource right-sizing by converting actor CPU and memory declarations into a SandboxSize struct, translating millicores to vCPUs, and embedding those constraints into the OCI specification before launching gVisor or micro-VM runtimes.
The agent-substrate/substrate repository provides a secure isolation layer for actors using either gVisor or micro-VM sandboxes. When actors declare resource requirements in their ActorTemplate, the system must translate those abstract limits into concrete cgroup constraints and hardware allocations. This examination of the internal/sizing package reveals how sandbox resource right-sizing unifies resource management across disparate runtime implementations.
Core Right-Sizing Logic in internal/sizing
The internal/sizing/sizing.go file defines the SandboxSize type and three critical methods that transform actor requirements into runtime constraints. When the RunWorkload or RestoreWorkload RPCs initiate an actor, the ateom process invokes these functions to prepare the container specification.
Converting Actor Limits with FromLimits
The FromLimits function builds a SandboxSize from the millicore and byte values received via RPC. It sanitizes input by clamping negative values to zero, treating them as unset rather than invalid.
// internal/sizing/sizing.go
func FromLimits(milliCPU, memoryBytes int64) SandboxSize { … }
When an actor template specifies 500 millicores and 256MB of memory, this function captures those values while ensuring no negative constraints propagate to the runtime.
Calculating Virtual CPU Requirements
The VCPUs method converts millicore limits into whole virtual CPUs required by micro-VM runtimes. It always rounds up fractional cores and guarantees a minimum allocation of one vCPU whenever any limit is set.
// internal/sizing/sizing.go
func (s SandboxSize) VCPUs() int { … }
This ensures that an actor requesting 1500 millicores receives exactly 2 vCPUs, while an actor requesting 100 millicores receives 1 vCPU rather than being rounded down to zero.
Writing Constraints to OCI Specifications
The ApplyToOCISpec method mutates the spec.Linux.Resources section of the OCI runtime specification. It writes CPU quota/period and memory limit values while leaving unset fields untouched, preserving existing defaults like Kata's device allowlist or CPU shares.
// internal/sizing/sizing.go
func (s SandboxSize) ApplyToOCISpec(spec *specs.Spec) { … }
This approach allows both runtimes to consume the same standardized resource representation without runtime-specific adaptations in the sizing logic.
Runtime Integration Paths
Both gVisor and micro-VM implementations rely on the shared internal/sizing package. They invoke ApplyToOCISpec at different stages of container initialization, ensuring the OCI specification contains the correct resource constraints before the sandbox runtime assumes control.
gVisor (runsc) Implementation
In cmd/ateom-gvisor/runsc.go, the ensureContainerCgroupsPath function reads the bundle's config.json, invokes ApplyToOCISpec, and writes the modified specification back to disk. The runsc binary then creates the per-container cgroup leaf using these values.
The --cpu-num-from-quota flag ensures the gVisor sandbox inherits the correct vCPU count derived from the OCI CPU quota.
// cmd/ateom-gvisor/runsc.go
r.size.ApplyToOCISpec(&spec) // ← right‑size cgroup
Micro-VM (Kata) Implementation
For micro-VMs, cmd/ateom-microvm/spec.go implements ensureKataCompatibleSpec. This function performs the same ApplyToOCISpec call before the kata-agent starts the VM. The VM's guest cgroup is then sized according to the limits, with the vCPU count derived from size.VCPUs().
// cmd/ateom-microvm/spec.go
size.ApplyToOCISpec(&spec) // ← right‑size guest cgroup
Summary
- Sandbox resource right-sizing begins with the
FromLimitsfunction ininternal/sizing/sizing.go, which sanitizes actor resource declarations into aSandboxSizestruct. - The
VCPUsmethod translates millicore requirements into whole virtual CPUs, rounding up and enforcing a minimum of one vCPU when limits are specified. ApplyToOCISpecwrites CPU and memory constraints into the standard OCIspec.Linux.Resourcessection, leaving unset values untouched to preserve runtime defaults.- Both gVisor (
cmd/ateom-gvisor/runsc.go) and micro-VM (cmd/ateom-microvm/spec.go) runtimes callApplyToOCISpecbefore initialization, ensuring consistent resource enforcement across sandbox technologies.
Frequently Asked Questions
How are negative resource limits handled in Agent Substrate?
The FromLimits function treats negative millicore or memory values as "unset" by clamping them to zero. This prevents invalid constraints from reaching the OCI specification while allowing actors to specify only one resource type (CPU or memory) if desired.
What is the minimum vCPU allocation for an actor?
When any CPU limit is specified, the VCPUs method guarantees a minimum allocation of one virtual CPU. This prevents micro-VMs from launching with zero capacity, ensuring the actor has sufficient compute resources to function even with minimal millicore requests.
Do gVisor and micro-VM runtimes use different resource sizing logic?
No. Both runtimes consume the same SandboxSize abstraction and call the identical ApplyToOCISpec method from internal/sizing. The difference lies in how each runtime consumes the OCI specification: gVisor configures host cgroups directly, while the micro-VM uses the limits to size the guest VM hardware and internal cgroups.
Where are resource limits stored during the actor lifecycle?
Resource limits originate in the actor's ActorTemplate, pass through the RunWorkload or RestoreWorkload RPCs to the ateom process, and are ultimately persisted in the OCI bundle's config.json via ApplyToOCISpec. Both runtimes read these values from the OCI specification when creating container cgroups or configuring VM hardware.
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 →