Use cases
Outcomes that map to shipping features — nothing aspirational.
FluxVM is a Rust-native VM control plane: create and manage isolated
virtual machines backed by QEMU/KVM, Cloud Hypervisor, Firecracker, or the
in-tree FluxVM hypervisor. Short-lived / disposable patterns (optional
ttl_seconds, cheap CoW clones) are supported but not required. This doc
walks through use cases that map onto what's actually implemented (see the
main documentation index for the full feature list) —
nothing here is aspirational.
FluxVM CI/CD build and test runners
Spin up a real VM per job, run the job inside it over vsock exec (no SSH,
no network path needed at all), and let ttl_seconds guarantee cleanup even
if the job crashes or the runner disappears mid-job.
cat > ci-job.json <<'JSON'
{
"name": "ci-job-4821",
"backend": "firecracker",
"image": "/var/lib/fluxvm/images/ci-runner.raw",
"vcpus": 2,
"memory_mib": 2048,
"network": {"mode": "none"},
"ttl_seconds": 900,
"agent": {"enabled": true, "port": 5000}
}
JSON
id=$(fluxctl create --spec ci-job.json | jq -r .id)
fluxctl exec "$id" -- ./run-tests.sh
Firecracker's jailer (chroot + uid/gid drop, see "Firecracker jailer" in the
README) gives each job its own privilege-dropped sandbox, and cgroup v2
resource control caps what a single job can consume on a shared runner host.
network.mode: "none" plus vsock exec means a compromised or malicious
test suite has no network path out at all — the same isolation shape as
gVisor/Firecracker-based CI sandboxes, built on this project's own control
plane instead of a hosted service.
Golden-image pipeline
Build a customized, versioned base image once — package installs, hostname, SSH keys, a baked-in agent binary — and reuse it across every VM you create from it, instead of provisioning each VM from scratch at boot time.
cat > golden-image.json <<'JSON'
{
"source": "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img",
"sha256": "...",
"output": "/var/lib/fluxvm/images/team-golden-v12.qcow2",
"packages": ["docker.io", "jq", "qemu-guest-agent"],
"commands": ["systemctl enable docker"],
"enable_services": ["qemu-guest-agent"]
}
JSON
sudo fluxctl build-image --spec golden-image.json
See docs/build-image-tutorials.md for the same
walkthrough across Debian/Ubuntu, RHEL-family, Arch, and Windows
(windows{} + Zyvor GuestKit agent) base images. Pair it
with the image catalog (SHA-256 + optional Ed25519 signing, see "Image
catalog & signing" in operations.md) to give every VM a provenance guarantee —
allowed_image_dirs and trusted_signers mean a tenant can reference an
image by name and have the daemon refuse anything that isn't a known,
signed entry.
Kubernetes-native VM workloads (DisposableVm)
For teams already running Kubernetes who want a real VM (not a container)
for a specific workload — untrusted code, a kernel-dependent test, a legacy
binary — the DisposableVm CRD plus the node-local fluxvm-kube operator
lets a VM be requested the same way any other Kubernetes resource is.
Product path: Ragnarok creates those CRs from its FluxVM Hub (with OIDC/SSO and RBAC). Install FluxVM first, then Ragnarok — see docs/ragnarok.md.
apiVersion: fluxvm.zyvor.io/v1
kind: DisposableVm
metadata:
name: untrusted-job-7
spec:
node: worker-3
backend: firecracker
image: /var/lib/fluxvm/images/sandbox.raw
vcpus: 1
memoryMib: 1024
networkMode: none
ttlSeconds: 600
kubectl delete disposablevm blocks on a finalizer until the real VM is
actually gone (no leaked QEMU/Firecracker process), and the operator
self-heals — if the underlying VM disappears out-of-band, it gets replaced
automatically without touching the CR. This is verified against a real k3s
cluster, not just unit-tested against a fake API server (see "Kubernetes
CRD/operator" in kubernetes-operator.md).
Secure Containers (OCI in a FluxVM)
For workloads that still look like containers to Kubernetes/ctr, but need a
per-Pod guest kernel instead of sharing the node kernel, FluxVM Secure
Containers maps a containerd task group onto one QEMU FluxVM
(runtime io.containerd.fluxvm.v2, RuntimeClass handler fluxvm).
Set 2 adds optional CNI L2 (guest gets the real Pod IP when a CRI netns exists)
and guest cgroup-v2 stats/resource updates. Set 3 adds containerd task events and
guest OCI process hardening. Set 4 adds Pod-UID write-through volumes and guest
RO/masked paths/devices/sysctls/libseccomp. Set 5 adds VSOCK stdio streaming and
real guest PTY/ResizePty. Status: GA. Scope boundaries remain (e.g. hostPath
hotplug, QEMU-only VMM) — see Current limitations in
docs/secure-containers.md. Full design:
docs/secure-containers.md,
Set 3,
Set 4,
Set 5. Deploy fragment:
deploy/containerd/.
sudo ./scripts/install-secure-containers.sh
# merge deploy/containerd/fluxvm-runtime.toml into containerd config, then:
ctr run --rm --runtime io.containerd.fluxvm.v2 docker.io/library/busybox:1.36 smoke /bin/echo ok
Multi-host fleets without Kubernetes
Not every team wants a Kubernetes control plane just to spread disposable
VMs across a handful of bare-metal or edge hosts. fluxvm-agent is a
lighter-weight alternative: a central fleet registry plus a per-host
heartbeat client, with load-aware placement deciding which host a new VM
request lands on — verified across two real, physically separate hosts.
This fits edge deployments, colo racks, or any fleet where standing up a
full Kubernetes cluster is disproportionate to the actual workload.
Sandboxed / untrusted code execution
The combination that makes FluxVM suitable for running code you don't trust:
- Firecracker jailer — chroot + uid/gid drop, so even a Firecracker process compromise doesn't hand over root on the host.
- cgroup v2 resource control — hard caps on CPU/memory/IO per VM.
- Network namespaces and
network.mode: "none"— no network path out of the guest at all when the workload doesn't need one. - vsock exec — get output back from the guest without opening any network port, SSH included.
- TTL reaper — a VM that's forgotten about (crashed harness, orphaned job) gets torn down anyway.
This is the same isolation shape used for malware analysis sandboxes, "run this untrusted PR's code" CI steps, and multi-tenant code-execution products — built from primitives this project already has, not a separate product.
For how that compares to a full AI-agent sandbox product (tens-of-ms snapshot
boot, egress vault, AutoPause), see
docs/agent-sandbox-gaps.md. The FluxVm backend
(backend: "flux-vm") is the agent-sandbox track: memory snapshots, /v1/sandboxes,
guest HTTP proxy with AutoResume, L7 egress, /console, and an optional native
TC/eBPF Network Fabric (GA; dataplane schema v4) (nftables default; IPv4/IPv6 L3+L4, rate
limits, security groups / CNP, Cilium coexistence without mutating Cilium
maps — docs/network-fabric.md,
docs/network-groups.md,
docs/network-policy.md,
docs/production-dataplane.md,
docs/ebpf-cilium.md).
Ephemeral / disposable dev/test environments
Give every branch, PR, or engineer their own real VM — not a shared
staging box — with automatic cleanup via ttl_seconds so nothing lingers
past its usefulness. QEMU's qcow2 copy-on-write overlays mean spinning up a
new VM from a golden image is cheap (no full disk copy), and pause/resume
let you park an environment instead of destroying and rebuilding it if
someone steps away mid-session.
Bring-your-own storage backend
Beyond the default qcow2/raw overlay, FluxVM supports LVM thin snapshots, NBD-exported disks, and Ceph RBD as storage backends for VM disks — Ceph RBD verified against a real Rook Ceph cluster. This matters if you're deploying into infrastructure that already standardized on one of these (a SAN exposed over NBD, an existing Ceph cluster, LVM thin pools on local NVMe) instead of adopting a new storage layer just for VM disks.
Networking that matches the environment, not a fixed default
- QEMU user-mode NAT — zero host config, good for a single dev machine.
- TAP + Linux bridge — a VM on the same L2 as the host, for lab/test networks that need real bridged connectivity.
- macvtap — a VM's own MAC address directly on a parent link (no bridge), for environments where the VM needs to look like an independent host on the physical network.
- Bridge-less direct (opt-in) — an eBPF redirect between the VM's tap and a physical uplink (or a Pod's veth) instead of a bridge, with FluxVM policy applied first (direct-datapath.md).
The first three are SSH-verified end-to-end in this project's own regression tests, not just configured-and-hoped-for. The direct mode is verified in network-namespace tests on a real kernel with a userspace guest, not yet end to end with a real guest.