- Go 100%
- Makefile <1%
talos-upgrade #
A CLI for managing Talos Linux cluster upgrades with profile-based configuration. It discovers cluster nodes, picks the right installer image (extensions, kernel args, overlays) per hardware profile via the Image Factory, and upgrades nodes one at a time — draining Kubernetes, staging the installer image, running the upgrade, and waiting for the node and its services to come back healthy before moving on.
Talos 1.13+ only. Upgrades use the
LifecycleService.UpgradegRPC API, which requires the node to run Talos >= 1.13.0. Older nodes are rejected.
Install #
Requires Go 1.26+.
make build # -> bin/talos-upgrade
make install # -> $GOPATH/bin/talos-upgrade
Both targets stamp the version via git describe --tags --always --dirty. A
plain go install ./cmd/talos-upgrade also works — the git commit is embedded
automatically through Go's build info.
Check what you have installed:
talos-upgrade --version # or: talos-upgrade version
talos-upgrade 2429132-dirty
commit: 2429132fc5dc-dirty
committed: 2026-05-17T19:43:07Z
go: go1.26.4
If the commit: matches your repo HEAD and has no -dirty suffix, the binary
is built from current source:
git rev-parse --short=12 HEAD
Prerequisites #
- A valid talosconfig (default discovery, same as
talosctl) — used to talk to nodes and discover cluster members. - A kubeconfig for the cluster — used to cordon/drain nodes during upgrade. If unavailable, drain is skipped (with a warning).
Configuration #
The tool looks for a config file in this order (unless -c/--config is given):
./configs/talos-profiles.yaml./talos-profiles.yaml- the same paths relative to the binary's directory
Note: the canonical config for this homelab lives at
/home/data/homelab/talos-profiles.yaml. The copy bundled inconfigs/can drift; pass-c /home/data/homelab/talos-profiles.yamlif in doubt.
Schema #
settings:
factory_base_url: "https://factory.talos.dev"
default_timeout_seconds: 600
github_releases_url: "https://api.github.com/repos/siderolabs/talos/releases/latest"
backup_dir: "backups" # where machine configs are backed up around upgrades (default: "backups")
# Hardware profiles: each becomes an Image Factory schematic.
profiles:
amd64:
description: "Intel GPU nodes with secureboot"
arch: amd64 # required
platform: metal # required
secureboot: true
kernel_args:
- pci=realloc
extensions:
- siderolabs/i915
- siderolabs/iscsi-tools
arm64-rpi:
arch: arm64
platform: metal
overlay: # SBC overlay (optional)
name: rpi_generic
image: siderolabs/sbc-raspberrypi
extensions:
- siderolabs/iscsi-tools
# Map discovered hardware -> profile. Nodes are discovered via the Talos
# cluster members API; their profile is detected from hardware info.
detection:
rules:
- profile: arm64-rpi
match: # AND: all listed conditions must match
system_manufacturer: raspberrypi # case-insensitive substring
arch: arm64 # case-insensitive exact
- profile: amd64
match:
arch: amd64
Detection matching:
match— AND, every condition must match.match_either— OR, any onematchblock matches.system_manufacturer/processor_manufacturerare case-insensitive substring matches;archis a case-insensitive exact match.
Instead of detection, you may list static nodes (ip / profile / role),
but detection is preferred.
Usage #
talos-upgrade [command] [flags]
Global flags #
| Flag | Env | Description |
|---|---|---|
-c, --config <path> |
Config file path | |
--dry-run |
DRY_RUN=true |
Show what would happen; make no changes |
--force |
Re-apply the upgrade even if the node already matches the target version/config | |
-V, --talos-version <ver> |
TALOS_VERSION |
Target Talos version (default: latest from GitHub) |
--version |
Print version/build info and exit |
When no version is supplied, the latest stable Talos release is fetched from
github_releases_url.
Commands #
| Command | Description |
|---|---|
status |
Show current cluster status and node versions |
urls [version] |
Print Image Factory browser URLs per profile |
images [version] |
Print installer image references per profile |
upgrade [target] [version] |
Upgrade nodes (workers first, then control planes) |
upgrade-node <ip> [version] |
Upgrade a single node by IP |
version |
Print version and build information |
upgrade targets: all (default), workers, controlplanes, a profile name,
or a node IP. Arguments are order-insensitive — upgrade workers 1.13.4 and
upgrade 1.13.4 workers are equivalent.
Examples #
# See current versions across the cluster
talos-upgrade status
# Preview the installer images that would be used for the latest release
talos-upgrade images
# Dry-run an upgrade of all nodes to the latest stable release
talos-upgrade --dry-run upgrade all
# Upgrade only workers to a specific version
talos-upgrade upgrade workers 1.13.4
# Upgrade a single node
talos-upgrade upgrade-node 192.168.1.50 1.13.4
How an upgrade works #
For each node, in order (workers before control planes):
- Skip if already at the target version with matching extensions and kernel args.
- Back up the node's machine config to
backup_dir(<ip>-<timestamp>-pre-upgrade.yaml). - Cordon and drain the Kubernetes node (DaemonSet and mirror pods are left in place; PDB-throttled evictions are retried until the timeout).
- Stage the installer image into the node's
systemcontainerd namespace viaImageService.Pull—LifecycleService.Upgradedoes not pull it itself. - Run
LifecycleService.Upgrade, stream install progress, and reboot. - Wait for the node to return to
RUNNING, then for Talos services (etcd/kubelet/apid/trustdon control planes), and for control-plane static pods (kube-apiserver,kube-controller-manager,kube-scheduler). - Back up the machine config again (
<ip>-<timestamp>-post-upgrade.yaml). - Uncordon the node (always attempted, even on failure).
A failed control-plane upgrade prompts before continuing to the next node.
Machine config backups #
Before and after each node upgrade the tool snapshots the node's active machine
config to backup_dir (default backups/, git-ignored):
<ip>-<timestamp>-pre-upgrade.yaml— the node exactly as it is now, captured before draining, unmodified.<ip>-<timestamp>-post-upgrade.yaml— the node's new state, withmachine.install.imagepatched to the target installer image so it doubles as a self-sufficient manifest for a from-scratch reinstall at the intended version (talosctl apply-config --insecure --file <backup>).
Backups contain machine secrets and are written owner-only (0600); keep
them somewhere safe.
Development #
make test # go test ./...
make tidy # go mod tidy
make build-all # cross-compile linux/darwin amd64+arm64
The repository is hosted at https://tangled.org/evan.jarrett.net/talos-upgrade (not GitHub).