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>
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-toolsandutil-linux-tools, ISO downloaded - All three machines booted from that ISO, sitting at the boot screen
talosctl version --clientruns successfullykubectl version --clientruns successfullyargocd version --clientruns 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.yamlrun —_out/controlplane.yaml,worker.yaml,talosconfigexistTALOSCONFIGexported (ortalosctl config endpoint/nodeset) to_out/talosconfig- For each of the three nodes:
talosctl get disks --insecure --nodes <NODE_IP>confirms two disks, thentalosctl apply-config --insecure --nodes <NODE_IP> --file _out/controlplane.yamlrun, node rebooted talosctl bootstrap --nodes <NODE1_IP>run — exactly once, against exactly one nodetalosctl kubeconfig --nodes <VIP_IP> .run,KUBECONFIGpointed at the resultkubectl get nodesshows all three nodes,Readydocs/network.mdupdated with all three node addresses and the VIP
Phase 3 — Argo CD install (03, argocd/README.md)
kubectl create namespace argocdkubectl apply --server-side -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yamlkubectl -n argocd wait --for=condition=Available --timeout=300s deployment --allcompletes- Initial admin password retrieved
kubectl -n argocd port-forward svc/argocd-server 8080:443running in its own terminalargocd login localhost:8080 --username admin --password <pw> --insecuresucceeds
Phase 4 — Hand the cluster to Git (04)
spec.source.repoURLfixed in all four placeholder files: rungrep -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
mainbranch kubectl apply -f argocd/app-of-apps/app-of-apps.yamlargocd app listshowsapp-of-apps,Synced/Healthyargocd app listshowsdemo,metallb, andlonghorn, appeared automatically, allSynced/Healthykubectl -n demo get pods,svcshows the demo app's Pod running (ServiceEXTERNAL-IPstill<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.yamledited to your real pool rangeapps/demo/service.yamledited to your real demo app addressdocs/network.mdupdated 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 demoshows a realEXTERNAL-IP; page loads athttp://<that-address>argocd-serverService patched toLoadBalancerwith 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 podsshows manager/CSI PodsRunningon all three nodeskubectl get storageclassshows a defaultlonghornStorageClass- (Optional) Gave the demo app a real PVC and confirmed it's
Boundwith a healthy, replicated Longhorn volume behind it
Phase 7 — Prove the loop (07)
- Edited the
<h1>text inapps/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).