Files
Maxwell MorrisandClaude Sonnet 5 110bd97cca 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>
2026-08-22 18:25:38 +01:00

6.2 KiB

Guided bootstrap checklist

A single-page, ordered checklist covering the entire path from bare machines to a working GitOps loop. It's meant to be worked through with Claude, one item at a time — ask Claude to walk you through this list, and it will run each step with you, wait for your output, confirm it worked, and only then move to the next one. See CLAUDE.md at the repo root for how Claude is primed to do this.

Each item names the doc it's drawn from, in case you want the full explanation before or after running it. Replace <NODE1_IP>/<NODE2_IP>/<NODE3_IP>, <VIP_IP>, YOUR_GITHUB_USERNAME, and the MetalLB IP addresses with your real values throughout — Claude will remind you if you paste a command still containing a placeholder, and will ask you for all of these directly in Phases 2 and 5 rather than guessing them.

Phase 1 — Prerequisites (01)

  • Three target machines chosen, each network-reachable, each with a stable (ideally DHCP-reserved) IP address, each with a second disk ≥900GB set aside for Longhorn
  • Custom Talos schematic built at factory.talos.dev with iscsi-tools and util-linux-tools, ISO downloaded
  • All three machines booted from that ISO, sitting at the boot screen
  • talosctl version --client runs successfully
  • kubectl version --client runs successfully
  • argocd version --client runs successfully
  • Repo forked on GitHub and cloned locally as your own copy

Phase 2 — Talos bootstrap (02, talos/README.md)

  • Ask Claude to help pick: your three nodes' IP addresses (or confirm DHCP reservations) and a separate VIP address — all based on your actual LAN/DHCP setup
  • talosctl gen config gitops-starter https://<VIP_IP>:6443 --output-dir _out --config-patch-control-plane @talos/patch-controlplane.yaml --config-patch-control-plane @talos/patch-longhorn.yaml run — _out/controlplane.yaml, worker.yaml, talosconfig exist
  • TALOSCONFIG exported (or talosctl config endpoint/node set) to _out/talosconfig
  • For each of the three nodes: talosctl get disks --insecure --nodes <NODE_IP> confirms two disks, then talosctl apply-config --insecure --nodes <NODE_IP> --file _out/controlplane.yaml run, node rebooted
  • talosctl bootstrap --nodes <NODE1_IP> run — exactly once, against exactly one node
  • talosctl kubeconfig --nodes <VIP_IP> . run, KUBECONFIG pointed at the result
  • kubectl get nodes shows all three nodes, Ready
  • docs/network.md updated with all three node addresses and the VIP

Phase 3 — Argo CD install (03, argocd/README.md)

  • kubectl create namespace argocd
  • kubectl apply --server-side -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
  • kubectl -n argocd wait --for=condition=Available --timeout=300s deployment --all completes
  • Initial admin password retrieved
  • kubectl -n argocd port-forward svc/argocd-server 8080:443 running in its own terminal
  • argocd login localhost:8080 --username admin --password <pw> --insecure succeeds

Phase 4 — Hand the cluster to Git (04)

  • spec.source.repoURL fixed in all four placeholder files: run grep -rl YOUR_GITHUB_USERNAME . to find them (argocd/app-of-apps/app-of-apps.yaml, apps/demo.yaml, apps/metallb.yaml, apps/longhorn.yaml)
  • Edit committed and pushed to your fork's main branch
  • kubectl apply -f argocd/app-of-apps/app-of-apps.yaml
  • argocd app list shows app-of-apps, Synced/Healthy
  • argocd app list shows demo, metallb, and longhorn, appeared automatically, all Synced/Healthy
  • kubectl -n demo get pods,svc shows the demo app's Pod running (Service EXTERNAL-IP still <pending> — expected for now)

Phase 5 — MetalLB: real IP addresses (05)

  • Ask Claude to help pick: a MetalLB pool range, an address for Argo CD's UI, and an address for the demo app — all based on your actual LAN/DHCP setup
  • apps/metallb/templates/ipaddresspool.yaml edited to your real pool range
  • apps/demo/service.yaml edited to your real demo app address
  • docs/network.md updated with the pool range and both addresses (Argo CD's added once patched, below)
  • Committed, pushed, and synced (argocd app sync metallb demo)
  • kubectl -n demo get svc demo shows a real EXTERNAL-IP; page loads at http://<that-address>
  • argocd-server Service patched to LoadBalancer with your chosen Argo CD address (kubectl -n argocd patch svc argocd-server ...)
  • Argo CD UI reachable at https://<that-address> with no port-forward running

Phase 6 — Longhorn: real storage (06)

  • kubectl -n longhorn-system get pods shows manager/CSI Pods Running on all three nodes
  • kubectl get storageclass shows a default longhorn StorageClass
  • (Optional) Gave the demo app a real PVC and confirmed it's Bound with a healthy, replicated Longhorn volume behind it

Phase 7 — Prove the loop (07)

  • Edited the <h1> text in apps/demo/configmap.yaml
  • Committed and pushed
  • argocd app sync demo (or waited for auto-poll) shows the change applied
  • Refreshed the browser — new text visible
  • (Optional) Triggered self-heal: hand-edited the ConfigMap with kubectl patch, confirmed Argo CD reverted it

You're done when

Every box above is checked, you've watched a change you made in a text editor show up in a browser without ever running kubectl apply yourself for it, and you can explain in your own words what happened between "git push" and the page updating. If you can't yet, that's the sign to ask Claude for a walkthrough of whichever phase felt shaky before calling this finished.

From here: 08-adding-new-apps.md to add something of your own, or 09-growing-up.md for the bigger next steps (more nodes, ingress, secrets management).