BOOTy

A lightweight initramfs agent for bare-metal OS provisioning over the network.
BOOTy boots as the init process inside a minimal initramfs, contacts a provisioning server, and orchestrates the full lifecycle of a bare-metal machine: disk imaging, OS configuration, network setup, and reboot. It supports two operating modes — CAPRF integration for Kubernetes cluster provisioning and legacy mode for standalone image deployment.
Warning — This software has no guard rails. Incorrect use can overwrite an existing Operating System.
Architecture
BOOTy operates in two modes depending on the boot environment:
CAPRF Mode (Cluster API Provider Redfish)
┌─────────────┐ ┌─────────────────┐ ┌──────────────────────┐
│ Redfish BMC │────▶│ BOOTy initrd │────▶│ CAPRF Controller │
│ (ISO boot) │ │ /deploy/vars │ │ (status/log/debug) │
└─────────────┘ └───────┬─────────┘ └──────────────────────┘
│
┌────────────┼────────────┐
│ │ │
┌──────▼──┐ ┌──────▼──┐ ┌──────▼──────┐
│ Network │ │ Disk │ │ OS │
│ FRR/DHCP│ │ Stream │ │ Configure │
└─────────┘ └─────────┘ └─────────────┘
- A Redfish BMC mounts an ISO containing a kernel, BOOTy initramfs, and
/deploy/vars config.
- BOOTy reads
/deploy/vars for machine config, image URLs, and CAPRF server endpoints.
- Network connectivity is established via FRR/EVPN (BGP underlay) or DHCP fallback.
- The provisioning pipeline runs 24 steps: status reporting → RAID cleanup → disk detection → image streaming → partition management → OS configuration → kexec.
- Status, logs, and debug info are shipped back to the CAPRF controller throughout.
Legacy Mode
┌──────────────┐ ┌──────────────────┐
│ PXE / iPXE │────────▶│ BOOTy initrd │
│ Boot loader │ │ (kernel + cpio) │
└──────────────┘ └───────┬──────────┘
│ DHCP / HTTP
┌───────▼──────────┐
│ BOOTy Server │
│ (config + images)│
└──────────────────┘
- A bare-metal server PXE-boots with a kernel and the BOOTy initramfs.
- BOOTy obtains an IP via DHCP and fetches its configuration from the provisioning server using its MAC address.
- Depending on the
action field in the config, BOOTy either writes an image to disk or reads a disk and uploads it.
Features
- Dual-mode provisioning — CAPRF (Kubernetes) and legacy (standalone) modes
- FRR/EVPN networking — BGP underlay with VXLAN overlay for data center fabrics (FRR-based)
- GoBGP/EVPN networking — Pure-Go BGP stack with VXLAN overlay (no external daemons)
- Static IP networking — Direct IP assignment via netlink (no external tools)
- LACP bond — 802.3ad link aggregation with configurable bond modes
- DHCP fallback — Automatic DHCP on all physical interfaces with connectivity check
- Broad NIC driver support — Intel (e1000e, igb, igc, ixgbe, i40e, ice), Broadcom (tg3, bnxt_en), Mellanox/NVIDIA (mlx4, mlx5), plus virtio for VMs
- Multi-format image streaming — Gzip, lz4, xz, zstd decompression with auto-detection
- OCI registry support — Pull images from OCI registries (authenticated & unauthenticated) via
oci:// URLs
- HTTP retry with backoff — Automatic exponential backoff retry for image downloads and OCI pulls
- Secure erase — NVMe format (SES1) and ATA Security Erase for full disk sanitization
- Software RAID — mdadm array creation (RAID 0/1/5/6/10)
- Filesystem support — ext2, ext3, ext4, xfs, btrfs, vfat mount/resize
- LLDP discovery — Raw AF_PACKET-based LLDP listener for switch topology discovery
- Post-provision hooks — Execute arbitrary commands in chroot after OS configuration
- 25-step provisioning pipeline — RAID cleanup, disk detection, image streaming, partition growth, LVM, filesystem resize, OS configuration, EFI boot, Mellanox SR-IOV, post-provision hooks
- Kexec support — Fast reboot into installed kernel without full BIOS POST (auto-disabled after firmware changes)
- Remote logging — Real-time log and debug shipping to CAPRF controller
- Hard/soft deprovisioning — Full disk wipe or GRUB rename for reprovisioning
- Standby mode — Hot standby with heartbeats and command polling for sub-second provisioning
- Multi-architecture — Builds for
linux/amd64 and linux/arm64
- Multiple build flavors — Full (FRR+tools), GoBGP (pure Go BGP), slim (DHCP-only), micro (pure Go), ISO (bootable)
Prerequisites
- Go 1.26+
- Docker (for building the initramfs)
- A DHCP/PXE environment (legacy mode) or Redfish BMC with ISO virtual media (CAPRF mode)
Building
Initramfs (recommended)
Build the complete initramfs with Docker:
make build
This compiles BOOTy for linux/amd64 and linux/arm64, then packages BusyBox, LVM2, FRR, and kernel modules for common server NICs into a bootable initramfs.
To extract the initramfs to the local filesystem:
docker run ghcr.io/telekom/booty:latest tar -cf - /initramfs.cpio.gz | tar xf -
Build Flavors
The initrd.Dockerfile supports multiple build targets via --target:
| Target |
Size |
Networking |
Disk Tools |
Use Case |
| (default) |
~80 MB |
FRR/EVPN + DHCP |
Full (LVM, sfdisk, mdadm) |
Production bare-metal provisioning |
gobgp |
~45 MB |
GoBGP/EVPN + DHCP |
Full (LVM, sfdisk, mdadm) |
Production without FRR dependency |
iso |
~100 MB |
FRR/EVPN + DHCP |
Full |
Bootable ISO for Redfish virtual media |
gobgp-iso |
~65 MB |
GoBGP/EVPN + DHCP |
Full |
Bootable GoBGP ISO for Redfish virtual media |
slim |
~15 MB |
DHCP only |
Minimal (e2fsck, resize2fs) |
Lightweight provisioning without BGP |
micro |
~10 MB |
None (pure Go) |
None |
Minimal agent, custom network stack |
# Build ISO (for Redfish BMC virtual media boot)
docker build --target=iso -f initrd.Dockerfile -o type=local,dest=. .
# Build slim initramfs
docker build --target=slim -f initrd.Dockerfile -o type=local,dest=. .
Binary only
GOOS=linux go build -o booty .
Hardware Compatibility
Network Interface Cards
BOOTy includes kernel modules for common data center NICs. Modules are loaded
automatically at boot from the /modules/ directory in the initramfs.
| Vendor |
Driver |
Hardware |
Speed |
| Intel |
e1000e |
I217/I218/I219 |
1G |
| Intel |
igb |
I350, I210/I211 |
1G |
| Intel |
igc |
I225/I226 |
2.5G |
| Intel |
ixgbe |
X520, X540, X550 (82599) |
10G |
| Intel |
i40e |
X710, XL710, XXV710 |
10/25/40G |
| Intel |
ice |
E810 |
25/50/100G |
| Intel |
iavf |
Adaptive Virtual Function |
VF |
| Broadcom |
tg3 |
NetXtreme BCM57xx |
1G |
| Broadcom |
bnxt_en |
NetXtreme-E/C BCM573xx/574xx |
10/25/50/100G |
| NVIDIA/Mellanox |
mlx4_core/mlx4_en |
ConnectX-3 |
10/40G |
| NVIDIA/Mellanox |
mlx5_core |
ConnectX-4/5/6/7, BlueField |
10/25/40/50/100/200/400G |
| Emulex/Broadcom |
be2net |
OneConnect OCe14xxx |
10G |
| QEMU/KVM |
virtio_net |
VirtIO NIC |
Virtual |
Mellanox SR-IOV: ConnectX-4+ cards are automatically detected via sysfs PCI vendor
ID (/sys/bus/pci/devices/*/vendor) — no lspci binary needed. SR-IOV is configured
using mstconfig during provisioning (requires a hard reboot to apply firmware changes).
Usage
CAPRF Mode
CAPRF mode is activated automatically when /deploy/vars exists (ISO-booted). The vars file is generated by the CAPRF controller and contains:
export IMAGE="http://images.local/ubuntu-22.04.img.gz"
export HOSTNAME="worker-01"
export TOKEN="bearer-token-for-auth"
export MODE="provision" # provision | deprovision | soft-deprovision
export PROVIDER_ID="redfish://bmc/Systems/1"
export FAILURE_DOMAIN="az-1"
export REGION="eu-central"
export INIT_URL="http://caprf:8080/status/init"
export SUCCESS_URL="http://caprf:8080/status/success"
export ERROR_URL="http://caprf:8080/status/error"
export LOG_URL="http://caprf:8080/log"
# Network (FRR/EVPN mode — omit for DHCP fallback)
underlay_subnet="10.0.0.0/24"
asn_server="65001"
provision_vni="10100"
overlay_subnet="fd00::/64"
dns_resolver="8.8.8.8"
Legacy Mode
The provisioning server serves configuration files and (optionally) disk images over HTTP.
Write an image to a remote server
go run server/server.go \
-action writeImage \
-mac 00:50:56:a5:0e:0f \
-sourceImage http://192.168.0.95:3000/images/ubuntu.img \
-destinationDevice /dev/sda
Read a disk from a remote server
go run server/server.go \
-action readImage \
-mac 00:50:56:a5:0e:0f \
-destinationAddress http://192.168.0.95:3000/image \
-sourceDevice /dev/sda
LVM & Disk Growth
Write an image, grow partition 1, and expand the root LVM volume:
go run server/server.go \
-action writeImage \
-mac 00:50:56:a5:0e:0f \
-sourceImage http://192.168.0.95:3000/images/ubuntu.img \
-destinationDevice /dev/sda \
-growPartition 1 \
-lvmRoot /dev/ubuntu-vg/root \
-shell
Feature Gates
| Variable |
Default |
Description |
MODE |
provision |
provision, deprovision, soft-deprovision, or standby |
DISABLE_KEXEC |
false |
Skip kexec, always hard-reboot |
MIN_DISK_SIZE_GB |
0 |
Minimum disk size filter (0 = no minimum) |
MACHINE_EXTRA_KERNEL_PARAMS |
— |
Additional kernel cmdline parameters |
HEARTBEAT_URL |
— |
Standby mode: URL for periodic keepalives |
COMMANDS_URL |
— |
Standby mode: URL to poll for pending commands |
SECURE_ERASE |
false |
Use NVMe format / ATA secure erase instead of partition wipe |
STATIC_IP |
— |
Static IP in CIDR notation (e.g. 10.0.0.5/24) |
STATIC_GATEWAY |
— |
Default gateway for static networking |
STATIC_IFACE |
— |
Interface for static IP (auto-detect if empty) |
BOND_INTERFACES |
— |
Comma-separated interfaces for LACP bond (e.g. eth0,eth1) |
BOND_MODE |
802.3ad |
Bond mode: 802.3ad/lacp, balance-rr, active-backup, balance-xor |
POST_PROVISION_CMDS |
— |
Semicolon-separated commands to run in chroot after provisioning |
Debugging
| Flag |
Description |
-shell |
Drop to a BusyBox shell if something fails |
-wipe |
Wipe the provisioned disk on failure |
-dryRun |
Log actions without writing to disk |
OCI Image Sources
BOOTy supports pulling disk images from OCI-compliant container registries. Use the
oci:// URL scheme in the IMAGE variable:
# Unauthenticated registry
export IMAGE="oci://ghcr.io/myorg/os-images:ubuntu-22.04"
# Authenticated registry (credentials from standard Docker config)
export IMAGE="oci://registry.example.com/images:rhel-9"
The OCI image must contain exactly one layer with the disk image (optionally compressed).
Authentication uses the standard Docker credential chain (~/.docker/config.json,
DOCKER_CONFIG, credential helpers). Both docker.io and OCI-spec registries are
supported via go-containerregistry.
HTTP and OCI fetches are retried up to 3 times with exponential backoff (1s, 2s, 4s).
Network Modes
BOOTy supports multiple network modes with automatic fallback:
| Priority |
Mode |
Trigger |
Description |
| 1 |
Bond |
BOND_INTERFACES set |
Creates bond0 (LACP/802.3ad) from listed interfaces |
| 2 |
GoBGP/EVPN |
NETWORK_MODE=gobgp |
Pure-Go BGP+EVPN via GoBGP (see below) |
| 3 |
FRR/EVPN |
underlay_subnet+asn_server set |
BGP underlay with VXLAN overlay (FRR) |
| 4 |
Static |
STATIC_IP set |
Assigns IP via netlink, adds default route |
| 5 |
DHCP |
Default |
Tries DHCP on all physical interfaces |
Bond mode creates the bond interface first, then the selected upper mode (FRR/Static/DHCP)
runs on top of it. Each mode falls back to DHCP on failure.
GoBGP Mode
Set NETWORK_MODE=gobgp to use the pure-Go BGP stack instead of FRR. GoBGP mode
uses a three-tier architecture:
- Underlay — eBGP peering with leaf switches for VXLAN reachability
- Overlay — EVPN Type-5 routes with VXLAN encapsulation
- IPMI — Optional L3 path to the BMC (planned)
The BGP_PEER_MODE environment variable controls session establishment:
| Mode |
Description |
unnumbered (default) |
Link-local interface peers — IPv4 + L2VPN-EVPN over unnumbered sessions |
dual |
Unnumbered underlay (IPv4) + numbered peers for L2VPN-EVPN (route reflectors or DCGWs) |
numbered |
Explicit neighbor IPs only — requires DHCP or static underlay for initial connectivity |
Additional environment variables for GoBGP mode:
BGP_NEIGHBORS — Comma-separated peer IPs (required for dual and numbered modes)
BGP_REMOTE_ASN — Remote ASN for numbered peers (0 or omitted = iBGP)
Extending Bundled Binaries
The initramfs is built in initrd.Dockerfile using a multi-stage Docker build. To add
a new binary:
- Install the package in the
tools build stage:
# In the 'tools' stage (FROM alpine AS tools)
RUN apk add --no-cache your-package
- Copy the binary into the final initramfs:
# In the builder stage
COPY --from=tools /usr/sbin/your-binary sbin/your-binary
- Verify all shared library dependencies are satisfied:
# Inside the container
ldd /usr/sbin/your-binary
Currently bundled binaries: mdadm, wipefs, sfdisk, sgdisk, e2fsck,
resize2fs, xfs_growfs, xfs_repair, btrfs, parted, kpartx, lvm,
hdparm, nvme, mstconfig, mstflint, lldpcli, lldpd, efibootmgr.
Prefer Go libraries: Where possible, use Go syscalls or libraries instead of
shelling out to external binaries. Examples: unix.FinitModule() instead of insmod,
syscall.SysProcAttr{Chroot} instead of chroot, sysfs reads instead of lspci.
Development
# Run unit tests with coverage
make test
# Run E2E tests (Linux only)
go test -tags e2e -v -race ./test/e2e/...
# Run linter
make lint
# Build binary
make build
Project Structure
├── main.go # Entry point: CAPRF vs legacy mode, kernel module loading
├── cmd/booty.go # Legacy CLI orchestration
├── server/server.go # Legacy provisioning server
├── initrd.Dockerfile # Multi-stage initramfs build (default, iso, slim, micro)
├── pkg/
│ ├── caprf/ # CAPRF client (status, log, debug, vars parsing)
│ ├── config/ # MachineConfig, Provider interface, Status types
│ ├── disk/ # Disk detection, partitioning, RAID, LVM, mount
│ ├── image/ # Image streaming (HTTP, OCI, gzip/lz4/xz/zstd auto-detect)
│ ├── kexec/ # GRUB parsing, kexec load/execute
│ ├── network/ # Network mode abstraction (FRR, DHCP, Static, Bond)
│ │ ├── frr/ # FRR/EVPN: config rendering, address derivation
│ │ └── lldp/ # LLDP frame listener (raw AF_PACKET sockets)
│ ├── provision/ # Orchestrator (24-step provision, deprovision)
│ │ └── configurator.go # OS config: hostname, kubelet, GRUB, DNS, EFI, Mellanox SR-IOV
│ ├── plunderclient/ # Legacy HTTP client for config retrieval
│ ├── realm/ # Device, mount, network, shell operations
│ ├── utils/ # Cmdline parsing, helpers
│ └── ux/ # ASCII art & system info display
├── test/e2e/ # E2E tests (ContainerLab + vrnetlab EVPN fabric)
│ ├── clab/ # ContainerLab topologies and FRR configs
│ │ └── vrnetlab/ # QEMU VM image builder for vrnetlab testing
│ └── integration/ # Integration test suites
├── docs/ # Design documents and proposals
├── .github/workflows/ # CI (lint, test, build, E2E clab, E2E vrnetlab, KVM boot)
└── .golangci.yml # Linter configuration
Contributing
See CONTRIBUTING.md for development setup, coding standards, and the PR process.
License
This project is licensed under the Apache License 2.0 — see LICENSE for details.