Skip to content

Every prod deploy rolling-reboots the whole fleet: ksail cluster update invalidates the GHCR node proofΒ #3042

Closed

Description

@devantler

πŸ€– Generated by the Agentic Engineer

Evidence

Since the Cilium rollout gate was released (#3035, merged 2026-08-09T20:00Z) every deploy runs πŸ”„ Update cluster (Talos machine config) again β€” and every deploy now rolling-reboots all seven nodes. Deploy durations, newest first:

Deploy started πŸš€ Deploy to Production cluster update
2026-08-09T20:06Z 52 min (reassert 2863 s) ran
2026-08-09T19:22Z 36.5 min (reassert 1974 s) ran
2026-08-09T18:01Z 64 min ran
2026-08-09T16:29Z 4.8 min skipped (gate active)
2026-08-08 Γ—6 4.4–5.7 min skipped (gate active)

The gate acted as an accidental A/B toggle: with cluster update skipped the deploy is ~5 min, with it running it is ~an hour.

Root cause, isolated within a single run (run 31333379409)

The same script runs before and after cluster update, so one run contains its own control:

Step root Secret result nodes rebooted
πŸ”‘ Stage β€” before cluster update ksail-registry-credentials patched (no change) 0
πŸ”‘ Reassert β€” after cluster update ksail-registry-credentials patched (changed) 7

The cluster is fully converged at Stage. ksail cluster update then rewrites flux-system/ksail-registry-credentials away from the Git/SOPS value and invalidates every node's v2 proof, so select_talos_node_targets selects all seven in reboot mode and the reassert performs a serial rolling reboot at ~5–6 min per node.

That the Secret gets rewritten is known and expected β€” AGENTS.md says the bridge "reasserts it after cluster update in case KSail rewrites its managed Secret". What appears unintended is that the rewrite also costs the node proof, since the proof annotations are Talos machine config (machine.nodeAnnotations) and cluster update re-renders machine config from ksail.prod.yaml and its patches. Two writers, one config: the bridge writes the proof, cluster update drops it, and the bridge then rebuilds it the expensive way.

Impact

Roughly 45–60 minutes added to every merge, on a repo whose main is behind a merge queue, so this serializes all delivery. It also reboots all seven production nodes β€” including all three control-plane members β€” on every merge, which is real availability risk taken repeatedly for no state change: the fleet is proven current 5 minutes earlier in the same run.

Expected

A cluster update that changes nothing about the registry credential should leave the node proof intact, so the reassert converges without rebooting anything. Directions worth evaluating (deliberately not pre-judged β€” this needs a decision, and one of them may be wrong for reasons the evidence here does not show):

  1. Carry the proof annotations in the machine config ksail cluster update itself renders, so a re-render preserves rather than drops them.
  2. Key node staleness on something cluster update does not rewrite β€” e.g. reading the node's effective RegistryAuthConfig rather than an annotation the same command owns.
  3. Have the bridge re-apply the proof annotations without a reboot when the credential is unchanged and only the annotation was lost β€” the reboot exists because containerd loads registry auth at process start, which does not apply when the auth did not change.

Acceptance criteria

  • A deploy whose credential is unchanged completes without rebooting any node.
  • A deploy whose credential did change still reboots the affected nodes and proves an uncached pull (the existing guarantee must not regress) β€” pinned by a test.
  • Before/after deploy durations recorded in the PR.

Rough size: M–L, and it needs a decision between the directions above before implementation. Related: #3039 and #3041 address the fence overhead, which is ~60 s and a different, much smaller cost β€” they do not address this.

Activity

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

    @coderabbitai
    Contributor
    πŸ”— Related PRs

    #2625 - fix(deploy): synchronize production GHCR pull auth [merged]
    #2633 - fix(deploy): verify incoming image on Talos nodes [merged]
    #2927 - fix(deploy): await pre-handoff kustomize-controller pod termination [merged]
    #2962 - fix(deploy): make rollout-gate suppression of machine-config sync visible and bounded [merged]
    #3035 - feat(cilium): release the homogeneous-device rollout gate [open]


    πŸ“ Issue Planner

    Check the box below or use the @coderabbitai plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    πŸ§ͺ Issue enrichment is currently in open beta.

    You can configure auto-planning by selecting labels in the issue_enrichment configuration.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    πŸ’¬ Have feedback or questions? Drop into our discord!

  4. self-assigned this
    on Aug 12, 2026
  5. moved this from πŸ“₯ Backlog to πŸ‘€ In Review in 🌊 Project Boardon Aug 12, 2026
  6. moved this from πŸ‘€ In Review to βœ… Done in 🌊 Project Boardon Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

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