feat: initial Firecracker snapshot orchestrator (fc-orch)
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>
This commit is contained in:
54
orchestrator/config.go
Normal file
54
orchestrator/config.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package orchestrator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Config holds all tunables for the orchestrator.
|
||||
type Config struct {
|
||||
FCBin string // path to firecracker binary
|
||||
BaseDir string // working directory for all state
|
||||
Kernel string // path to vmlinux
|
||||
Rootfs string // path to base rootfs.ext4
|
||||
VCPUs int64
|
||||
MemMiB int64
|
||||
Bridge string // host bridge name, or "none" to skip networking
|
||||
BridgeCIDR string // e.g. "172.30.0.1/24"
|
||||
GuestPrefix string // e.g. "172.30.0" — clones get .10, .11, ...
|
||||
GuestGW string
|
||||
BootArgs string
|
||||
}
|
||||
|
||||
func DefaultConfig() Config {
|
||||
c := Config{
|
||||
FCBin: envOr("FC_BIN", "firecracker"),
|
||||
BaseDir: envOr("FC_BASE_DIR", "/tmp/fc-orch"),
|
||||
VCPUs: envOrInt("FC_VCPUS", 1),
|
||||
MemMiB: envOrInt("FC_MEM_MIB", 128),
|
||||
Bridge: envOr("FC_BRIDGE", "fcbr0"),
|
||||
BridgeCIDR: envOr("FC_BRIDGE_CIDR", "172.30.0.1/24"),
|
||||
GuestPrefix: envOr("FC_GUEST_PREFIX", "172.30.0"),
|
||||
GuestGW: envOr("FC_GUEST_GW", "172.30.0.1"),
|
||||
BootArgs: "console=ttyS0 reboot=k panic=1 pci=off i8042.noaux quiet loglevel=0",
|
||||
}
|
||||
c.Kernel = envOr("FC_KERNEL", c.BaseDir+"/vmlinux")
|
||||
c.Rootfs = envOr("FC_ROOTFS", c.BaseDir+"/rootfs.ext4")
|
||||
return c
|
||||
}
|
||||
|
||||
func envOr(key, fallback string) string {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
return v
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func envOrInt(key string, fallback int64) int64 {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
if n, err := strconv.ParseInt(v, 10, 64); err == nil {
|
||||
return n
|
||||
}
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
Reference in New Issue
Block a user