Talos¶
Declarative Talos Linux machine configuration, built
from composable multi-document patches (requires Talos 1.14 or later). Nothing
in kubernetes/talos/
is applied automatically. Configs are rendered on demand and pushed with
talosctl. Version upgrades are the exception: tuppr handles those (see
Upgrades).
Layout¶
| Path | Purpose |
|---|---|
cluster.yaml.j2 |
Documents applied to every node |
controlplane.yaml.j2 |
Control-plane-only documents, including machine.type |
workers.yaml.j2 |
Worker-only documents (not created yet; added with the first worker) |
nodes/<role>/<node>.yaml.j2 |
Per-node documents: hostname, NIC alias, bond, install disk, volumes |
nodes/<role>/<node>.schematic.yaml.j2 |
Optional per-node schematic override |
schematic.yaml.j2 |
Shared Image Factory schematic |
version.yaml |
Pinned Talos and Kubernetes versions (updated by Renovate) |
mod.just |
just talos … recipes |
What's in the config¶
Applied to every node from cluster.yaml.j2:
- DHCP on
bond0, with the UDM as resolver - Filesystem trim and scrub schedules, and a hardware watchdog
- Kernel modules for DRBD,
dm_thin_poolandnbd - Sysctl tuning: BBR with
fq, large TCP buffers for QUIC, NFS RPC slot limits, raised inotify limits, IPv6 disabled nfsmount.confwith tuned NFS mount defaults- Registry mirrors for
docker.io,ghcr.io,quay.ioandregistry.k8s.io, pointing at the Zot pull-through cache on the NAS (registry.bykaj.app), falling back to upstream - KubePrism, and kubelet node IPs restricted to
10.73.20.0/24
The shared schematic adds the Intel i915, intel-ucode and mei extensions
for iGPU transcoding, nfsrahead, and drbd. It also sets kernel arguments
that trade some hardening for performance (mitigations=off, no
init_on_alloc/init_on_free, auditd disabled).
Rendering¶
just talos render-config <node> builds the final machine config in three
layers:
talosctl machineconfig patch <(cluster.yaml.j2) \
-p @<(controlplane.yaml.j2 | workers.yaml.j2) \
-p @<(nodes/<role>/<node>.yaml.j2)
Each layer passes through minijinja-cli (strict Jinja; the schematic ID
arrives as a -D define) and op inject (1Password) before talosctl merges
them. Later patches merge strategically into earlier ones: documents with the
same kind and name are deep-merged, and new documents are appended.
Two conventions keep the layers honest:
- Directory placement is the single source of truth for a node's role. The
role patch is chosen by which
nodes/<role>/directory holds the node file, andmachine.typeis set by the role patch, not by the node file. - Secrets never live in the repo. Sensitive values are
op://Homelab/talos/...references resolved at render time.
Schematics¶
just talos schematic-id POSTs the schematic to the Image Factory and gets
back a content-addressed ID. That ID is templated into the
UnattendedInstallConfig installer image and used by download-image and
upgrade-node.
Resolution is per node: nodes/<role>/<node>.schematic.yaml.j2 wins when
present, otherwise the shared schematic.yaml.j2 applies. Overrides are
complete files, not deltas. None exist today.
Gotchas¶
machine.caandcluster.camerge as a cert+key unit: a patch that supplies onlykeyblankscrt. That is whycontrolplane.yaml.j2repeats thecrtreferences alongside the keys.- Rendering a worker before
workers.yaml.j2andnodes/workers/exist fails loudly. Adding the first worker means creatingworkers.yaml.j2(withmachine: { type: worker }and acablock carryingcrtonly) plusnodes/workers/<node>.yaml.j2. - Kernel names for the two NVMe drives can swap across reboots. Disks are
selected by model and links by MAC, so this is harmless, but match by model
or serial when reading
talosctloutput.
Common tasks¶
just talos render-config <node> # render a node's full machine config to stdout
just talos apply-node <node> # render and apply (talosctl apply-config)
just talos upgrade-node <node> # upgrade Talos using the node's schematic image
just talos upgrade-k8s <version> # upgrade Kubernetes across the cluster
just talos download-image <version> # fetch a metal ISO from the Image Factory
just talos reboot-node <node> # reboot (asks for confirmation)
Verify a template refactor by diffing rendered output before and after, then confirming this reports "No changes." on every node: