One-command development sandboxes on Firecracker microVMs. https://git.thaloco.com/thaloco/banger/
Find a file
Thales Maciel ebb68c3126 Reconcile stale default image on startup
Upgrades from the pre-bundle layout can leave the unmanaged default image pointing at repo-root artifacts that no longer exist, causing vm start preflight to fail forever. Treat the default image as reconcilable state instead of bailing out when a record exists.

Compute the desired default image from current runtime/config defaults, update an existing unmanaged default in place when its paths diverge, keep managed defaults untouched, and preserve the original ID so existing VMs keep referencing it. Added regression tests covering creation, no-op, reconciliation, managed-image skip, and missing-artifact behavior.
2026-03-16 16:45:54 -03:00
cmd Switch to fetched runtime bundles 2026-03-16 15:05:10 -03:00
internal Reconcile stale default image on startup 2026-03-16 16:45:54 -03:00
.gitignore Switch to fetched runtime bundles 2026-03-16 15:05:10 -03:00
AGENTS.md Make runtime defaults portable 2026-03-16 15:30:08 -03:00
customize.sh Make runtime defaults portable 2026-03-16 15:30:08 -03:00
dns.sh Make runtime defaults portable 2026-03-16 15:30:08 -03:00
firecracker-api.yaml Add runtime options and schema 2026-01-29 01:14:29 -03:00
go.mod Use Firecracker SDK in daemon 2026-03-16 13:26:41 -03:00
go.sum Use Firecracker SDK in daemon 2026-03-16 13:26:41 -03:00
interactive.sh Make runtime defaults portable 2026-03-16 15:30:08 -03:00
make-rootfs.sh Switch to fetched runtime bundles 2026-03-16 15:05:10 -03:00
Makefile Make runtime defaults portable 2026-03-16 15:30:08 -03:00
nat.sh Store VM metadata as JSON 2026-01-31 23:17:12 -03:00
packages.apt Streamline VM overlays and rootfs packages 2026-03-15 19:36:54 -03:00
packages.sh Streamline VM overlays and rootfs packages 2026-03-15 19:36:54 -03:00
README.md Add structured daemon lifecycle logs 2026-03-16 16:16:28 -03:00
runtime-bundle.toml Make runtime defaults portable 2026-03-16 15:30:08 -03:00
verify.sh Add regression coverage for VM failure paths 2026-03-16 15:46:54 -03:00

banger

Persistent Firecracker development VMs managed through a Go daemon, CLI, and TUI.

Requirements

  • Linux host with KVM (/dev/kvm access)
  • Core VM lifecycle: sudo, ip, dmsetup, losetup, blockdev, truncate, pgrep, ps
  • Guest rootfs patching: e2cp, e2rm, debugfs
  • Guest work disk creation/resizing: mkfs.ext4, e2fsck, resize2fs, mount, umount, cp
  • SSH and logs: ssh
  • DNS publishing: mapdns
  • Optional NAT: iptables, sysctl
  • Image build helper flow: bash, curl, jq, sha256sum

banger validates these per command and returns actionable errors instead of assuming one workstation layout.

Runtime Bundle

Runtime artifacts are no longer tracked directly in Git. Source checkouts use a generated ./runtime/ bundle, while installed binaries use $(prefix)/lib/banger.

The bundle contains:

  • firecracker
  • bundle.json with the bundle's default kernel/initrd/modules/rootfs paths
  • a kernel, initrd, and modules tree referenced by bundle.json
  • rootfs-docker.ext4
  • rootfs.ext4 when present
  • packages.apt
  • id_ed25519
  • the helper scripts used by image builds and installs

Bootstrap a source checkout explicitly:

make runtime-bundle

make runtime-bundle reads runtime-bundle.toml, downloads the published bundle, verifies its SHA256, and unpacks it into ./runtime/. make install will not fetch artifacts for you. The manifest must point at a published or locally staged bundle before bootstrap can work.

Build

make runtime-bundle
make build

Install into ~/.local/bin by default, with the runtime bundle under ~/.local/lib/banger:

make install

After make install, the installed banger and bangerd do not need the repo checkout to keep working.

Basic VM Workflow

Create and boot a VM:

banger vm create --name calm-otter --disk-size 16G

List VMs:

banger vm list

Inspect a VM:

banger vm show calm-otter
banger vm stats calm-otter

SSH into a running VM:

banger vm ssh calm-otter

Stop, restart, kill, or delete it:

