Remove the last shell-owned NAT surface by extracting the iptables logic into a shared Go package and using it from both bangerd and a hidden helper bridge in the CLI. Route customize.sh and interactive.sh through banger internal nat up/down so the remaining shell helpers reuse the same rule logic, resolve the local banger binary explicitly, and tear NAT back down during cleanup. Drop nat.sh from the runtime bundle and docs now that NAT is Go-managed everywhere, and keep coverage aligned with the new shared package and helper command. Validation: go test ./..., bash -n customize.sh interactive.sh verify.sh, make build, and a live ./verify.sh --nat run that installed host rules, reached outbound network access, and cleaned them up successfully.
253 lines
7.3 KiB
Markdown
253 lines
7.3 KiB
Markdown
# 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 from a local or published runtime archive. The
|
|
checked-in [`runtime-bundle.toml`](/home/thales/projects/personal/banger/runtime-bundle.toml)
|
|
is a template and intentionally ships with empty `url` and `sha256`.
|
|
|
|
If you need to create a local archive first, do that from a checkout or machine
|
|
that already has a populated `./runtime/` tree:
|
|
```bash
|
|
make runtime-package
|
|
cp dist/banger-runtime.tar.gz /path/to/fresh-checkout/dist/
|
|
```
|
|
|
|
In the fresh checkout:
|
|
```bash
|
|
cp runtime-bundle.toml runtime-bundle.local.toml
|
|
```
|
|
|
|
Edit `runtime-bundle.local.toml` to point at the staged archive and checksum:
|
|
```toml
|
|
url = "./dist/banger-runtime.tar.gz"
|
|
sha256 = "<sha256 printed by make runtime-package>"
|
|
```
|
|
|
|
Then bootstrap `./runtime/` with the local manifest copy:
|
|
```bash
|
|
make runtime-bundle RUNTIME_MANIFEST=runtime-bundle.local.toml
|
|
```
|
|
|
|
`url` may be a relative path, absolute path, `file:///...` URL, or HTTP(S)
|
|
URL. `make install` will not fetch artifacts for you.
|
|
|
|
## Build
|
|
```bash
|
|
make build
|
|
```
|
|
|
|
Run `make build` after `./runtime/` has been bootstrapped.
|
|
|
|
Install into `~/.local/bin` by default, with the runtime bundle under
|
|
`~/.local/lib/banger`:
|
|
```bash
|
|
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:
|
|
```bash
|
|
banger vm create --name calm-otter --disk-size 16G
|
|
```
|
|
|
|
List VMs:
|
|
```bash
|
|
banger vm list
|
|
```
|
|
|
|
Inspect a VM:
|
|
```bash
|
|
banger vm show calm-otter
|
|
banger vm stats calm-otter
|
|
```
|
|
|
|
SSH into a running VM:
|
|
```bash
|
|
banger vm ssh calm-otter
|
|
```
|
|
|
|
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
|
|
```
|
|
|
|
Update stopped VM settings:
|
|
```bash
|
|
banger vm set calm-otter --memory 2048 --vcpu 4 --disk-size 32G
|
|
```
|
|
|
|
Launch the TUI:
|
|
```bash
|
|
banger tui
|
|
```
|
|
|
|
## Daemon
|
|
The CLI auto-starts `bangerd` when needed.
|
|
|
|
Useful daemon commands:
|
|
```bash
|
|
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:
|
|
```bash
|
|
banger image list
|
|
```
|
|
|
|
Build a managed image:
|
|
```bash
|
|
banger image build --name docker-dev --docker
|
|
```
|
|
|
|
Show or delete images:
|
|
```bash
|
|
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:
|
|
```bash
|
|
banger vm create --name web --nat
|
|
banger vm set web --nat
|
|
banger vm set web --no-nat
|
|
```
|
|
|
|
NAT is applied by the Go control plane using host `iptables` rules derived from
|
|
the VM's current guest IP and TAP device. The remaining shell helpers also
|
|
route NAT changes through `banger` instead of a standalone shell NAT script.
|
|
|
|
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
|
|
The checked-in [`runtime-bundle.toml`](/home/thales/projects/personal/banger/runtime-bundle.toml)
|
|
is a template. Keep `bundle_metadata` accurate there, but use a separate local
|
|
manifest copy when you need concrete `url` and `sha256` values for bootstrap
|
|
testing or publication.
|
|
|
|
Package a local `./runtime/` tree into an archive:
|
|
```bash
|
|
make runtime-package
|
|
```
|
|
|
|
That writes `dist/banger-runtime.tar.gz` and prints its SHA256 so you can update
|
|
a local manifest copy before testing bootstrap changes or publishing the
|
|
archive elsewhere.
|
|
|
|
## 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
|
|
- `packages.sh`, `dns.sh`: shell helper libraries
|
|
- `verify.sh`: smoke test for the Go workflow (`./verify.sh --nat` adds NAT coverage)
|