Upgrade Command
The upgrade command upgrades Talos OS on each node to the desired version specified in the installer image.
Flags
All flags can also be set via environment variables using the TOPF_ prefix and uppercasing the flag name (e.g. --reboot-mode → TOPF_REBOOT_MODE).
| Flag | Default | Description |
|---|---|---|
--dry-run |
false |
Only show what upgrades would be performed without actually upgrading |
--max-parallel |
1 |
Number of worker nodes to upgrade concurrently, as an integer (e.g. 5) or a percentage of the total node count (e.g. 25%); control-plane nodes are always upgraded one at a time |
--reboot-mode |
default |
Reboot mode during upgrade: default uses kexec, powercycle does a full reboot |
--drain |
true |
Cordon and drain the Kubernetes node before rebooting, then uncordon after stabilization (modern flow only; ignored on legacy nodes, where Talos drains and uncordons server-side) |
--drain-timeout |
5m |
Maximum time to wait for pod evictions (and, with --delete-if-eviction-fails, deletions) to complete during drain (modern flow only) |
--delete-if-eviction-fails |
false |
If graceful drain fails (e.g. a PodDisruptionBudget blocks eviction), retry by deleting pods directly (DELETE instead of EVICT, bypassing PDBs); reuses --drain-timeout for the delete fallback (modern flow only) |
--force |
false |
Skip etcd health checks; only applies to nodes running Talos < 1.13 (legacy MachineService.Upgrade RPC); has no effect on Talos >= 1.13, where the LifecycleService.Upgrade RPC validates etcd health server-side |
--stage |
false |
Install upgrade artifacts without rebooting; the node is left running and can be labeled/annotated/tainted (see --stage-label/--stage-annotation/--stage-taint) so an external controller or human reboots it later |
--stage-label |
- | Kubernetes node label to apply after staging (key=value); can be repeated; requires --stage |
--stage-annotation |
- | Kubernetes node annotation to apply after staging (key=value); can be repeated; requires --stage |
--stage-taint |
- | Kubernetes node taint to apply after staging (key=value:Effect); can be repeated; requires --stage |
--nodes-filter |
- | Regex pattern to filter which nodes to operate on (global flag) |
Upgrade API selection. Nodes running Talos >= 1.13 use the modern
LifecycleService.Upgradestreaming RPC (pre-pull, install, separate reboot). Nodes running Talos < 1.13 fall back to the legacyMachineService.UpgradeRPC, which installs, drains, and reboots in a single server-side sequence. The--forceflag is only meaningful on the legacy path;--drainand--drain-timeoutare only meaningful on the modern path.When to use
--delete-if-eviction-fails. The graceful drain uses the Kubernetes eviction API, which respects PodDisruptionBudgets. A PDB withminAvailable: 1on a single-replica pod (e.g. a standalone database StatefulSet) will block eviction until--drain-timeoutexpires and the drain fails.--delete-if-eviction-failsretries the drain with direct pod deletion (DELETE instead of EVICT), bypassing PDBs — the pod is killed and its controller reschedules it elsewhere. The delete fallback reuses--drain-timeoutas its timeout.Note that the drain always runs with
kubectl drain --forcesemantics (unmanaged pods are deleted, emptyDir data is removed) — this is the default behavior for a rebooting node and is not controlled by--delete-if-eviction-fails. The flag only switches the eviction API to direct deletion for the fallback attempt, which is what lets it bypass PDBs.Staging upgrades with
--stage(Talos >= 1.13 only). Sometimes you want to install new Talos artifacts on nodes without immediately rebooting them — e.g. to spread reboots over a maintenance window or let an external controller (such as a drain scheduler) reboot nodes one at a time.--stageinstalls the upgrade artifacts but skips the drain, reboot, and uncordon steps. The node continues running on its current kernel until it is manually rebooted, at which point the staged upgrade takes effect.
--stage-label,--stage-annotation, and--stage-taintmark the Kubernetes node so controllers or humans can identify nodes with a pending reboot. For example,--stage-taint topf.postfinance.ch/staged-upgrade=true:PreferNoSchedulediscourages new pods from scheduling on the node until it is rebooted and the taint is removed. All three flags can be repeated and require--stage.--stagetakes precedence over--drainand--delete-if-eviction-fails; both are silently ignored when staging. No need to pass--drain=falsewith--stage.
Behavior
- Pre-flight checks: Ensures all nodes are in the
Runningstage - Version comparison: Extracts schematic and version from the installer image and only upgrades nodes where either differs from the current state
- Per-node confirmation: Before each upgrade (unless
--confirm=false, see global flags) - API selection: Per node, if the running Talos version is >= 1.13.0, the modern flow (a) is used; otherwise the legacy flow (b) is used
Modern flow (Talos >= 1.13):
- Resolve the Kubernetes node name (if
--drainis enabled or for staged upgrades with--stage-labeland/or--stage-taintand/or--stage-annotation) - Pre-pull the installer image via
ImageService.Pull - Install the upgrade artifacts via
LifecycleService.Upgrade - If
--stageis set: apply labels/annotations/taints (if any) and stop here — the node is not rebooted - Cordon and drain the Kubernetes node if
--drainis enabled. If the drain fails (e.g. a pod cannot be evicted within--drain-timeout), the upgrade aborts unless--delete-if-eviction-failsis set: in that case, the drain retries with pod deletion (DELETE instead of EVICT, bypassing PodDisruptionBudgets, reusing--drain-timeout). If the forced drain also fails, the node is left cordoned with the new artifacts installed but not rebooted, and no further nodes are upgraded. In-flight upgrades on other nodes (when--max-parallel > 1) are allowed to complete, but no new ones are started. The node must be uncordoned and rebooted manually to recover. - Issue a
Rebootwith the selected reboot mode (default: kexec) - Wait 30 seconds for the node to stabilize
- Uncordon the Kubernetes node
Legacy flow (Talos < 1.13):
- Issue
MachineService.Upgrade, which installs the upgrade artifacts, cordons and drains the node, and reboots — all in a single server-side sequence.--drainand--drain-timeoutare ignored (Talos drains and uncordons the node itself);--forceskips etcd health checks.--stageis not supported on legacy nodes. - Wait 30 seconds for the node to stabilize
Installer Image
Using talosVersion and schematicId (recommended)
To override the installer image for the entire cluster, set talosVersion and optionally schematicId in topf.yaml. Topf will automatically generate a cluster-level patch:
This generates factory.talos.dev/metal-installer/<schematicId>:v<talosVersion> as the base installer image. Since this patch is applied first, any subsequent machine.install.image patch (shared or node-level) will override it. The factory and platform can be customized via factory and platform in topf.yaml (or per node).
Manual installer image patch
Alternatively, manage the installer image explicitly via a patch. The target image for each node comes from the machine.install.image field in the assembled node configuration (i.e. the last patch takes precedence). The patch looks like:
all/00-install.yaml:
machine:
install:
image: factory.talos.dev/metal-installer/376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba:v1.12.0
Per-node override
To upgrade a single node to a different version or schematic, add a node-specific patch that overrides the image:
node/node1/installer.yaml:
machine:
install:
image: factory.talos.dev/metal-installer/376567988ad370138ad8b2698212367b8edcb69b5fd68c80be1f2ec7d603b4ba:v1.13.0
Because node-level patches are merged last (see Configuration Model), this override applies only to that host.
Example Usage
# Upgrade with confirmation (default)
topf upgrade
# Upgrade without confirmation
topf upgrade --confirm=false
# Preview what would be upgraded
topf upgrade --dry-run
# Upgrade without draining the Kubernetes node
topf upgrade --drain=false
# Upgrade up to 3 worker nodes concurrently
topf upgrade --max-parallel=3
# Upgrade with a custom drain timeout
topf upgrade --drain-timeout=10m
# Force upgrade on legacy (Talos < 1.13) nodes, skipping etcd health checks
topf upgrade --force
# Upgrade, falling back to pod deletion if graceful drain fails
topf upgrade --delete-if-eviction-fails
# Upgrade with a longer drain timeout (shared by graceful and fallback)
topf upgrade --delete-if-eviction-fails --drain-timeout=10m
# Stage an upgrade without rebooting (reboot manually later to complete it)
topf upgrade --stage
# Stage an upgrade and label the node so a controller can find it
topf upgrade --stage --stage-label topf.postfinance.ch/staged-upgrade=true
# Stage an upgrade and taint the node to discourage new pods from scheduling
topf upgrade --stage --stage-taint topf.postfinance.ch/staged-upgrade=true:PreferNoSchedule
# Stage an upgrade and annotate the node so a controller can find it
topf upgrade --stage --stage-annotation topf.postfinance.ch/staged-at=2026-08-07