2026-08-22 17:30:45 +01:00
|
|
|
|
# Talos bootstrap — command reference
|
|
|
|
|
|
|
|
|
|
|
|
This is the detailed, copy-pasteable companion to
|
|
|
|
|
|
[`docs/02-talos-bootstrap.md`](../docs/02-talos-bootstrap.md). Read that file
|
|
|
|
|
|
first for the explanations — this one is here so you have every exact
|
|
|
|
|
|
command in one place once you understand what they do.
|
|
|
|
|
|
|
2026-08-22 18:25:38 +01:00
|
|
|
|
Throughout, replace `<NODE1_IP>`, `<NODE2_IP>`, `<NODE3_IP>` with your three
|
|
|
|
|
|
machines' real IP addresses, and `<VIP_IP>` with the shared address you
|
|
|
|
|
|
picked (with Claude's help) for the cluster's VIP — see
|
|
|
|
|
|
[`docs/02-talos-bootstrap.md`](../docs/02-talos-bootstrap.md#the-vip-one-address-for-a-cluster-that-moves).
|
|
|
|
|
|
Give each machine a DHCP reservation (a fixed IP tied to its MAC address)
|
|
|
|
|
|
in your router or hypervisor before you start, so none of these addresses
|
|
|
|
|
|
change under the cluster. Talos bakes them into certificates during setup,
|
|
|
|
|
|
and changing one later means starting over for that node.
|
|
|
|
|
|
|
|
|
|
|
|
Steps 1–2 below run **once, total**. Steps 3 runs **once per node** (three
|
|
|
|
|
|
times). Steps 4–6 run **once, total**, against whichever node you like
|
|
|
|
|
|
(or, once it exists, the VIP).
|
2026-08-22 17:30:45 +01:00
|
|
|
|
|
|
|
|
|
|
All commands assume you're running them from the root of this repo.
|
|
|
|
|
|
|
|
|
|
|
|
## 1. Generate machine configuration
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
2026-08-22 18:25:38 +01:00
|
|
|
|
talosctl gen config gitops-starter https://<VIP_IP>:6443 \
|
2026-08-22 17:30:45 +01:00
|
|
|
|
--output-dir _out \
|
2026-08-22 18:25:38 +01:00
|
|
|
|
--config-patch-control-plane @talos/patch-controlplane.yaml \
|
|
|
|
|
|
--config-patch-control-plane @talos/patch-longhorn.yaml
|
2026-08-22 17:30:45 +01:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-22 18:25:38 +01:00
|
|
|
|
Note the cluster endpoint here is the **VIP**, not any one node's address
|
|
|
|
|
|
— every node needs to agree in advance on where the cluster "lives," and
|
|
|
|
|
|
that address has to be the one that keeps working no matter which node is
|
|
|
|
|
|
currently answering.
|
|
|
|
|
|
|
2026-08-22 17:30:45 +01:00
|
|
|
|
This writes three files into `_out/` (already covered by this repo's
|
|
|
|
|
|
`.gitignore` — they contain private keys and must never be committed):
|
|
|
|
|
|
|
2026-08-22 18:25:38 +01:00
|
|
|
|
- `controlplane.yaml` — the machine configuration for a control-plane
|
|
|
|
|
|
node, with both patches baked in. Applied identically to all three
|
|
|
|
|
|
nodes — there's no separate worker config in this setup, since every
|
|
|
|
|
|
node is both.
|
|
|
|
|
|
- `worker.yaml` — a plain worker config, generated automatically but
|
|
|
|
|
|
unused here since every node in this repo's setup is both control plane
|
|
|
|
|
|
and worker. Kept around for [`docs/09-growing-up.md`](../docs/09-growing-up.md),
|
|
|
|
|
|
where a fourth-and-beyond node uses exactly this file.
|
2026-08-22 17:30:45 +01:00
|
|
|
|
- `talosconfig` — *your* client credentials for talking to the Talos API on
|
|
|
|
|
|
this cluster (equivalent in spirit to a kubeconfig, but for Talos itself
|
|
|
|
|
|
rather than Kubernetes).
|
|
|
|
|
|
|
|
|
|
|
|
`gitops-starter` is the cluster name — an arbitrary label baked into the
|
|
|
|
|
|
generated certificates and config, used to tell clusters apart if you ever
|
2026-08-22 18:25:38 +01:00
|
|
|
|
manage more than one. Port 6443 is the standard Kubernetes API server port.
|
2026-08-22 17:30:45 +01:00
|
|
|
|
|
|
|
|
|
|
## 2. Point talosctl at this cluster
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
export TALOSCONFIG=_out/talosconfig
|
2026-08-22 18:25:38 +01:00
|
|
|
|
talosctl config endpoint <NODE1_IP> <NODE2_IP> <NODE3_IP>
|
2026-08-22 17:30:45 +01:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-22 18:25:38 +01:00
|
|
|
|
`endpoint` is which machine(s) talosctl is willing to *talk to* — giving
|
|
|
|
|
|
it all three means it can still reach the cluster if any one of them is
|
|
|
|
|
|
down. You'll pass `--nodes` per-command below for which machine a given
|
|
|
|
|
|
command actually *applies to* — Talos always keeps those two concepts
|
|
|
|
|
|
separate.
|
2026-08-22 17:30:45 +01:00
|
|
|
|
|
2026-08-22 18:25:38 +01:00
|
|
|
|
## 3. Apply the configuration — once per node
|
2026-08-22 17:30:45 +01:00
|
|
|
|
|
2026-08-22 18:25:38 +01:00
|
|
|
|
Boot each machine from your custom Talos ISO (see
|
|
|
|
|
|
[docs/01-prerequisites.md](../docs/01-prerequisites.md)). Each boots into
|
|
|
|
|
|
"maintenance mode" — alive enough to accept a configuration, with nothing
|
|
|
|
|
|
installed yet. For **each** node in turn:
|
2026-08-22 17:30:45 +01:00
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
talosctl get disks --insecure --nodes <NODE_IP>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-22 18:25:38 +01:00
|
|
|
|
Confirm you see two disks: the one Talos will install itself to, and the
|
|
|
|
|
|
≥900GB one `talos/patch-longhorn.yaml`'s `UserVolumeConfig` will claim for
|
|
|
|
|
|
Longhorn. Then:
|
2026-08-22 17:30:45 +01:00
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
talosctl apply-config --insecure \
|
|
|
|
|
|
--nodes <NODE_IP> \
|
|
|
|
|
|
--file _out/controlplane.yaml
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`--insecure` is required for this one command only: the node has no
|
|
|
|
|
|
certificates yet, so talosctl can't authenticate to it normally. This is
|
|
|
|
|
|
the one moment during setup where you're trusting the network — do this on
|
2026-08-22 18:25:38 +01:00
|
|
|
|
a network you control. The node will reboot, install Talos to its system
|
|
|
|
|
|
disk, format and mount its second disk for Longhorn, and come back up
|
|
|
|
|
|
running the configuration you gave it — now *with* certificates, so every
|
|
|
|
|
|
command after this uses the secure path.
|
|
|
|
|
|
|
|
|
|
|
|
Repeat this for `<NODE1_IP>`, `<NODE2_IP>`, and `<NODE3_IP>` before moving on.
|
2026-08-22 17:30:45 +01:00
|
|
|
|
|
2026-08-22 18:25:38 +01:00
|
|
|
|
## 4. Bootstrap etcd — once, total
|
2026-08-22 17:30:45 +01:00
|
|
|
|
|
2026-08-22 18:25:38 +01:00
|
|
|
|
Talos is installed on all three nodes and Kubernetes components are
|
|
|
|
|
|
starting, but the cluster has no data store yet. This one-time command
|
|
|
|
|
|
initializes it:
|
2026-08-22 17:30:45 +01:00
|
|
|
|
|
|
|
|
|
|
```sh
|
2026-08-22 18:25:38 +01:00
|
|
|
|
talosctl bootstrap --nodes <NODE1_IP>
|
2026-08-22 17:30:45 +01:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-22 18:25:38 +01:00
|
|
|
|
Run this **exactly once**, against **exactly one** of your three nodes —
|
|
|
|
|
|
even though all three will end up running etcd as peers, only one needs
|
|
|
|
|
|
telling to *start* the cluster; the other two discover and join the
|
|
|
|
|
|
existing one. Running it again against an existing cluster can corrupt it.
|
2026-08-22 17:30:45 +01:00
|
|
|
|
|
|
|
|
|
|
## 5. Get your kubeconfig
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
2026-08-22 18:25:38 +01:00
|
|
|
|
talosctl kubeconfig --nodes <VIP_IP> .
|
2026-08-22 17:30:45 +01:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Downloads a kubeconfig into the current directory (also gitignored —
|
2026-08-22 18:25:38 +01:00
|
|
|
|
it grants full cluster access), pointed at the VIP rather than any one
|
|
|
|
|
|
node. Merge it with `~/.kube/config` or point `KUBECONFIG` at it directly:
|
2026-08-22 17:30:45 +01:00
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
export KUBECONFIG=$PWD/kubeconfig
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 6. Verify
|
|
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
|
kubectl get nodes
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-22 18:25:38 +01:00
|
|
|
|
Expect to see **three** nodes, `Ready`, within a couple of minutes (it
|
|
|
|
|
|
takes a moment for the default CNI — Talos ships Flannel out of the box —
|
|
|
|
|
|
to come up and clear each node's networking checks).
|
2026-08-22 17:30:45 +01:00
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
NAME STATUS ROLES AGE VERSION
|
|
|
|
|
|
talos-... Ready control-plane 90s v1.3x.x
|
2026-08-22 18:25:38 +01:00
|
|
|
|
talos-... Ready control-plane 85s v1.3x.x
|
|
|
|
|
|
talos-... Ready control-plane 80s v1.3x.x
|
2026-08-22 17:30:45 +01:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-22 18:25:38 +01:00
|
|
|
|
If any node is stuck on `NotReady`, give it another minute before
|
|
|
|
|
|
troubleshooting — first boot does a lot of one-time work.
|