# 02 — Bootstrapping Talos At the end of this doc, you'll have a three-node Kubernetes cluster, running nothing but Kubernetes itself (plus the storage prep Longhorn needs later). No Argo CD yet — that's next. ## Why Talos, specifically Most guides have you install a general-purpose Linux distribution, then install Kubernetes on top by hand or with a tool like kubeadm — meaning there's a whole normal OS underneath, with a package manager, an SSH daemon, and every other thing that can drift out of a known-good state or need patching. Talos throws that away: it's an OS whose only job is running Kubernetes. There's no SSH, no shell to log into, no packages to manage — you configure it entirely by sending it a **machine config** file over the network (the `talosctl` commands below), and it applies that config the same declarative way Kubernetes applies your app manifests. Less surface area, less to secure, less to keep in sync by hand — the same philosophy as the rest of this stack, one layer lower. ## Three nodes, each both control plane and worker A "real" Kubernetes cluster has multiple nodes — some running the **control plane** (the brain: API server, scheduler, the cluster's own database, called etcd) and others as **workers** (running your actual apps) — so that losing one machine doesn't take the whole cluster down. This repo starts with three nodes, each acting as *both* control plane and worker, which gets you real resilience — survive losing any one machine — without needing more than three. Why three specifically, and not two: etcd (the control plane's database) uses **quorum** — a majority vote among its members — to agree on cluster state, and a majority only means something with an odd number of voters. With one control-plane node, losing it loses the cluster outright. Two doesn't help: losing either one leaves one survivor, which is not a majority of two. Three is the smallest number where losing any *one* still leaves two — a majority — able to keep agreeing on state. This is also why [`docs/09-growing-up.md`](09-growing-up.md) — once you're past this doc — specifically warns against going to four control-plane nodes later: four doesn't improve on three's fault tolerance, it just makes quorum math worse. ## The VIP: one address for a cluster that moves With three control-plane nodes, "where's the API server?" no longer has one fixed answer — it's whichever nodes happen to be up right now. Talos's **VIP** (Virtual IP) feature solves this: the three nodes continuously elect one of themselves to answer on one shared IP address you choose, and re-elect within seconds if that node goes down. Everything that talks to this cluster — `talosctl`, `kubectl`, the Application manifests in this repo — points at the VIP, never at one node's own address. See the `vip` block in [`talos/patch-controlplane.yaml`](../talos/patch-controlplane.yaml). > **Ask Claude:** "help me pick the VIP address for my cluster" before you > generate any config — same kind of decision as the MetalLB pool in > [`docs/05-metallb.md`](05-metallb.md): a real, unused address on your > LAN, outside your DHCP range, that Claude can't guess on its own. ## Preparing storage for Longhorn Each node also gets a second disk reserved for [Longhorn](06-longhorn.md), this repo's pre-installed storage layer — handled by [`talos/patch-longhorn.yaml`](../talos/patch-longhorn.yaml), applied at the same time as the control-plane patch below. Read that file's comments; the short version is that Talos finds, formats, and mounts a disk for Longhorn on its own, using rules you set (not the system disk, at least 900GB), so there's no manual partitioning step here. ## Steps Full exact commands live in [`talos/README.md`](../talos/README.md) — read that alongside this doc; this section explains what's happening at each stage, that one has copy-paste blocks. You'll repeat most of these steps **three times**, once per node — `talosctl README.md` calls out exactly which commands are "once" vs. "once per node." 1. **Generate machine configuration.** `talosctl gen config` produces Talos's config files for your cluster, with both [`talos/patch-controlplane.yaml`](../talos/patch-controlplane.yaml) (scheduling + the VIP) and [`talos/patch-longhorn.yaml`](../talos/patch-longhorn.yaml) (storage prep) baked in — read both files, they explain themselves. This produces one `controlplane.yaml`, applied identically to all three nodes; there's no separate worker config in this setup, since every node is both. 2. **Apply the config to each node.** Each node, freshly booted from your custom Talos ISO, is sitting in "maintenance mode" with no configuration. `talosctl apply-config` sends it the config from step 1. Run this once per node, pointed at that node's own address. Each node reboots, installs Talos to its system disk, formats and mounts its second disk for Longhorn, and comes up running for real. 3. **Bootstrap etcd.** `talosctl bootstrap` initializes the cluster's data store. This is a one-time, one-node-ever operation, run against exactly one of your three nodes — even though all three will end up running etcd, only one of them needs telling to *start* the cluster; the other two join the existing one once it exists. 4. **Retrieve your kubeconfig.** `talosctl kubeconfig` downloads the credentials you'll use to talk to Kubernetes with `kubectl` — the Kubernetes equivalent of the `talosconfig` you got in step 1. Point it at the VIP, not at any one node. 5. **Verify.** `kubectl get nodes` should show all three nodes, `Ready`. > **Ask Claude:** "what's the difference between a kubeconfig and a > talosconfig, and why are they separate files?" is a good one to ask once > you've got both — the split trips people up the first time. ## Checklist - [ ] VIP address chosen, with Claude's help, for your LAN - [ ] `_out/controlplane.yaml` and `talosconfig` generated, with both patches applied - [ ] Config applied to **all three** nodes; each has rebooted, installed Talos, and mounted its Longhorn disk - [ ] `talosctl bootstrap` run exactly once, against exactly one node - [ ] kubeconfig retrieved, pointed at the VIP - [ ] `kubectl get nodes` shows all three nodes `Ready` Once all three nodes are `Ready`, continue to [`docs/03-installing-argocd.md`](03-installing-argocd.md).