SandboxConfig
SandboxConfig is a cluster-scoped CRD that describes the sandbox binaries
for one sandbox class (gvisor or microvm) as a list of versions. It keeps
binary selection out of both the worker image and the workload. A
WorkerPool resolves a SandboxConfig for its class,
and atelet fetches the assets (a gVisor release for gVisor, or a VMM,
virtiofsd, kernel, and guest image for a micro-VM). An ActorTemplate has no
say in which binaries an actor runs on.
The spec
The platform installs the gVisor config below, annotated as the class default.
apiVersion: ate.dev/v1kind: SandboxConfigmetadata: name: gvisor-default # cluster-scoped: no namespace annotations: sandboxconfig.ate.dev/is-class-default: "true"spec: sandboxClass: gvisor # gvisor (default) | microvm defaultVersion: v5 # the version new sandboxes boot with versions: - name: v5 state: Enabled # Enabled (default) | Disabled assets: # map[arch]map[name]AssetFile amd64: gvisor: url: gs://gvisor/releases/release/20261019.0/x86_64/gvisor.tar.zstd sha256: 8637abfb... # lower-case hex, 64 chars arm64: gvisor: url: gs://gvisor/releases/release/20261019.0/aarch64/gvisor.tar.zstd sha256: 88556c21...The spec has three fields, and each version carries its own assets.
sandboxClassis the runtime family this config applies to. A WorkerPool only uses configs whose class matches its own.defaultVersion(required) names the version that new and cold-booted actors start on. It must exist and can’t beDisabled.versions(1 to 16) holds the versions, each with a DNS-labelname, astate, andassetskeyed first by architecture (GOARCH, e.g.amd64,arm64) and then by asset name. Each asset has aurland asha256that both names the cached file and verifies the download.
Asset names are interpreted by the worker, and a ValidatingAdmissionPolicy
enforces each class’s set (shown in the table below) for every architecture
of every version. A config that’s missing one of its class’s assets is
rejected at admission.
| Class | Required assets |
|---|---|
gvisor | gvisor, the release tarball (runsc plus its helper binaries), which atelet extracts |
microvm | cloud-hypervisor, virtiofsd, kata-kernel, kata-image |
How it fits together
flowchart LR WP["WorkerPool<br/>sandboxClasses:<br/>- name: gvisor<br/> configRef?"] SC["SandboxConfig<br/>(cluster-scoped)<br/>versions[ ]"] ATELET["atelet<br/>fetch, hash, probe"] W["Worker<br/>default + restorable<br/>runtimes"] API["ate-api-server<br/>scheduler"] WP -- "configRef<br/>(else class default)" --> SC SC -- "url + sha256<br/>per version" --> ATELET ATELET -- "sandbox-runtimes.json" --> W W -- "SetWorkerSandboxRuntimes" --> API click WP "/concepts/workerpool/" "WorkerPool" click ATELET "/components/atelet/" "atelet" click W "/concepts/worker/" "Worker"
As the diagram above shows, a WorkerPool picks the config, and atelet turns its versions into runtimes. Each worker then reports those runtimes to the scheduler.
- A WorkerPool names a config with
spec.sandboxClasses[].configRef, or falls back to the class default, which is the newest SandboxConfig of that class annotatedsandboxconfig.ate.dev/is-class-default: "true". atecontroller records the result in the pool’s status, and while a pool’s status names a config, a finalizer keeps the config from being deleted. - atelet fetches each version’s assets for the node’s architecture through
the node’s object-store plugin, which serves its own backend’s scheme
(
gs://ors3://). Ags://URL the plugin can’t serve is read anonymously, which covers public buckets such asgs://gvisor. Every download is sha256-verified into a node-local content-addressed cache. - atelet hashes each version’s asset digests into a
sandbox_bundle_hashand probes the node (CPU features for gVisor, CPU vendor and model for a micro-VM). The default version becomes each worker’s default runtime, and the otherEnabledversions become restorable runtimes.
Versions and snapshots
A memory snapshot is stamped with the runtime it was taken on, and it restores its memory only on a worker that still offers that runtime. That’s the reason the config holds several versions instead of one.
- To upgrade, add a version and point
defaultVersionat it. New and cold-booted actors start on the new version, while snapshots taken on the old one still restore with their memory on any worker that keeps it as a restorable runtime. - Keep the previous version unless it has a known vulnerability. Removing it,
or marking it
Disabled, means snapshots taken on it can no longer resume with memory. Once such a snapshot is durable, the control plane falls back to restoring its rootfs and volumes and cold-booting the processes. - Changing the config rewrites what every worker in the affected pools advertises, spread over a short jitter so the fleet doesn’t re-register at once.
A micro-VM example
Unlike the gVisor config, the micro-VM config is opt-in. You assemble the asset set and stage it into a bucket the object-store plugin can serve, and then apply a config like this one. Asset URLs must sit outside any snapshot location, because the object-store plugin refuses to serve snapshot data as a sandbox asset.
apiVersion: ate.dev/v1kind: SandboxConfigmetadata: name: microvm annotations: sandboxconfig.ate.dev/is-class-default: "true"spec: sandboxClass: microvm defaultVersion: v2 versions: - name: v2 assets: amd64: cloud-hypervisor: { url: gs://my-bucket/kata-assets/cloud-hypervisor, sha256: ... } virtiofsd: { url: gs://my-bucket/kata-assets/virtiofsd, sha256: ... } kata-kernel: { url: gs://my-bucket/kata-assets/vmlinux, sha256: ... } kata-image: { url: gs://my-bucket/kata-assets/rootfs.img, sha256: ... }Related
- WorkerPool - resolves a SandboxConfig per class.
- atelet - fetches, caches, and probes the assets.
- Workers - how runtimes gate snapshot restores.