feat(autoscaling): scale on request rate past the VPA ceiling, cap replicas at 3#2030
Merged
Merged
Conversation
…plicas at 3 - homepage/umami: KEDA ScaledObjects (min 2 / max 3) on Coroot's eBPF inbound request-rate series, wired through Flagger's autoscalerRef so the primary scales and the canary source stays paused at 0 between rollouts; drop the now-obsolete postRenderer replicas pins - whoami/fleetdm: raise HTTPScaledObject ceilings 2 -> 3 - netpols: KEDA operator -> coroot-prometheus:9090 (egress + ingress) - validate-replica-ceiling (Audit): flags workloads declaring >3 replicas and autoscaler ceilings >3. A PDB cannot express this — it has no maxAvailable field and only gates voluntary evictions — so the cap lives on the autoscalers and is audited by policy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
|
🎉 This PR is included in version 1.52.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements "scale vertically up to a sane limit, then horizontally" and codifies the 3-pod-per-workload ceiling.
Why the PDB ask landed elsewhere
PodDisruptionBudgethas nomaxAvailablefield — its API is onlyminAvailable/maxUnavailable, and a PDB only gates voluntary evictions; it cannot cap how many pods a controller creates. The repo's PDBs already follow the drain-safemaxUnavailable: 1house pattern (completed by #1991), so no PDB was changed here. The "never more than three pods per Deployment/StatefulSet/ReplicaSet" rule is instead enforced where replica counts actually live:validate-replica-ceiling— a new Audit-mode Kyverno ClusterPolicy (inverse ofvalidate-replica-floor) flagging any Deployment/StatefulSet/ReplicaSet declaring >3 replicas and any HPA / ScaledObject / HTTPScaledObject whose ceiling exceeds 3 (including KEDA's implicit default of 100 when the ceiling is unset). Audit, not Enforce, for the same reason as the floor policy: replicas are owned by KEDA/Flagger/HPA at runtime and an admission deny would fight them. Escape hatch:platform.devantler.tech/replica-ceiling: exempt.Horizontal scaling on a metric that complements VPA
The vertical axis already exists:
auto-vparight-sizes every workload in place up tomaxAllowed(3 CPU / 6Gi) — that is the "sane limit". The horizontal trigger must therefore be a metric VPA does not control, or the two fight. The platform's established answer is HTTP request rate, and this PR completes it:ScaledObject2–3 on Coroot RPS, via FlaggerautoscalerRef# No autoscalerRef)For homepage/umami this uses the pattern
docs/progressive-delivery.mddocumented but never used: a namedprometheustrigger oncontainer_http_inbound_requests_total(Coroot's eBPF node-agent series, same source as the Flagger MetricTemplates), referenced from theCanaryviaautoscalerRef. Flagger clones each ScaledObject to<name>-primary(query rewritten for-primary-pods viaprimaryScalerQueries; the source query's vowel-free hash regex can't match-primary-) and pauses the source's scaler at 0 between rollouts — preserving today's behavior. The obsolete postRenderer replicas pins were removed;fallback: replicas: 3fails high to the old static HA count if Prometheus is unreachable.The mechanics: when sustained load outgrows what right-sized pods absorb, RPS-per-pod crosses the per-pod threshold (homepage 10 rps — single-threaded Next.js SSR; umami 50 rps — cheap
/api/sendingest) and the 2→3 scale-out fires. Thresholds are marked for tuning against livecoroot-prometheusdata. Two replicas still survive a node drain (PDBmaxUnavailable: 1+ topology spread); the steady-state drop from 3→2 returns memory on a memory-tight cluster.Network path:
allow-kedagains egress toobservability:9090andallow-corootgains the matching ingress — mirroring the existing Flagger/OpenCost rules.Open question on the "5"
The request said
maxAvailable: 5but also "never more than three pods" — since the field doesn't exist, I implemented the explicit 3-pod rule throughout. If 5 was meant as the autoscaler ceiling instead, it's a one-line change in each scaler plus the policy's threevalue: 3comparisons.Validation
ksail workload validate: green (304 files)ksail --config ksail.prod.yaml workload validate: sole failure is the pre-existing upstream datreeio CRDs-catalog coroot schema gap (notificationIntegrations— fixed by CRDs-catalog#896), unrelatedkubectl kustomizeof both cluster overlays +providers/hetzner/{apps,infrastructure}andbases/infrastructure/controllers: all build; ScaledObjects,autoscalerRefs, netpol rules, and the new ClusterPolicy verified in the rendered output-primaryScaledObjects and KEDA takes over primary replica counts (expected steady-state 2 unless RPS demands 3). The PromQL is written against Coroot's documented schema but not validated against live data — same caveat as the existing MetricTemplates.🤖 Generated with Claude Code