Skip to content

Talos node upgrades can exceed the 10-minute drain timeout, evicting the bump from the merge queueΒ #3388

Open

Description

@devantler

πŸ€– Generated by the Agentic Engineer

Evidence

A Talos patch bump (v1.13.8 β†’ v1.13.9, #3382) was evicted from the merge queue when the prod deploy's πŸ”„ Update cluster (Talos machine config) step failed after ~16 minutes:

βœ— distribution upgrade to pinned version v1.13.9 failed: rolling upgrade from v1.13.8 to v1.13.9:
  upgrading node <redacted> (worker): drain: drain node prod-worker-2 (timeout 10m0s):
  error when evicting pods/"instance-manager-…" -n "longhorn-system":
  global timeout reached: 10m0s; raise spec.cluster.talos.drainTimeout (or --drain-timeout)
  to give workloads more time, or re-run with --force-drain to delete pods bypassing PodDisruptionBudgets

The drain retried the same eviction in a tight loop for the full window, each attempt refused with Cannot evict pod as it would violate the pod's disruption budget.

The mechanism is a timeout mismatch between two correct settings, not a flake:

  • Longhorn runs node-drain-policy: block-if-contains-last-replica (confirmed live). It deliberately refuses to drain a node holding a volume's last healthy replica until it has rebuilt one elsewhere.
  • The live instance-manager-* PDBs each report ALLOWED DISRUPTIONS: 0, so this is structural, not transient.
  • ksail.prod.yaml sets no spec.cluster.talos.drainTimeout, so ksail's 10-minute default applies β€” less than a replica rebuild needs.

Failing run: 32956840398 (2026-08-26 10:10Z).

Impact

Every Talos version bump risks evicting itself β€” and whatever else is queued behind it β€” from the merge queue. Each occurrence costs a full ~35-minute prod deploy that drains and uncordons real nodes before failing. #3382 needed three queue attempts to land.

Because the drain is retried in a loop and the deploy job's later steps (Cilium gate, GHCR-auth reassert) run as always-steps and succeed, the job log tail reads green β€” the failure is only visible at the cluster_update end-action. That makes this easy to misread as an unrelated deploy fault.

Expected

A Talos node upgrade either drains within its allotted window, or waits long enough for Longhorn to hand off the last replica β€” so a routine patch bump merges in one queue attempt.

Acceptance criteria

  1. Measure how long Longhorn actually needs to relocate the last replica off a drained node, at current volume sizes.
  2. Set spec.cluster.talos.drainTimeout in ksail.prod.yaml to comfortably exceed that, and record why that value.
  3. Confirm the deploy still fails promptly on a genuinely stuck drain rather than hanging for the new timeout.
  4. Prove it: a Talos patch bump merges in a single queue attempt.

Explicitly NOT the fix

--force-drain deletes pods bypassing PodDisruptionBudgets. Here the PDB is the data-safety control β€” it is protecting a volume's last healthy replica β€” so forcing the drain trades a merge-queue annoyance for a risk of data loss on the storage layer. Likewise, relaxing node-drain-policy away from block-if-contains-last-replica removes the protection rather than accommodating it.

Size

Small β€” one config field plus the measurement that justifies its value.

Activity

  1. added theissue type on Aug 26, 2026
  2. moved this to πŸ“₯ Backlog in 🌊 Project Boardon Aug 26, 2026
  3. devantler commented on Aug 26, 2026

    @devantler
    ContributorAuthor

    πŸ€– Generated by the Agentic Engineer

    Refinement: the "last replica" is transient, and the rolling upgrade creates it

    Live steady state (read-only, admin@prod) shows the block is not caused by any under-replicated volume:

    • 13 Longhorn volumes, every one numberOfReplicas: 3, state=attached, robustness=healthy.
    • Replicas are evenly placed β€” prod-worker-1, -2 and -3 each hold 13 running replicas, one per volume.

    So draining a single worker in steady state leaves two healthy replicas and block-if-contains-last-replica would not fire.

    It fires because a rolling upgrade reboots the workers in sequence. While a previously-upgraded worker's 13 replicas are still rebuilding, the node being drained next genuinely does hold the last healthy replica for some volume β€” so Longhorn correctly blocks, and keeps the per-node instance-manager PDB at ALLOWED DISRUPTIONS: 0 until the rebuild catches up.

    The upgrade is therefore outpacing Longhorn's replica rebuild, and 10 minutes is not enough slack for ~13 replicas to re-sync between nodes.

    This sharpens acceptance criterion 1: the quantity to measure is replica re-sync time between consecutive node reboots during a rolling upgrade, not a static per-volume rebuild time. It cannot be measured from steady state β€” every volume is healthy right now β€” so it needs capturing during the next Talos bump.

    It also reinforces the "explicitly not the fix" note: --force-drain would delete the instance-manager holding the only healthy replica of a volume mid-rebuild, which is precisely the case the policy exists to prevent.

  4. devantler commented on Oct 2, 2026

    @devantler
    ContributorAuthor

    πŸ€– Generated by the Agentic Engineer

    Progress check, 2026-10-02: AC1 measured from logs, AC2 already shipped, AC3–AC4 still open

    AC1: measured from three rolling upgrades' deploy logs. I timed the gap between each worker's Draining … line and its Upgrading … via LifecycleService line:

    Rollout prod-worker-1 prod-worker-3 prod-worker-2
    v1.13.9, attempt 1 (run 32956840398, 2026-08-26 10:17Z) 3m06s 0m45s (drain started 1s after worker-1 was Ready) >10m02s, timed out. Drain started 1s after worker-3 was Ready.
    v1.13.9, attempt 2 (run 32966678815, ~1h40m later) already upgraded already upgraded 4m03s
    Audit-schematic roll, #4099 (run 35904894804, 2026-09-23 18:57Z, drainTimeout: 40m) 2m25s 3m54s 3m32s

    What this shows:

    • Uncontended, a worker drains in about 2.5–4 minutes. That holds even when the drain starts ~1 minute after the previous worker came back (the fix(talos): roll declared audit schematic onto production nodesΒ #4099 roll). So the block-if-contains-last-replica wait does not happen on every rollout.
    • When it does happen, it took longer than 10 minutes (attempt 1). The logs give only a lower bound, because KSail stopped at its deadline. The true replica re-sync time for that case is still not observed.
    • Control planes drain in 16–23 s in every run, so they are not part of this problem.

    AC2: met by #3916 (merged 2026-09-20). ksail.prod.yaml sets spec.cluster.talos.drainTimeout: 40m, with the reasoning recorded next to it: CloudNativePG's 1800 s stop window plus 10 minutes for Longhorn to release the instance-manager PDB, after a 30m budget failed at exactly that deadline. The #4099 roll above ran under it and did not come near it.

    AC3: open. No run has measured how long a deploy takes to fail when a drain is genuinely stuck. A 40m per-node budget makes that interaction with the queue relevant, because merge-group deploys already compete with the queue's check timeout (#3097).

    AC4: open, waiting for a vehicle. No Talos patch bump has gone through the queue since #3382. Talos v1.13.11 was published on 2026-10-01, but Renovate's renovate/talos branch is occupied by the v1.14.0 PR (#4044), which is parked on #3850. A v1.13.11 patch bump would therefore be the natural single-attempt proof.

    Next: when a Talos patch bump merges, record its queue-attempt count and per-worker drain times here. If it merges in one attempt with all drains under 40m, AC2 and AC4 are met, and AC3 is the only thing keeping this open.

  5. added a commit that references this issue on Oct 6, 2026
  6. devantler commented on Oct 6, 2026

    @devantler
    ContributorAuthor

    πŸ€– Generated by the Agentic Engineer

    AC4 now has a vehicle on the way: #4557.

    Production runs Talos v1.13.10 and v1.13.11 has been published since 2026-10-01, but no update was proposed. Renovate offers only the newest non-major release, which is v1.14.x, and that pull request (#4044) is parked on its migration. So the wait recorded above was not for upstream to publish a patch: the patch existed and could not be offered.

    #4557 gives Talos patch releases their own pull request beside the parked minor one, still never auto-merged and with the same manual checklist. Once it merges, the v1.13.11 pull request Renovate opens is the single-attempt proof this issue is waiting for: record its queue-attempt count and per-worker drain times here.

  7. devantler commented on Oct 6, 2026

    @devantler
    ContributorAuthor

    πŸ€– Generated by the Agentic Engineer

    #4557 merged at 09:15Z: Renovate now offers Talos patch releases on their own branch (renovate/patch-talos) while the v1.14 minor upgrade stays parked in #4044. Production runs v1.13.10 and v1.13.11 has been out since 1 October.

    Next step: when Renovate opens the patch pull request, complete its checklist (talosctl checksum, ISO, expected version), drive it through the queue, and record the node drain times here.

  8. devantler commented on Oct 7, 2026

    @devantler
    ContributorAuthor

    πŸ€– Generated by the Agentic Engineer

    The Talos patch pull request is not late: it is due after 2026-10-08 17:54Z. No renovate/patch-talos branch exists yet, 25 hours after #4557 merged, and that is expected. This repository makes Renovate wait seven days after a release before offering it, and Talos v1.13.11 was published on 2026-10-01 at 17:54Z. Renovate itself is running normally (it opened and merged #4619 today).

    Next check: after that time. If the patch pull request has still not appeared by 2026-10-09, the split added in #4557 is not doing what it was meant to and needs another look; if it has, the steps in the previous comment apply.

  9. devantler commented on Oct 10, 2026

    @devantler
    ContributorAuthor

    πŸ€– Generated by the Agentic Engineer

    The protected deployment failure reproduced with the configured 40-minute drain window in run 38091510339. The failing step is autoscaler boot-image reconciliation: pod eviction remains blocked by database-primary and storage disruption budgets until the global drain timeout. Later successful admission and gateway checks do not make that failed deployment green.

    A read-only follow-up found the declared nodes Ready and schedulable and the affected databases fully Ready. That establishes current readiness only; it does not establish the requested boot image, successful deployment, or alert clearance. The protected recovery job is still restoring main. No budget was disabled and no pod, node, volume, or database was changed by this investigation.

    The next diagnosis must distinguish the database operator's supported switchover from storage replica evacuation and verify each against the failed drain interval. Increasing the timeout again is not sufficient evidence of a repair. Preserve the disruption budgets and data-protection rules; do not re-queue the failed rollout until recovery and the drain prerequisite are verified.

    The bounded storage-manager log confirms it retained the disruption budget because volume engines were still attached. That message does not prove a last-replica rebuild failure. The available database-operator log begins after the failed drain, so it cannot establish why the expected switchover did not complete during that interval. Preserve that uncertainty before choosing a configuration change.

    Recovery readback (2026-10-11 00:32 UTC): the protected restore-main job completed successfully at 00:18:17 UTC. Its reviewed production checks passed, and a fresh consumer platform-health check exited 0. This clears the recovery-pending state; the original 40-minute drain failure remains unresolved and is still the investigation scope of this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Fields

    Priority

    None yet

    Effort

    None yet

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions