Move to a three-node cluster with a Talos VIP; add Longhorn

Every node is now both control plane and worker, giving real tolerance
for losing any single machine (etcd quorum needs 3, not 1). A Talos VIP
gives the cluster one stable address regardless of which node answers.

Also pre-installs Longhorn for replicated storage, backed by a Talos
UserVolume on each node's second disk (>=900GB, non-system) rather than
the default path — mirroring the pattern from the homescale repo.

Docs renumbered to make room for 06-longhorn.md; checklist, glossary,
network map, and CLAUDE.md's guided-bootstrap instructions updated to
match, including asking the user for node IPs, VIP, and disk info before
generating any Talos config.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Maxwell Morris
2026-08-22 18:25:38 +01:00
co-authored by Claude Sonnet 5
parent 92c3ad3191
commit 110bd97cca
26 changed files with 777 additions and 261 deletions
+25 -13
View File
@@ -59,7 +59,16 @@ end to end" — drive [`docs/checklist.md`](docs/checklist.md) interactively:
6. Periodically remind them of `docs/glossary.md` and the "Ask Claude"
checkpoints along the way — this mode shouldn't feel like a script being
read at them.
7. **Phase 5 (MetalLB) needs real information from the user, not
7. **The Talos phase (docs/02) needs real information too, before any
config is generated.** Ask: what are the three nodes' IP addresses (or
DHCP reservations), and — separately — what unused address should the
cluster's VIP use? The VIP is a fourth address, distinct from all three
node IPs and from the MetalLB pool (below); it needs the same "ask about
their LAN and DHCP range" treatment as MetalLB. Also confirm each node
actually has a second disk ≥900GB before they generate config — if not,
that's a real constraint on `talos/patch-longhorn.yaml`'s `minSize`, not
something to paper over with a placeholder.
8. **The MetalLB phase (docs/05) needs real information from the user, not
placeholders.** Before editing `apps/metallb/templates/ipaddresspool.yaml`
or `apps/demo/service.yaml`, actually ask: what does their LAN's subnet
look like, and what IP range does their router's DHCP server already
@@ -80,10 +89,12 @@ useful if it's actually current, so treat updating it as part of the
change itself, not an afterthought:
- Whenever you (Claude) assign, learn, or change a real IP address for
something — walking the user through MetalLB's pool
([`docs/05-metallb.md`](docs/05-metallb.md)), patching `argocd-server`,
helping add a new app with a `LoadBalancer` Service — update the table in
`docs/network.md` in the same breath. Don't wait to be asked.
something — the three node addresses and VIP in
[`docs/02-talos-bootstrap.md`](docs/02-talos-bootstrap.md), walking the
user through MetalLB's pool ([`docs/05-metallb.md`](docs/05-metallb.md)),
patching `argocd-server`, helping add a new app with a `LoadBalancer`
Service — update the table in `docs/network.md` in the same breath.
Don't wait to be asked.
- Every row needs a full, correct URL — scheme, IP, and port — not just a
bare address. Include the port number unless it's the protocol's default
(80 for `http://`, 443 for `https://`). If you're not sure what port a
@@ -101,7 +112,7 @@ Point new users here first if they seem unsure where to start:
1. [`README.md`](README.md) — orientation
2. [`docs/00-what-is-all-this.md`](docs/00-what-is-all-this.md) — mental model, read before touching a terminal
3. [`docs/01-prerequisites.md`](docs/01-prerequisites.md) → [`08-growing-up.md`](docs/08-growing-up.md) — in order
3. [`docs/01-prerequisites.md`](docs/01-prerequisites.md) → [`docs/09-growing-up.md`](docs/09-growing-up.md) — in order
4. [`docs/checklist.md`](docs/checklist.md) — condensed step-by-step reference once concepts are understood, or to drive Guided Bootstrap Mode
5. [`docs/glossary.md`](docs/glossary.md) — reference throughout, not read start to finish
@@ -116,17 +127,18 @@ If asked to change manifests or docs rather than explain them:
`argocd/`.
- Keep the moving parts minimal. Ingress, cert-manager, and secrets
management are intentionally **documented, not shipped** (see
[`docs/08-growing-up.md`](docs/08-growing-up.md)) — don't add them to
make the repo "more complete" without being asked. MetalLB is the one
exception, shipped deliberately because bare metal has no other way to
give a Service a real IP address — don't take that as license to add
other addons the same way without being asked.
[`docs/09-growing-up.md`](docs/09-growing-up.md)) — don't add them to
make the repo "more complete" without being asked. MetalLB and Longhorn
are the two exceptions, shipped deliberately because bare metal has no
other way to give a Service a real IP address or give an app real
persistent storage — don't take that as license to add other addons the
same way without being asked.
- This repo is **public**. Never write a plaintext secret, credential, or
private key into any file here. If a change would need one, stop and
point to the Sealed Secrets / SOPS guidance in
`docs/08-growing-up.md` instead of improvising.
`docs/09-growing-up.md` instead of improvising.
- New apps follow the existing `apps/<name>.yaml` + `apps/<name>/` pattern
— see [`docs/07-adding-new-apps.md`](docs/07-adding-new-apps.md) before
— see [`docs/08-adding-new-apps.md`](docs/08-adding-new-apps.md) before
adding one. `apps/metallb/` is the reference example for a Helm-based
one.
- Every `apps/*.yaml` Application manifest needs its own `repoURL` fixed to