corvus
ADR 0002 accepted relates to ADR 0001

Unattended Arch install for cluster nodes

Context

ADR 0001 decided that the x86 nodes (four ThinkCentre M715q, one ThinkPad T430, later the Omarchy T430) run Arch installed from a custom archiso image, with Ansible taking over at first SSH. This record settles what that image does, drawing on the operator’s existing manual install notes for the T430 workstation and dropping what does not apply to a headless cluster node.

The operator has a GL.iNet KVM reachable over Tailscale. It is an emergency tool and deliberately not part of the install path.

Decisions

Fully unattended

The ISO boots, installs, and reboots with no console interaction. No hostname prompt, no passphrase, no KVM. Per box the workflow is: plug in the USB stick, power on, wait for the reboot into the installed system, pull the stick.

No disk encryption

Nodes get a plain disk. Common practice for bare-metal Kubernetes nodes: the OS disk holds nothing secret by design, nodes must reboot unattended, and encryption belongs at the data layer. Sensitive data is protected by Longhorn encrypted volumes (LUKS per PVC, key in a Kubernetes Secret) and etcd encryption at rest. TPM2 auto-unlock was considered (the M715q has an AMD fTPM) but it adds ISO work for a threat (a stolen drive from a home desktop) that the data layer already covers, and the T430 has no TPM2.

Disk layout

GPT, UEFI, two partitions:

PartitionSizeUse
11 GBEFI system partition, FAT32, /boot
2restLVM physical volume

One volume group with two logical volumes:

LVSizeMount
root40 GB, ext4/ (includes /var/lib/rancher/k3s, so larger than the 32 GB workstation default)
longhornremaining, ext4/var/lib/longhorn

No swap (kubelet refuses to start with swap on by default). No /home. LVM is kept so root can be resized without a reinstall and so a full Longhorn disk cannot wedge the OS.

Target disk selection: the first non-removable disk that is not the boot medium. The script refuses to run if more than one disk matches, so a box with an unexpected second disk is never wiped by surprise.

Identity

Hostname at install is arch-<last three bytes of the primary NIC MAC>, unique and recognisable in the UniFi client list but not meaningful. Ansible renames the box from a MAC-keyed static inventory in platform/ansible/, which is the single place MACs are typed; the same list feeds the UniFi fixed-IP entries in platform/infra (ADR 0001).

Networking is DHCP on any ethernet interface via systemd-networkd, with systemd-resolved. The node never carries an address; the fixed IP is assigned by UniFi.

What the ISO installs

Packages: base linux linux-firmware lvm2 openssh sudo plus amd-ucode or intel-ucode chosen by CPU vendor at install. Nothing else.

Configuration baked in:

Everything else is Ansible: mirrorlist and reflector, editors and tools, k3s binary and config, open-iscsi and nfs-utils for Longhorn, sysctl tuning, firewall, the etcd snapshot cron on servers. No Tailscale on nodes; remote access goes through the in-cluster Tailscale operator (ADR 0001).

Build and test

platform/iso/ holds the archiso profile and the install script. ahoy iso build runs mkarchiso directly on the Omarchy T430 for fast iteration. Once the profile is stable, the build moves to a privileged archlinux container (Dockerfile in the same directory) and a GitLab CI job on main attaches the ISO to a release, so a known-good image exists without a local Arch box. ahoy iso burn <device> wraps the dd procedure from the operator’s notes.

Testing is on real hardware. A QEMU/OVMF harness was considered but the flash-and-boot cycle on five identical boxes is short enough not to need it.

Consequences