Harvester Reinstall Runbook — harvester.sthings.lab¶
Single-node Harvester demo/test cluster in the sthings.lab homelab.
This captures the exact configuration of the rebuild so it can be reproduced
by any method (TUI wizard, automated config.yaml, PXE, or IaC).
Scope: clean reinstall, not upgrade. No VM/Longhorn data is preserved. Only network and cluster config is reproduced; VM disks are recreated from scratch.
Version & install method¶
| Item | Value |
|---|---|
| Product | Harvester (SUSE Virtualization) |
| Version | v1.8.0 (GA) |
| Topology | Single node, mode: create |
| Install method used | Full ISO → interactive TUI wizard |
| Full ISO | https://releases.rancher.com/harvester/v1.8.0/harvester-v1.8.0-amd64.iso |
| Checksum | https://releases.rancher.com/harvester/v1.8.0/harvester-v1.8.0-amd64.sha512 |
| Base OS | SL Micro 6.2 |
For exact embedded component versions (RKE2 / KubeVirt / Longhorn / Rancher), see the v1.8.0 release notes: https://github.com/harvester/harvester/releases/tag/v1.8.0 and docs at https://docs.harvesterhci.io/v1.8.
ISO verification before flashing:
1 2 3 | |
Node identity¶
| Field | Value |
|---|---|
install mode |
create |
install role |
default |
hostname |
harvester (resolves as harvester.sthings.lab via DD-WRT expand-hosts) |
token |
Atlan7is |
password |
set at install — mandatory in v1.7+, plaintext, not recoverable from old hash |
| SSH keys | supply current workstation pubkey (none were stored in old /oem) |
Management network¶
Single physical uplink, configured as an active-backup bond (single member), static addressing.
| Field | Value |
|---|---|
| Interface (NIC) | enp5s0 |
MAC (hwAddr) |
58:47:ca:7d:34:f0 |
| Bond mode | active-backup |
Bond miimon |
100 |
| Method | static |
| IP | 192.168.10.110 |
| Subnet mask | 255.255.255.0 (/24) |
| Gateway | 192.168.10.1 |
| DNS | 192.168.10.1 |
| NTP | 0.suse.pool.ntp.org |
| MTU | 1500 (default) |
| Management VLAN | none (untagged) |
Note: the node IP
.110also has a DD-WRT static reservation, somethod: dhcpwould also work. Static was chosen to remove the dependency on the reservation.
VIP (cluster access — UI + Kubernetes API)¶
| Field | Value |
|---|---|
| VIP | 192.168.10.139 (confirm/adjust — see note) |
| VIP mode | static (recommended) |
Decision: the original install used a DHCP VIP (random kube-vip MAC, address from the dynamic pool). On rebuild this is fragile — a DHCP VIP cannot be pre-reserved on the router (no stable MAC), and the address is not guaranteed back.
Use a static VIP outside the DHCP dynamic range (
192.168.10.100–149). Either move it below the pool (e.g.192.168.10.50) or shrink the pool so.139falls outside it. Confirm the actual running value with:
1kubectl get cm vip -n harvester-system -o yaml | yq '.data'
Cluster-internal CIDRs¶
Left at defaults (blank in the installer). Internal overlay ranges only — they
never touch the 192.168.10.0/24 LAN, so no conflict.
| Field | Default | Notes |
|---|---|---|
| Pod CIDR | 10.52.0.0/16 |
|
| Service CIDR | 10.53.0.0/16 |
|
| Cluster DNS | 10.53.0.10 |
must sit inside the service CIDR |
Gotcha: the vm-dhcp-controller addon also defaults its internal service CIDR to
10.53.0.0/16. Only an issue if you change the cluster service CIDR and forget to update the addon. Staying on defaults avoids it. (Not in use here — see networking model.)
Disks¶
⚠️ Critical: this host has a Windows disk that must never be selected.
| Disk | Device | Role | Action |
|---|---|---|---|
| Samsung SSD 990 EVO Plus 2TB | nvme1n1 |
Install + Longhorn (single-disk) | ✅ SELECT |
| WD_BLACK SN850X 931.5G | nvme0n1 |
NTFS / Windows Data volume |
❌ NEVER TOUCH |
| VIRTUAL-DISK 40G/50G | sda / sdb |
scratch / leftover | ❌ ignore |
Install disk selection:
| Field | Value |
|---|---|
| Installation disk | nvme1n1 (nvme-Samsung_SSD_990_EVO_Plus_2TB_S7U7NJ0YA04645J) |
| Data disk | "Use the installation disk" (single-disk; OS + Longhorn share nvme1n1) |
| Persistent size | 558Gi |
In the install confirmation screen, "Use the installation disk" is rendered as
data_disk: /dev/nvme1n1(same path asdevice). This is correct for a single-disk layout — not a misconfiguration. The remainder of the 2TB after the 558GiCOS_PERSISTENTpartition becomes the LonghornHARV_LH_DEFAULTpartition.Always pin the disk by
/dev/disk/by-id/...when scripting —/dev/nvmeXn1enumeration can reorder across reboots.
Networking model (how addressing actually works)¶
This cluster uses the simplest possible network layout — worth understanding before reproducing:
- Cluster network: only the built-in
mgmt(auto-created by the installer). No custom cluster networks. - VM network: a single NAD named
vms, untagged, bridged ontomgmt-br. - No VlanConfigs — VM traffic rides the management network directly.
- No managed DHCP — the
vm-dhcp-controlleraddon is not enabled.ipam: {}. - Addressing source: DD-WRT (the homelab router) hands out all VM and node leases.
The VM network NAD (vms) config:
1 2 3 4 5 6 7 8 | |
Labels: clusternetwork: mgmt, type: UntaggedNetwork, ready: true.
Implication for rebuild: reproducing the management interface (above) is what makes
mgmt-brexist; thevmsNAD then attaches to it and VMs get IPs from DD-WRT. There is nothing managed-DHCP / IP-pool related to restore.
Router (DD-WRT) — 192.168.10.1¶
LAN / DHCP¶
| Field | Value |
|---|---|
| Router IP | 192.168.10.1/24 |
| DHCP | enabled, DHCP Server |
| DHCP pool | 192.168.10.100 – 192.168.10.149 (start .100, max 50) |
| Lease | 43200 min (30 days) -- was 1440 until 2026-09-21 |
The lab is often off for days. With a 24h lease the VMs came back on new
addresses, and a single-node RKE2/k3s cluster does not survive that: etcd keeps
the old peer URL (homerun2-dev, .117 -> .118, harvester#238). Every node
that runs Kubernetes gets a static lease; the long lease time covers the rest
(Rancher pool nodes, fresh VMs). Build-time automation: stuttgart-things/clusterbook#211.
Static leases (nvram static_leases / static_leasenum, DD-WRT renders them as
dhcp-host=...,infinite):
| MAC | Hostname | IP |
|---|---|---|
58:47:CA:7D:34:F0 |
harvester |
192.168.10.110 |
00:E0:4C:A2:63:AA |
platform |
192.168.10.134 |
00:E0:4C:68:1F:05 |
sthings-air12 |
192.168.10.146 |
BA:B3:3E:EA:51:F3 |
homerun2-dev |
192.168.10.117 |
BA:69:A8:A3:BA:28 |
crossplane-mgmt |
192.168.10.108 |
BE:64:F3:26:1A:60 |
machinery-hv |
192.168.10.105 |
B8:27:EB:D9:33:DB |
matrix |
192.168.10.120 |
The VM MACs are pinned in the Harvester VM spec, so they survive reboots but not a rebuild -- a rebuilt VM needs its entry updated.
VIP placement rule: the static VIP must be outside
192.168.10.100–149, or the router can lease the VIP address to another client. Either use an IP below the pool (e.g..50) or shrink the pool (e.g. max users 30 → ends at.129, freeing.130–.149).
dnsmasq (DNS for sthings.lab)¶
Additional Options currently set:
1 2 3 4 | |
Also set: host-record=matrix.sthings.lab,192.168.10.120, the led-catcher Pi
(hosts/matrix/).
Recommended addition for the VIP (gives it a stable name + PTR; use a name that does
not collide with the harvester node lease):
1 | |
No DNS Rebindis enabled — harmless for the cluster (internal resolution doesn't traverse the router), but it will drop public hostnames that resolve to192.168.10.x.
Equivalent automated config.yaml¶
For reproducing via automatic install / PXE instead of the wizard
(scheme_version: 1 is stable across recent releases):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | |
Post-install restore (config objects)¶
After the node is up and mgmt/management show green:
1. Fresh kubeconfig¶
The host SSH key changes on reinstall — clear the stale entry first:
1 2 3 4 5 | |
2. VM network — inline (the only networking object to restore)¶
mgmt is auto-created by the installer; VlanConfigs were empty; IP pools/managed DHCP
are not in use. So the entire networking restore is this single NAD, defined inline
below — no backup files needed:
1 2 3 4 5 6 7 8 9 10 11 12 | |
The controller fills in network.harvesterhci.io/ready: "true" and the connectivity
status after apply. (Harvester's UI also adds a cosmetic network.harvesterhci.io/route
annotation — optional; the NAD works without it.)
3. Trust the sthings.lab CA¶
Do this before restoring images — they are fetched over HTTPS from the artifact store and Harvester verifies that certificate itself.
1 2 | |
Run it from a checkout of this repo — a wrong path makes cat fail, jq yields an
empty string and the patch silently wipes the setting.
The CA lives at packer/_build/sthings-lab-ca.crt,
issued by the OpenBao PKI on the platform cluster (the sthings.lab PKI moved off the
decommissioned infra Vault — issue #152). Watch out when diagnosing this: the old and
new CAs share the subject C=DE, O=sva, CN=sthings.lab and differ only by key, so a
stale one fails as x509: certificate signed by unknown authority ... crypto/rsa:
verification error rather than as an obvious name mismatch. Compare fingerprints, not
subjects:
1 2 | |
4. VM images¶
VM images are download-type: Harvester pulls the qcow2 from the MinIO artifact store
itself, so an image can be recreated from a VirtualMachineImage YAML — as long as the
artifact is still published and step 3 is done. They used to be upload-type, until pushing
the ~1.8 GB body through the nginx in front of the VIP started dying on its 60 s
proxy-read-timeout (issue #215).
The record below is provenance, not a manifest dump: it says how to rebuild the artifact, which is what a manifest cannot capture.
u26-dev — Ubuntu 26 dev base image:
| Field | Value |
|---|---|
| Name / display | u26-dev |
| Namespace | default |
| Image type | raw_qcow2 |
| OS type | linux |
| Virtual size | 10 Gi |
| Storage class | harvester-longhorn |
| Source type | download |
| Encryption | false |
| Built by | Packer — stuttgart-things/harvester → packer/dev/u26-dev |
Cloud-init (packer/dev/u26-dev/users.yaml) provisions a sthings user with passwordless
sudo and the workstation SSH keys baked in — so VMs from this image are SSH-ready with no
Harvester keypair attachment required.
Reproduce: run the Packer Build workflow (workflow_dispatch, image dev/u26-dev,
Upload to Harvester on). It builds the qcow2, publishes it to MinIO and registers it.
See packer/README.md for the manual equivalent and for why image
names are versioned and never replaced in place.
Templates (
virtualmachinetemplates/ versions): recreate via UI as needed. Not inlined — for a demo cluster they're cheap to rebuild and not worth committing as dumps.Not restored (intentionally): IP pools /
vmnetcfgs(managed DHCP not in use), Longhorn/VM disk data (wiped),mgmtcluster network (auto-created), node-local status objects (blockdevices, vlanstatuses, hugepages, etc.).
Verification checklist¶
1 2 3 4 5 | |
UI/API reachable at https://<VIP> (and https://harvester-vip.sthings.lab if the DNS record was added).