feat(ha): add drain-safe PDBs to the remaining critical controllers and apps#1991
feat(ha): add drain-safe PDBs to the remaining critical controllers and apps#1991devantler wants to merge 7 commits into
Conversation
…nd apps Completes the #1880/#1882 drain-safe PDB sweep: every multi-replica platform-critical workload now bounds voluntary disruption to one pod at a time (maxUnavailable: 1), so node drains, Talos upgrades and autoscaler scale-down never take a whole control plane component down at once and never deadlock. Chart-native values where the chart supports the maxUnavailable shape: - keda: operator, metrics-apiserver, admission-webhooks - external-secrets: controller, webhook, cert-controller (minAvailable nulled out -- the chart defaults to the minAvailable shape that validate-pdb-drain-safe flags) - vpa: recommender + updater (mirrors the existing admissionController) - kyverno: background/reports/cleanup controllers (chart auto-enables their PDBs at replicas > 1 with minAvailable: 1; pin maxUnavailable) Raw PodDisruptionBudget manifests where the chart has no usable knob: - flagger (chart only offers minAvailable) - keda-add-ons-http external scaler (chart covers only the interceptor) - snapshot-controller (piraeus chart has no PDB value; hetzner overlay) - umami (Flagger target; selector keys on app.kubernetes.io/instance because Flagger rewrites /name on the primary, see canary.yaml) - actual-budget (KEDA scale-to-zero; inert at 0 replicas) OpenBao needs no change: at openbao_replicas: 3 the chart's default ha.disruptionBudget already renders maxUnavailable: 1. Validated: ksail workload validate green (320 files); prod validate's only failure is the known pre-existing coroot schema gap in the upstream CRDs-catalog. All chart-value shapes verified against rendered templates (helm template) for keda 2.20.0, external-secrets 2.5.0, kyverno 3.8.1, vpa 4.11.0, keda-add-ons-http 0.14.1, openbao 0.28.3. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
System-test status: the first run failed in ~3 min on a transient schema-fetch error during |
…ride renders
The kyverno chart defaults each controller's podDisruptionBudget to
minAvailable: 1, and Helm deep-merges user values onto chart defaults --
so setting only maxUnavailable left BOTH fields set and the chart's
kyverno.pdb.spec helper hard-failed every upgrade at render time
('Cannot set both .minAvailable and .maxUnavailable') wherever the
controllers run more than one replica. minAvailable: null deletes the
default key at value coalescing, the same mechanism the external-secrets
values in this PR already use.
Verified by rendering kyverno 3.8.1 with all three controllers at 3
replicas: without the null the render reproduces the reported failure;
with it, each controller gets a maxUnavailable: 1 PDB. The other charts
in this PR are not affected -- keda and vpa default their PDB blocks to
{} (no minAvailable to merge against).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixed the reported kyverno failure and merged Verified by rendering kyverno 3.8.1 with all three controllers at 3 replicas: without the null the render reproduces the exact error; with it each controller gets a clean |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
System Test run 27361178852 (the first run after the kyverno The kyverno values themselves are sound — independently verified by rendering chart 3.8.1 with the fixed values ( FYI: the wider incident this PR's merge-queue attempt caused is written up in #2026 (merge-group deploys leave prod on unmerged code when the group fails). |
The 16:18 run on |
Main independently landed overlapping PDB changes in #2016 (kyverno reports/cleanup PDB flips with identical values, and VPA recommender/ updater PDBs at a different position in each block). Resolution keeps main's comment wording for kyverno and main's placement for the VPA blocks, deduplicating the auto-merged duplicate podDisruptionBudget keys git produced in recommender and updater. No value differences remain between the two lineages for those files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 17:36 run on |
Third occurrence of the runner-starvation flake on this branch (this time visible at the lowest level: kube-scheduler itself timing out lease renewal against KubePrism at |
Summary
Completes the #1880/#1882 drain-safe PDB sweep so node drains, Talos upgrades and autoscaler scale-down never take out a whole platform component at once — and never deadlock. Every change uses the house pattern
maxUnavailable: 1, which the disruption controller evaluates against the live replica count, so it stays drainable even if a replica floor drops.Chart-native values (chart supports the maxUnavailable shape)
minAvailable: nullremoves the chart's default minAvailable shape thatvalidate-pdb-drain-safeflags)minAvailable: 1, so prod (3 replicas each) has been running the flagged shape; this pinsmaxUnavailable: 1insteadRaw PDB manifests (no usable chart knob)
minAvailableapp.kubernetes.io/instancebecause Flagger rewrites/nametoumami-umami-primaryon the primary (see canary.yaml); provision-tenants Job pods carry different labels and are not matchedExplicitly unchanged
openbao_replicas: 3the chart's defaultserver.ha.disruptionBudgetalready rendersmaxUnavailable: 1(verified against the 0.28.3 template math).validate-replica-floorexemptions.Validation
ksail workload validate: green (320 files)ksail --config ksail.prod.yaml workload validate: only failure is the pre-existing coroot schema gap in the upstream datreeio CRDs-catalog (fixed upstream by CRDs-catalog#896, unrelated)helm templateand inspecting the produced PDBs (all rendermaxUnavailable: 1; kyverno verified via itskyverno.pdb.spechelper which forbids setting both fields)🤖 Generated with Claude Code