Manage image artifacts and show VM create progress

Stop relying on ad hoc rootfs handling by adding image promotion, managed work-seed fingerprint metadata, and lazy self-healing for older managed images after the first create.

Rebuild guest images with baked SSH access, a guest NIC bootstrap, and default opencode services, and add the staged Void kernel/initramfs/modules workflow so void-exp uses a matching Void boot stack.

Replace the opaque blocking vm.create RPC with a begin/status flow that prints live stages in the CLI while still waiting for vsock health and opencode on guest port 4096.

Validate with GOCACHE=/tmp/banger-gocache go test ./... and live void-exp create/delete smoke runs.
This commit is contained in:
Thales Maciel 2026-03-21 14:48:01 -03:00
parent 9f09b0d25c
commit 30f0c0b54a
No known key found for this signature in database
GPG key ID: 33112E6833C34679
37 changed files with 2334 additions and 99 deletions

View file

@ -212,10 +212,11 @@ banger image build --name docker-dev --docker
Rebuilt images install a pinned `mise` at `/usr/local/bin/mise`, activate it
for bash login and interactive shells, install `opencode` through `mise`,
configure `tmux-resurrect` plus `tmux-continuum` for `root` with periodic
autosaves and manual-only restore by default, and bake in the
`banger-vsock-agent` systemd service used by the post-SSH reminder path and
guest health checks. They
expose `/usr/local/bin/opencode`, configure `tmux-resurrect` plus
`tmux-continuum` for `root` with periodic autosaves and manual-only restore by
default, start a host-reachable `opencode serve` service on guest TCP port
`4096`, and bake in the `banger-vsock-agent` systemd service used by the
post-SSH reminder path and guest health checks. They
also emit a `work-seed.ext4` sidecar that lets new VMs clone a prepared `/root`
work disk instead of rebuilding it from scratch on every create.
@ -225,6 +226,17 @@ banger image show docker-dev
banger image delete docker-dev
```
Promote an existing unmanaged image into a managed one:
```bash
banger image promote default
banger image promote void-exp
```
Promotion copies the image's `rootfs` and optional `work-seed` into the
daemon's managed image state directory and keeps the same image ID, so existing
VM references stay valid. The image's kernel, initrd, modules, and package
manifest paths stay pointed at their current locations.
`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.
@ -253,6 +265,10 @@ short best-effort HTTP and HTTPS probes; detected web listeners are shown as
`https://<hostname>.vm:port/`. Older images without `ss` may need rebuilding
before `vm ports` works.
Newly rebuilt images also start `opencode serve` by default on guest TCP port
`4096`, bound on guest interfaces so the host can reach it directly at the
guest IP or via the endpoint shown by `banger vm ports`.
## Storage Model
- VMs share a read-only base rootfs image.
- Each VM gets its own sparse writable system overlay for `/`.
@ -286,7 +302,8 @@ make rootfs
```
That rebuild also regenerates `./runtime/rootfs-docker.work-seed.ext4`, which
the daemon uses to speed up future `vm create` calls.
the daemon uses to speed up future `vm create` calls, and bakes in the default
host-reachable `opencode` server service.
If your runtime bundle does not include `./runtime/rootfs.ext4`, pass an
explicit base image instead:
@ -303,25 +320,37 @@ 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`.
Existing VMs keep using their current image and disks; rebuilds only affect VMs
created from the rebuilt image afterward.
created from the rebuilt image afterward. Restarting an existing VM is not
enough to pick up guest provisioning changes such as the default `opencode`
server service.
## Experimental Void Rootfs
There is also a separate, opt-in builder for an experimental Void Linux guest
path:
```bash
make void-kernel
make rootfs-void
```
That writes:
- `./runtime/void-kernel/` when `make void-kernel` is used
- `./runtime/rootfs-void.ext4`
- `./runtime/rootfs-void.work-seed.ext4`
This path is intentionally local-only and does not change the default Debian
image flow. It reuses the current runtime bundle kernel, initrd, and modules,
but builds a lean `x86_64-glibc` Void userspace with:
image flow. `make void-kernel` stages an actual Void `linux6.12` kernel package
under `./runtime/void-kernel/`, including the raw `vmlinuz`, extracted
Firecracker `vmlinux`, a matching `initramfs`, the matching config, and the
matching modules tree. The initramfs is generated locally with `dracut`
against the downloaded Void sysroot so the kernel, initrd, and modules stay
aligned. `make rootfs-void` then prefers that staged modules tree when it exists;
otherwise it falls back to the runtime bundle modules. The rootfs builder
itself still builds a lean `x86_64-glibc` Void userspace with:
- `bash` installed for interactive/admin use
- pinned `mise` installed at `/usr/local/bin/mise`, activated for `root` bash shells
- `opencode` installed through `mise`, with `/usr/local/bin/opencode` available by default
- a guest network bootstrap that configures the VM NIC from the kernel `ip=` boot arg
- a host-reachable `opencode serve` runit service enabled on guest TCP port `4096`
- `docker` plus `docker-compose` installed from Void packages
- the `docker` runit service enabled, with Docker netfilter/forwarding kernel prep
- `openssh` enabled under runit
@ -333,26 +362,30 @@ It still keeps some Debian-oriented extras out for now:
- no tmux plugin defaults
The builder fetches official static XBPS tools and packages from the Void
mirror during the build. It currently supports only `x86_64-glibc`.
mirror during the build. The kernel fetcher and rootfs builder currently
support only `x86_64`.
The package set comes from [`packages.void`](/home/thales/projects/personal/banger/packages.void).
You can override the mirror, size, or output path directly:
You can override the mirror, size, output path, or kernel package directly:
```bash
./make-void-kernel.sh --kernel-package linux6.12
./make-rootfs-void.sh --mirror https://repo-default.voidlinux.org --size 2G
```
The fastest local iteration loop does not require changing your default image
config at all:
```bash
make void-kernel
make rootfs-void
make void-register
./banger vm create --image void-exp --name void-dev
./banger vm ssh void-dev
```
Rebuild the Void rootfs and recreate existing `void-exp` VMs after changing the
package set or guest provisioning; restart alone will not update the image
contents or `/root` work-seed.
Rebuild the staged Void kernel or Void rootfs, then recreate existing
`void-exp` VMs after changing the package set, guest provisioning, or staged
kernel artifacts; restart alone will not update the image contents, kernel, or
`/root` work-seed.
There is also a smoke path for the experimental image:
```bash
@ -361,7 +394,9 @@ make verify-void
`make void-register` uses the unmanaged image registration path to create or
update a `void-exp` image record in place, so repeated rebuilds do not require
editing `~/.config/banger/config.toml`.
editing `~/.config/banger/config.toml`. It expects a complete staged Void
kernel set under `./runtime/void-kernel/` and points the experimental image at
the staged Void `vmlinux`, `initramfs`, and matching modules tree.
There is also a one-step helper target:
```bash
@ -390,6 +425,9 @@ banger image register \
--name void-exp \
--rootfs ./runtime/rootfs-void.ext4 \
--work-seed ./runtime/rootfs-void.work-seed.ext4 \
--kernel ./runtime/void-kernel/boot/vmlinux-6.12.77_1 \
--initrd ./runtime/void-kernel/boot/initramfs-6.12.77_1.img \
--modules ./runtime/void-kernel/lib/modules/6.12.77_1 \
--packages ./packages.void
```