madbox
Blog
SUSE Edge Image Builder

Automating Infrastructure with Edge Image Builder

17 July 2026 · 18 min read

SUSE's Edge Image Builder (EIB) skips config management entirely: describe a cluster in one YAML definition, and it hands back a self-installing ISO that partitions the disk, installs the OS, and bootstraps RKE2 on first boot. No PXE server, no Ansible run, no manual kubeadm join. I started from a reference definition for a full SUSE Observability stack — five nodes, three servers and two agents, with cert-manager, Longhorn, MetalLB, ingress-nginx, and the observability charts themselves all baked in. Before touching any of that on real hardware, I stripped it down to see if the basic mechanism worked at all.

One Build, Not Two

The whole exercise was one build, validated once in a disposable VM, then written straight to the five physical boxes — nothing rebuilt for hardware. The VM's only job was answering “does this image even install and boot” somewhere free to fail, before trusting the same file to real disks.

BUILD VM TEST PHYSICAL DEPLOYMENT fails → fix → rebuild boots clean — same ISO, no rebuild Reference Definition 6 Helm charts · 5 nodes Strip to One Node RKE2 + Calico only KVM Test VM disposable · free to fail 5 Real Nodes real NICs · disks · apiVIP SMART-Test Disks verify before they join Production serving real traffic
one ISO, validated in a disposable VM, then written to real hardware unchanged

Building the ISO

EIB ships as a container, not a package — building the ISO is a podman run against it with the working directory bind-mounted in. This all assumes a SL Micro 6.x host with podman installed; having KVM on the same box makes the VM-test phase practical too.

build.sh
podman run --rm -it \
  --privileged \
  -v "${SCRIPT_DIR}":/eib \
  "${EIB_IMAGE}" \
  build --definition-file "${DEFINITION_FILE}"

--privileged is needed because EIB loop-mounts and manipulates the base ISO and the raw disk image it builds on top of it.

./build.sh — screen recording, no audio, 8x speed

The Installer That Wouldn't Say Anything

First boot in the test VM produced nothing on the console — not an error, just silence. The inherited kernel args included quiet, suppressing all boot output including whatever the kiwi imaging step was doing to the disk. Getting a usable picture took:

NMState Doesn't Know It's a VM

The network config was written against real hardware and named the interface em1 — a biosdevname-style name. KVM's virtio NICs don't get biosdevname names; they come up as predictable enp* names instead, so the interface never came up in the VM until renamed to match.

The tell: if an NMState interface name looks like a physical NIC naming scheme and the target is a VM, check what the hypervisor's NIC actually enumerates as before assuming the YAML is wrong.

Two Bugs, Baked Permanently into the Image

Two first-boot scripts fix things that only show up after watching a boot fail once:

Five Real Boxes Called Lenny

The cluster's called Lenny because the machines are Lenovo M910q tiny-form-factor PCs — the name is just what's left of “Lenovo” once you're naming five of them after it. RKE2 v1.33.3+rke2r1 with Calico, three servers and two agents, an apiVIP fronting the HA control plane:

HostRoleIP
lenny1.shed.localserver (initializer)172.16.0.11
lenny2.shed.localserver172.16.0.12
lenny3.shed.localserver172.16.0.13
lenny4.shed.localagent172.16.0.14
lenny5.shed.localagent172.16.0.15

Trusting Real Disks Before Real Data Goes on Them

A disposable VM's disk doesn't have a failure mode worth testing for; five physical drives about to hold real data do. Each one gets a SMART extended self-test, polled every 30 seconds until it completes, then checked for reallocated sectors, pending sectors, and uncorrectable offline sectors.

Why bother: it's the difference between finding out a drive is marginal now, before it's holding etcd data, versus finding out during a write six months in.

Completing the Definition

A few real gaps got closed after the fact. cert-manager, Longhorn, and MetalLB — all stripped for the single-node test image — are back, verified against the real Helm repos rather than assumed (a lesson learned the hard way: cert-manager and MetalLB were both wrongly assumed to live in the same repo as Longhorn, and neither does). apiHost came back alongside apiVIP, with a tls-san entry so clients connecting via the VIP don't hit a TLS mismatch. And checking each physical node directly turned up a second disk (/dev/nvme0n1, ~932G) on every box, dedicated to Longhorn storage, that nothing in the definition had ever declared — now provisioned by a first-boot script that never reformats a disk that already has a filesystem on it.

None of the individual pieces here were exotic. What mattered was the order: strip a six-chart, five-node definition down to the smallest thing that could possibly boot, prove the imaging mechanism itself worked in a VM where failure is free, then scale back up one real constraint at a time instead of debugging all of it, on real hardware, at once.