Switch to fetched runtime bundles
Stop treating Firecracker, kernels, modules, and guest images as tracked source files. Source checkouts now resolve runtime assets from ./runtime, while installed binaries keep using ../lib/banger. Add a small runtimebundle helper plus runtime-bundle.toml so make can bootstrap, package, and install a runtime bundle with checksum validation. Update the shell helpers and daemon path hints to fail clearly when the bundle is missing instead of assuming repo-root artifacts. This removes the tracked runtime blobs from HEAD in favor of an ignored local runtime/ tree. Verified with go test ./..., make build, bash -n on the shell helpers, make -n install, and a temporary package/fetch smoke test. The manifest URL/SHA still need a published bundle before fresh clones can bootstrap, and history rewrite remains a separate rollout step.
This commit is contained in:
parent
ce1be52047
commit
238bb8a020
6512 changed files with 1019 additions and 65372 deletions
304
README.md
304
README.md
|
|
@ -1,182 +1,206 @@
|
|||
# banger
|
||||
|
||||
Minimal Firecracker launcher.
|
||||
Persistent Firecracker development VMs managed through a Go daemon, CLI, and TUI.
|
||||
|
||||
## Requirements
|
||||
- Linux host with KVM (`/dev/kvm` access)
|
||||
- `sudo`, `ip`, `curl`, `ssh`, `jq`
|
||||
- `dmsetup`, `losetup`, `blockdev` (device-mapper snapshot for rootfs)
|
||||
- `e2cp`, `e2rm` (writes hostname and resolv.conf into rootfs snapshot)
|
||||
- `dmsetup`, `losetup`, `blockdev`
|
||||
- `e2cp`, `e2rm`, `debugfs`
|
||||
- `mapdns`
|
||||
|
||||
## Files
|
||||
- `firecracker`: Firecracker binary
|
||||
- `wtf/root/boot/vmlinux-6.8.0-94-generic`: guest kernel
|
||||
- `wtf/root/boot/initrd.img-6.8.0-94-generic`: guest initrd
|
||||
- `wtf/root/lib/modules/6.8.0-94-generic/`: guest kernel modules
|
||||
- `rootfs.ext4`: guest root filesystem (base image if present)
|
||||
- `rootfs-docker.ext4`: docker-ready guest rootfs (built via `make-rootfs.sh`)
|
||||
- `packages.apt`: apt packages baked into rebuilt guest images
|
||||
- `id_ed25519`: SSH key for `root`
|
||||
- `mapdns`: local DNS mapping CLI used to publish `<vm-name>.vm` → guest IP records
|
||||
## 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`.
|
||||
|
||||
## Run
|
||||
```
|
||||
./run.sh
|
||||
The bundle contains:
|
||||
- `firecracker`
|
||||
- `wtf/root/boot/vmlinux-6.8.0-94-generic`
|
||||
- `wtf/root/boot/initrd.img-6.8.0-94-generic`
|
||||
- `wtf/root/lib/modules/6.8.0-94-generic/`
|
||||
- `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:
|
||||
```bash
|
||||
make runtime-bundle
|
||||
```
|
||||
|
||||
## Experimental Go Control Plane
|
||||
There is now an XDG-based Go daemon + CLI prototype alongside the shell scripts.
|
||||
It keeps persistent VM/image state in SQLite under your XDG state directory and
|
||||
talks over a Unix socket under your XDG runtime directory.
|
||||
`make runtime-bundle` reads [`runtime-bundle.toml`](/home/thales/projects/personal/banger/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 it with:
|
||||
```
|
||||
## Build
|
||||
```bash
|
||||
make runtime-bundle
|
||||
make build
|
||||
```
|
||||
|
||||
Or directly with Go:
|
||||
```
|
||||
go build -o ./banger ./cmd/banger
|
||||
go build -o ./bangerd ./cmd/bangerd
|
||||
Install into `~/.local/bin` by default, with the runtime bundle under
|
||||
`~/.local/lib/banger`:
|
||||
```bash
|
||||
make install
|
||||
```
|
||||
|
||||
Basic usage:
|
||||
```
|
||||
./banger daemon status
|
||||
./banger tui
|
||||
./banger vm list
|
||||
./banger vm create --name calm-otter --disk-size 16G
|
||||
./banger vm set calm-otter --memory 2048 --vcpu 4
|
||||
./banger image list
|
||||
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:
|
||||
```bash
|
||||
banger vm create --name calm-otter --disk-size 16G
|
||||
```
|
||||
|
||||
Notes:
|
||||
- `banger` auto-starts the per-user daemon when needed.
|
||||
- `banger tui` launches a terminal UI for browsing, creating, editing, and operating VMs.
|
||||
- VM configs are persistent by default.
|
||||
- RAM, vCPU, and work-disk size edits are stopped-only.
|
||||
- The Go image build path currently delegates guest customization to `customize.sh`.
|
||||
|
||||
## Run Options
|
||||
```
|
||||
./run.sh --name calm-otter --vcpu 4 --ram 2048 --overlay-size 12G
|
||||
```
|
||||
- `--name`: must be unique and match `[a-z0-9][a-z0-9-]{0,63}`.
|
||||
- `--vcpu`: defaults to 2, max 16.
|
||||
- `--ram`: MiB, defaults to 1024, max 32768.
|
||||
- `--overlay-size`: writable dm-snapshot size for VM changes under `/`, including `/root` and `/var` (default: 8G).
|
||||
- `--rootfs`: path to the rootfs image (default: `./rootfs-docker.ext4`).
|
||||
- `--kernel`: path to the kernel image (default: `./wtf/root/boot/vmlinux-6.8.0-94-generic`).
|
||||
- `--initrd`: path to the initrd image (default: `./wtf/root/boot/initrd.img-6.8.0-94-generic`).
|
||||
|
||||
## Storage Layout
|
||||
- `rootfs.ext4` is used as the read-only origin for a per-VM device-mapper snapshot mounted as `/`.
|
||||
- Each VM gets one sparse writable overlay file (`cow.ext4`) that stores its changes on top of the shared base image.
|
||||
- `/root` and `/var` live inside that per-VM overlay, so VMs can install packages without copying separate disks per VM.
|
||||
- `run.sh` masks stale `home.mount` and `var.mount` units at boot so older images with `/dev/vdb` and `/dev/vdc` entries in `/etc/fstab` still boot.
|
||||
- `/run` and `/tmp` should be tmpfs via `/etc/fstab`.
|
||||
|
||||
## SSH
|
||||
```
|
||||
ssh -i "./id_ed25519" root@<guest_ip>
|
||||
List VMs:
|
||||
```bash
|
||||
banger vm list
|
||||
```
|
||||
|
||||
Shortcut:
|
||||
```
|
||||
./ssh.sh <vm-name-or-ip>
|
||||
Inspect a VM:
|
||||
```bash
|
||||
banger vm show calm-otter
|
||||
banger vm stats calm-otter
|
||||
```
|
||||
|
||||
## VM DNS
|
||||
- Spawned VMs register `<vm-name>.vm` → guest IP through `mapdns set`.
|
||||
- VM teardown removes the mapping through `mapdns rm`.
|
||||
- `mapdns` writes to `/home/thales/.local/share/mapdns/records.json`.
|
||||
|
||||
## Internet Access
|
||||
VMs do not get internet access by default. You must enable forwarding and NAT:
|
||||
```
|
||||
./nat.sh up <id-or-name-prefix>
|
||||
```
|
||||
This enables `net.ipv4.ip_forward=1` and installs per-VM NAT rules for the VM's
|
||||
guest IP and TAP device. To remove rules:
|
||||
```
|
||||
./nat.sh down <id-or-name-prefix>
|
||||
```
|
||||
Check status with:
|
||||
```
|
||||
./nat.sh status <id-or-name-prefix>
|
||||
SSH into a running VM:
|
||||
```bash
|
||||
banger vm ssh calm-otter
|
||||
```
|
||||
|
||||
## Shutdown
|
||||
```
|
||||
reboot
|
||||
Stop, restart, kill, or delete it:
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
## Customize Rootfs (Docker + Kernel Modules)
|
||||
Use `customize.sh` to build a writable rootfs with Docker and kernel modules
|
||||
preloaded so Docker works out of the box. Pass the base rootfs as a positional
|
||||
argument; the output defaults to `docker-<base filename>` in the same directory
|
||||
unless you pass `--out`.
|
||||
|
||||
Base guest packages come from `./packages.apt`. Edit that file to bake tools
|
||||
like `vim` and `tmux` into rebuilt images.
|
||||
|
||||
```
|
||||
./customize.sh ./rootfs.ext4 --size 6G --docker
|
||||
Update stopped VM settings:
|
||||
```bash
|
||||
banger vm set calm-otter --memory 2048 --vcpu 4 --disk-size 32G
|
||||
```
|
||||
|
||||
Options:
|
||||
- `--size`: optional size for the output image.
|
||||
- `--kernel`: kernel path (default: `./wtf/root/boot/vmlinux-6.8.0-94-generic`).
|
||||
- `--initrd`: initrd path (default: `./wtf/root/boot/initrd.img-6.8.0-94-generic`).
|
||||
- `--modules`: kernel modules directory (default: `./wtf/root/lib/modules/6.8.0-94-generic`).
|
||||
- `--docker`: install Docker packages into the image.
|
||||
- `--out`: output rootfs path (default: `docker-<base filename>`).
|
||||
|
||||
After boot, enable NAT and validate Docker:
|
||||
```
|
||||
./nat.sh up <id-or-name-prefix>
|
||||
ssh -i "./id_ed25519" root@<guest_ip> "systemctl enable --now docker"
|
||||
ssh -i "./id_ed25519" root@<guest_ip> "docker run --rm hello-world"
|
||||
Launch the TUI:
|
||||
```bash
|
||||
banger tui
|
||||
```
|
||||
|
||||
## Build Rootfs On Demand
|
||||
`run.sh` defaults to `./rootfs-docker.ext4`. If it is missing, `run.sh` will
|
||||
invoke `make-rootfs.sh` to build it.
|
||||
## Daemon
|
||||
The CLI auto-starts `bangerd` when needed.
|
||||
|
||||
```
|
||||
./make-rootfs.sh
|
||||
Useful daemon commands:
|
||||
```bash
|
||||
banger daemon status
|
||||
banger daemon socket
|
||||
banger daemon stop
|
||||
```
|
||||
|
||||
`make-rootfs.sh` chooses the first available base image:
|
||||
- `./rootfs.ext4`
|
||||
State lives under XDG directories:
|
||||
- config: `~/.config/banger`
|
||||
- state: `~/.local/state/banger`
|
||||
- cache: `~/.cache/banger`
|
||||
- runtime socket: `$XDG_RUNTIME_DIR/banger/bangerd.sock`
|
||||
|
||||
If `./packages.apt` changes after `rootfs-docker.ext4` is built, `run.sh` will
|
||||
warn and keep using the existing image. `make-rootfs.sh` will also warn and
|
||||
exit without rebuilding while the image already exists.
|
||||
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`.
|
||||
|
||||
To rebuild after package changes:
|
||||
```
|
||||
rm -f ./rootfs-docker.ext4 ./rootfs-docker.ext4.packages.sha256
|
||||
./make-rootfs.sh
|
||||
Useful config keys:
|
||||
- `runtime_dir`
|
||||
- `firecracker_bin`
|
||||
- `ssh_key_path`
|
||||
- `namegen_path`
|
||||
- `customize_script`
|
||||
- `default_rootfs`
|
||||
- `default_base_rootfs`
|
||||
- `default_kernel`
|
||||
- `default_initrd`
|
||||
- `default_modules_dir`
|
||||
- `default_packages_file`
|
||||
|
||||
## Images
|
||||
List images:
|
||||
```bash
|
||||
banger image list
|
||||
```
|
||||
|
||||
## Interactive Customization
|
||||
To create a writable copy and customize it manually over SSH (no automatic
|
||||
package/config changes), use:
|
||||
|
||||
```
|
||||
./interactive.sh ./rootfs-docker.ext4
|
||||
Build a managed image:
|
||||
```bash
|
||||
banger image build --name docker-dev --docker
|
||||
```
|
||||
|
||||
You can override the output path:
|
||||
```
|
||||
./interactive.sh ./rootfs-docker.ext4 --out ./my-rootfs.ext4
|
||||
Show or delete images:
|
||||
```bash
|
||||
banger image show docker-dev
|
||||
banger image delete docker-dev
|
||||
```
|
||||
|
||||
## VM Info File
|
||||
Each VM writes:
|
||||
- `state/vms/<id>/vm.json`: local metadata under `.meta` plus the raw Firecracker config under `.config`.
|
||||
`banger` auto-registers the bundled `default_rootfs` image when it exists. If
|
||||
`rootfs.ext4` is not present in the bundle, `image build` falls back to using
|
||||
`rootfs-docker.ext4` as its default base image.
|
||||
|
||||
## Log Notes
|
||||
- `PCI: Fatal: No config space access function found` and `MissingAddressRange` lines are expected with `pci=off` in `run.sh`.
|
||||
- `SELinux: Could not open policy file ...` is expected in the minimal rootfs.
|
||||
## Networking And DNS
|
||||
Enable NAT when creating or updating a VM:
|
||||
```bash
|
||||
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`:
|
||||
```bash
|
||||
make rootfs
|
||||
```
|
||||
|
||||
If the package manifest changed and you want a fresh source-checkout image:
|
||||
```bash
|
||||
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`](/home/thales/projects/personal/banger/runtime-bundle.toml)
|
||||
with the published bundle URL and SHA256.
|
||||
|
||||
Package a local `./runtime/` tree for publication:
|
||||
```bash
|
||||
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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue