Skip to content

Latest commit

 

History

History
112 lines (85 loc) · 4.46 KB

File metadata and controls

112 lines (85 loc) · 4.46 KB

knaller

What is this?

knaller is a Go library and CLI that makes it simple to run Firecracker microVMs. It starts a Firecracker process for each VM, connects to its API socket, configures the VM, and boots it. VMs are non-interactive — connect via SSH. It provides a high-level API (knaller.Run, knaller.List, knaller.StopVM, vm.Cleanup) that abstracts away the low-level Firecracker socket API. There's also a low-level firecracker sub-package for direct API access.

Project layout

knaller/
  vm.go              High-level API: Run(), List(), VM type
  config.go          Config struct with defaults and validation
  network.go         Network config derivation + pasta namespace setup script
  disk.go            Per-VM rootfs copy management + host DNS detection
  Containerfile_guest Guest rootfs container definition (Ubuntu + sshd + systemd)
  Makefile           Build targets: build, test, create-guest
  firecracker/
    client.go        Low-level HTTP-over-Unix-socket Firecracker API client
    models.go        Firecracker API types (BootSource, Drive, etc.)
  cmd/knaller/
    main.go          CLI binary entry point + subcommand dispatch
  internal/cli/
    start.go         "knaller start" subcommand (non-interactive, SSH access)
    stop.go          "knaller stop" subcommand
    list.go          "knaller list" subcommand
    version.go       "knaller version" subcommand (version set via ldflags)

Key design decisions

  • No state files. VM discovery is done by scanning the socket directory (~/.local/share/knaller/sockets/) and querying each Firecracker instance via its API. The socket's existence IS the state.

  • SSH access only. VMs don't have an interactive serial console. Firecracker's stdin is not connected. Use SSH to interact with the guest. The guest IP is printed on start and available via knaller list.

  • Rootless networking via pasta. Each VM runs inside a pasta network namespace (from the passt project). pasta creates a user+network namespace with a TAP device and provides L2↔L4 translation to the host — all without root privileges. Inside the namespace, a second TAP device is created for Firecracker's guest NIC using ip tuntap (works because we have CAP_NET_ADMIN within the namespace).

  • Per-VM rootfs copies. Each VM gets its own copy of the base rootfs at ~/.local/share/knaller/vms/<name>/rootfs.ext4, using cp --reflink=auto for copy-on-write when the filesystem supports it.

  • Auto DNS via kernel boot args. DNS servers are passed to the guest via the kernel ip= boot parameter. The guest rootfs symlinks /etc/resolv.conf/proc/net/pnp where the kernel writes them. Host DNS detection skips localhost entries (systemd-resolved stub) and falls back to resolvectl dns or 1.1.1.1/8.8.8.8.

  • One Firecracker process per VM. Firecracker is not a daemon — each process is exactly one VM with one API socket. Knaller starts a new Firecracker process for each Run() call and manages its lifecycle.

  • Cleanup is explicit. Call vm.Cleanup() after vm.Wait() returns. This removes the API socket and rootfs copy. Network namespace cleanup is automatic when the pasta process exits. The CLI handles this automatically via signal handlers.

Building

go build -o knaller ./cmd/knaller

Testing

go test ./...             # unit tests (no root needed)
go vet ./...              # static analysis

Unit tests use mock HTTP servers over Unix sockets — they don't need Firecracker, root access, or KVM. Integration testing requires running actual VMs (root + KVM).

Releasing

Releases are handled by GoReleaser via GitHub Actions. Push a tag to trigger a release:

git tag v0.1.0
git push origin v0.1.0

This cross-compiles for linux/amd64 and linux/arm64, generates a changelog from commit messages, and creates a GitHub release.

External dependencies

  • No external Go dependencies (only stdlib)

Requirements for running VMs

  • Linux with KVM (/dev/kvm)
  • pasta binary (from the passt project) — rootless networking
  • Firecracker binary (linux/amd64 or linux/arm64)
  • No root privileges required

Common issues

  • Guest DNS doesn't work: The host's /etc/resolv.conf pointed to 127.0.0.53 (systemd-resolved). We detect this and use resolvectl dns to find real upstreams.
  • apt interactive prompts in guest: Use DEBIAN_FRONTEND=noninteractive and dpkg force-confdef/force-confold options.