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:
| Partition | Size | Use |
|---|---|---|
| 1 | 1 GB | EFI system partition, FAT32, /boot |
| 2 | rest | LVM physical volume |
One volume group with two logical volumes:
| LV | Size | Mount |
|---|---|---|
root | 40 GB, ext4 | / (includes /var/lib/rancher/k3s, so larger than the 32 GB workstation default) |
longhorn | remaining, 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:
- user
opswith the operator’s SSH public key (committed in the profile, it is public), passwordless sudo - sshd: key-only, no root login, no root password set
- systemd-boot with a single entry;
mkinitcpiohooksbase systemd autodetect microcode modconf kms keyboard sd-vconsole block lvm2 filesystems fsck - locale
en_US.UTF-8, timezoneAmerica/Argentina/Buenos_Aires, systemd-timesyncd enabled /var/lib/longhornin fstab
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
- The ISO never changes per box. A new node is: flash, boot, add its MAC to the inventory, run Ansible.
- Rebuilding and reflashing is only needed when the baked-in set changes (packages, the operator key, disk layout). Everything else is a playbook run.
- A box with two internal disks (none today) needs the selection rule extended before it can be installed.
- Losing a node’s disk loses nothing: the OS is reproducible from the ISO plus Ansible, and Longhorn re-replicates the volumes.