This episode covers microVM scaling: reaching thousands of microVMs per host with a jailer per VM, cgroup v2, page cache sharing, and memory overcommit via balloon, plus the operational practices of a daemon per microVM, health checks, and snapshot garbage collection.

In episode 18 we saw the products standing on Firecracker — they all boil down to one economic question: how many microVMs can live on a single host? Episode 19 covers scaling: the techniques that make densities of thousands of microVMs per host possible, and the operational discipline that keeps them healthy.
Why is this episode important? Firecracker exists to make that high density possible — a 125 ms boot and < 5 MiB overhead only mean something if hundreds or even thousands of VMs can share one host. This is the episode where those numbers translate into real capacity, with honest trade-offs.
A modern server host (e.g. 192 vCPUs, 512 GB RAM) can hold how many microVMs? Let's calculate with the data we have:
The limiting factors aren't just RAM: there are vCPUs, page cache, I/O, and kernel limits (number of fds, threads, inotify). Realistic density is determined by load testing (episode 16), not paper calculations.
Every microVM runs through the jailer with a unique --id (episode 7). The per-jailer overhead is small — a few processes and a cgroup — but its value is large:
<id> chroot is a clean way to release all resources.At the thousands scale, good habits become mandatory: never skip the jailer "for speed." Code managing thousands of VMs without a jailer is an accident waiting to happen.
At high density, a single leaking VM can exhaust the host. cgroup v2 gives structured control:
mkdir -p /sys/fs/cgroup/fc/vm-001
echo 536870912 > /sys/fs/cgroup/fc/vm-001/memory.max
echo 500000 100000 > /sys/fs/cgroup/fc/vm-001/cpu.max
echo <pid> > /sys/fs/cgroup/fc/vm-001/cgroup.procsIn cgroup v2, there's one bonus important for density: more precise memory control, including swap limits and page cache accounting. With per-VM limits, a greedy VM doesn't take down the host — it hits its own limit.
This is one of the highest-impact density techniques. When many VMs use the same rootfs, the host kernel stores the same file pages once in the page cache — and all VMs share them.
cat /proc/meminfo | grep -i cachedFor maximum sharing:
This is where episode 8's image decisions meet host economics: the same, read-only, lightweight image = more VMs per host.
The balloon (episode 10) adds another dimension: promised memory isn't always used. A smart orchestrator uses balloon statistics to overcommit:
mem_size_mib larger than typical needs.deflate_on_oom as a safety net).Overcommit increases the number of VMs you can promise — with a risk: if all VMs need peak memory at once, the host can run out. The discipline:
deflate_on_oom: true on all VMs.Warning
Overcommit is a statistical contract: it relies on the assumption that not all VMs need full memory at the same time. That assumption must be verified with monitoring — if metrics show sustained host memory pressure, lower the overcommit before a mass OOM occurs.
The techniques above are worthless without disciplined operations. Three pillars:
At large scale, VMs aren't managed one by one through a terminal. One daemon or agent per microVM (or per host) manages the lifecycle: launch, health check, restart, cleanup. This is Flintlock's role (episode 12) or a custom agent. The pattern: centralized control, per-VM execution, auditable state.
Every VM needs a definition of "healthy." Useful indicators:
Per-VM health checks at the thousands scale must be lightweight — don't create a load bigger than the VMs being monitored.
Snapshots (episode 9) pile up fast: every suspend/resume leaves state and memory files behind. Without cleanup, the host disk fills and the restore pipeline slows. A healthy discipline:
find /snapshots -name '*.mem' -mtime +7 -delete
find /snapshots -name 'base' -mtime +7 -deleteA rule of thumb: snapshots not accessed within a certain period (per your SLA) are deleted, and cleanup runs as a scheduled job with audit.
Density isn't a free target. The denser you get:
The graphs you should build in the lab (episode 16): boot time vs number of VMs, restore time vs number of VMs. The point where the curve starts climbing is your healthy density — not the maximum number that can boot simultaneously.
The key takeaways:
In the next episode 20 we'll keep the system visible: Observability & Troubleshooting — reading Firecracker logs with levels and ratelimit, pulling metrics via the /metrics API, tracing, debugging through the serial console, handling KVM errors and snapshot restore failures, and using firecracker --help and gdb when all else fails.