banger vm stop calm-otter
banger vm start calm-otter
banger vm restart calm-otter
banger vm kill --signal TERM calm-otter
banger vm delete calm-otter

Update stopped VM settings:

banger vm set calm-otter --memory 2048 --vcpu 4 --disk-size 32G

Launch the TUI:

banger tui

Daemon

The CLI auto-starts bangerd when needed.

Useful daemon commands:

banger daemon status
banger daemon socket
banger daemon stop

banger daemon status prints the daemon PID, socket path, and bangerd.log location.

State lives under XDG directories:

  • config: ~/.config/banger
  • state: ~/.local/state/banger
  • cache: ~/.cache/banger
  • runtime socket: $XDG_RUNTIME_DIR/banger/bangerd.sock

Installed binaries resolve their runtime bundle from ../lib/banger relative to the executable. Source-checkout binaries resolve it from ./runtime next to the repo-built ./banger. You can override either with runtime_dir in ~/.config/banger/config.toml or BANGER_RUNTIME_DIR.

mapdns uses its own default data store unless you set mapdns_data_file or BANGER_MAPDNS_DATA_FILE.

Useful config keys:

  • log_level
  • runtime_dir
  • firecracker_bin
  • mapdns_bin
  • mapdns_data_file
  • ssh_key_path
  • namegen_path
  • customize_script
  • default_rootfs
  • default_base_rootfs
  • default_kernel
  • default_initrd
  • default_modules_dir
  • default_packages_file

Logs

  • daemon lifecycle logs: ~/.local/state/banger/bangerd.log
  • raw Firecracker output per VM: ~/.local/state/banger/vms/<vm-id>/firecracker.log
  • raw image-build helper output: ~/.local/state/banger/image-build/*.log

bangerd.log is structured JSON. Set log_level in ~/.config/banger/config.toml or BANGER_LOG_LEVEL to one of debug, info, warn, or error.

Images

List images:

banger image list

Build a managed image:

banger image build --name docker-dev --docker

Show or delete images:

banger image show docker-dev
banger image delete docker-dev

banger auto-registers the bundled default_rootfs image when it exists. If the bundle does not include a separate base rootfs.ext4, image build falls back to using rootfs-docker.ext4 as its default base image.

Networking And DNS

Enable NAT when creating or updating a VM:

banger vm create --name web --nat
banger vm set web --nat
banger vm set web --no-nat

For daemon-managed VMs, NAT is applied directly by bangerd using host iptables rules derived from the VM's current guest IP and TAP device.

Running VMs are published as <vm-name>.vm through mapdns.

Storage Model

  • VMs share a read-only base rootfs image.
  • Each VM gets its own sparse writable system overlay for /.
  • Each VM gets its own persistent ext4 work disk mounted at /root.
  • Stopping a VM preserves its overlay and work disk.

Rebuilding The Repo Default Rootfs

packages.apt controls the base apt packages baked into rebuilt images.

To rebuild the source-checkout default image in ./runtime/rootfs-docker.ext4:

make rootfs

If the package manifest changed and you want a fresh source-checkout image:

rm -f ./runtime/rootfs-docker.ext4 ./runtime/rootfs-docker.ext4.packages.sha256
make rootfs

make rootfs expects a bootstrapped runtime bundle. If ./runtime/rootfs.ext4 is not available, pass an explicit --base-rootfs to ./make-rootfs.sh.

Maintaining The Runtime Bundle

Maintain the checked-in manifest in runtime-bundle.toml with the published bundle URL, SHA256, and bundle_metadata defaults.

Package a local ./runtime/ tree for publication:

make runtime-package

That writes dist/banger-runtime.tar.gz and prints its SHA256 so you can update the manifest before publishing or testing bootstrap changes.

Remaining Shell Helpers

The runtime VM lifecycle is managed through banger. The remaining shell scripts are not the primary user interface:

  • customize.sh: implementation used by banger image build; it now reads assets from BANGER_RUNTIME_DIR and stores transient state under BANGER_STATE_DIR/XDG state
  • make-rootfs.sh: convenience wrapper for rebuilding ./runtime/rootfs-docker.ext4
  • interactive.sh: manual one-off rootfs customization over SSH
  • nat.sh: legacy host NAT helper used by the shell customization flows
  • packages.sh, dns.sh: shell helper libraries
  • verify.sh: smoke test for the Go workflow (./verify.sh --nat adds NAT coverage)