Firecracker runner executor
Vetrix's Firecracker executor runs untrusted workloads — fork-PR refs and
workflows that declare slsa: L3 — in an ephemeral microVM. The executor
lives in cmd/worker/firecracker_executor.go and is selected per runner
group via the isolation_kind='firecracker' column on the runner groups
table.
When a job is forced onto a Firecracker runner
The engine evaluates the job's IsolationSpec at dispatch time
(internal/cicd/isolation.go). Any job that meets one of these
conditions is required to run on a Firecracker runner:
| Trigger | Additional requirement |
|---|---|
| Fork-PR ref | Runner isolation_kind='firecracker' |
slsa: L3 workflow |
Firecracker and a dedicated signing daemon |
If no reachable runner group satisfies the tier the engine leaves the run
queued and surfaces the stable reason string
isolation_requirement_unsatisfied. The reason is recorded verbatim on
the run row and exposed through the dashboard.
VM lifecycle
Per job:
- Allocate a private vsock pair and a copy-on-write overlay of the base rootfs image.
- Boot the microVM with the per-job CPU millis and memory MiB caps from
the runner group (
runner_groups.cpu_millis,runner_groups.mem_mib). Boot must land underMaxBootBudget(default 500 ms, p99) or the job fails fast with reasonboot_budget_exceeded. - Execute the job's commands through the in-guest init; stream stdout and stderr line-by-line to the log sink.
- Teardown: power off, wipe the COW overlay, release vsock ports.
Image management
runs-on: [linux, self-hosted, firecracker] tag matching resolves to one
of the rootfs images staged on the host under
FirecrackerExecutorConfig.RootfsDir. The default mapping translates
alpine:3.19 to <dir>/alpine_3.19.ext4; operators override this with
RootfsLookup when they maintain custom naming.
Image references are admitted only if at least one regex in
FirecrackerExecutorConfig.ImageAllowlist matches the full reference
string. An empty allowlist blocks every image — fork-PR refs must never
run under an unrestricted allowlist. Trusted refs may use .* to accept
any seeded rootfs.
Network posture
| Ref class | Allowlist applied |
|---|---|
| Trusted (non-fork) | NetworkAllowlist + ControlPlaneEndpoints |
| Fork-PR | ControlPlaneEndpoints only (user allowlist is suppressed) |
DNS lookups are forwarded through the runner host resolver; the VM never
sees cluster DNS directly. The cloud-metadata endpoint
(169.254.169.254) is never reachable.
Resource caps
FirecrackerExecutorConfig.DefaultCPUMillis / DefaultMemMiB are the
per-VM caps when the job does not supply its own. OOM kills surface as a
job failure with reason oom_killed and the masked stdout convention
(exit 137).
Metrics
Exposed through FirecrackerExecutor.Metrics() and read by the admin
dashboard:
| Name | Shape | Meaning |
|---|---|---|
vetrix_firecracker_boot_ms |
histogram | Rolling ring of the last 128 boots. |
vetrix_firecracker_vm_alive_count |
gauge | Live VMs managed by this executor. |
vetrix_firecracker_teardown_ms |
histogram | Rolling ring of the last 128 tears. |
Testing the executor without a kernel
The executor delegates VM lifecycle to a vmBackend interface. Tests
inject a fake backend that records the job's behaviour (boot latency,
per-VM file writes, exec hooks) and verify every acceptance criterion
without a live kernel. See cmd/worker/firecracker_executor_test.go.