A "poor man's" Firecracker VM orchestrator that boots a single golden VM,
snapshots it, then restores N clone VMs from that snapshot with minimal
per-clone overhead.
How it works:
- `init` — downloads a Linux 6.1 kernel and builds a minimal Alpine 3.20
rootfs (512 MiB ext4) with a basic init script
- `golden` — boots the golden VM, lets it settle, then pauses and snapshots
it (vmstate + memory file); the golden VMM is then terminated
since only the artifacts are needed
- `spawn N` — restores N clone VMs concurrently from the golden snapshot:
* rootfs: filesystem-level COW copy via `cp --reflink` (falls
back to a plain copy if reflinks are not supported)
* memory: shared golden `mem` file; Firecracker's MAP_PRIVATE
lets the kernel handle COW page-by-page at no up-front cost
* vmstate: small file, cheap regular copy per clone
* networking: per-clone TAP device (fctapN) bridged to fcbr0
with iptables MASQUERADE NAT on the default route interface
- `status` — reads PID files and checks /proc to report alive/dead clones
- `kill` — stops in-memory clones, kills any stragglers via PID files,
and tears down all fctap* devices
- `cleanup` — kill + remove all state dirs and the bridge
All tunables (binary path, base dir, kernel/rootfs paths, vCPUs, memory,
bridge name/CIDR) are configurable via environment variables.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
84 lines
1.9 KiB
Go
84 lines
1.9 KiB
Go
// fc-orchestrator — Poor man's Firecracker snapshot orchestrator in Go.
|
|
//
|
|
// Creates a golden VM, snapshots it, then spawns N clones that share the
|
|
// base memory file via Firecracker's MAP_PRIVATE (kernel-level COW).
|
|
// Rootfs gets a filesystem-level COW copy (reflink where supported).
|
|
//
|
|
// Usage:
|
|
//
|
|
// go build -o fc-orch .
|
|
// sudo ./fc-orch init
|
|
// sudo ./fc-orch golden
|
|
// sudo ./fc-orch spawn 10
|
|
// sudo ./fc-orch status
|
|
// sudo ./fc-orch kill
|
|
// sudo ./fc-orch cleanup
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/you/fc-orchestrator/orchestrator"
|
|
)
|
|
|
|
func main() {
|
|
if len(os.Args) < 2 {
|
|
usage()
|
|
os.Exit(1)
|
|
}
|
|
|
|
orch := orchestrator.New(orchestrator.DefaultConfig())
|
|
|
|
switch os.Args[1] {
|
|
case "init":
|
|
fatal(orch.Init())
|
|
case "golden":
|
|
fatal(orch.Golden())
|
|
case "spawn":
|
|
n := 1
|
|
if len(os.Args) > 2 {
|
|
fmt.Sscanf(os.Args[2], "%d", &n)
|
|
}
|
|
fatal(orch.Spawn(n))
|
|
case "status":
|
|
orch.Status()
|
|
case "kill":
|
|
fatal(orch.Kill())
|
|
case "cleanup":
|
|
fatal(orch.Cleanup())
|
|
default:
|
|
usage()
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func usage() {
|
|
fmt.Fprintf(os.Stderr, `Usage: %s <command> [args]
|
|
|
|
Commands:
|
|
init Download kernel + create Alpine rootfs
|
|
golden Boot golden VM → pause → snapshot
|
|
spawn [N] Restore N clones from golden snapshot (default: 1)
|
|
status Show running clones
|
|
kill Kill all running VMs
|
|
cleanup Kill VMs + remove all state
|
|
|
|
Environment:
|
|
FC_BIN firecracker binary path (default: firecracker)
|
|
FC_BASE_DIR working directory (default: /tmp/fc-orch)
|
|
FC_KERNEL vmlinux path
|
|
FC_ROOTFS rootfs.ext4 path
|
|
FC_VCPUS vCPUs per VM (default: 1)
|
|
FC_MEM_MIB MiB per VM (default: 128)
|
|
FC_BRIDGE bridge name or "none" (default: fcbr0)
|
|
`, os.Args[0])
|
|
}
|
|
|
|
func fatal(err error) {
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "fatal: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|