Skip to content

feat: allow an external autoscaler to own proxy Deployment replicas - #9628

Open
guanchzhou wants to merge 2 commits into
envoyproxy:mainfrom
guanchzhou:eg-external-autoscaler-replicas
Open

feat: allow an external autoscaler to own proxy Deployment replicas#9628
guanchzhou wants to merge 2 commits into
envoyproxy:mainfrom
guanchzhou:eg-external-autoscaler-replicas

Conversation

@guanchzhou

Copy link
Copy Markdown
Contributor

What this PR does

Adds replicasManagedByExternalAutoscaler to the Envoy proxy KubernetesDeploymentSpec. When set to true, Envoy Gateway omits the replicas field from the generated proxy Deployment, so an external autoscaler — a user-managed HorizontalPodAutoscaler, a KEDA ScaledObject, etc. — can own the replica count without Envoy Gateway reverting it on the next reconcile.

Why

Envoy Gateway applies the proxy Deployment with server-side apply + ForceOwnership, so it owns spec.replicas and reverts any externally computed value unless the built-in envoyHpa is configured. But envoyHpa only supports what a native HPA metrics spec can express — it can't drive Prometheus-query / event-driven scaling that KEDA provides.

Today the only workaround is to template-unset envoyDeployment.replicas so Envoy Gateway doesn't own the field — brittle, and it has to be repeated per gateway. This is the same class of problem as the stale #5751; the recent fix that omits spec.replicas under an HPA only covers the built-in envoyHpa, not external autoscalers.

Fixes #9627.

Implementation

  • API (api/v1alpha1/shared_types.go): new optional ReplicasManagedByExternalAutoscaler *bool on KubernetesDeploymentSpec.
  • Controller (internal/infrastructure/kubernetes/proxy/resource_provider.go): replicas is left nil when the flag is set or EnvoyHpa != nil. Semantics mirror the existing envoyHpa path — when set, Replicas is ignored (precedence, no hard rejection, which is friendlier for GitOps migrations). Deployment only (DaemonSet has no replicas).
  • Regenerated deepcopy, both envoyproxies CRDs, and the API reference.
  • Docs: a new "Scale EnvoyProxy with an External Autoscaler" section in customize-envoyproxy.md, including how to target the Deployment via a pinned envoyDeployment.name or the stable gateway.envoyproxy.io/owning-gateway-* labels, with a KEDA ScaledObject example.
  • Release note fragment added.

Testing

New golden test case with-external-autoscaler asserts spec.replicas is absent when the flag is set and no envoyHpa is configured (the exact fingerprint of the bug), and unchanged otherwise.

go build ./...                                            # ok
go test ./internal/infrastructure/kubernetes/proxy/...    # ok
go test ./api/...                                         # ok
gofmt -l / go vet                                         # clean

Open question for maintainers

Boolean (replicasManagedByExternalAutoscaler, as here) vs. an enum (replicaManagement: EnvoyGateway | External). Happy to switch to whichever you prefer. A follow-up PR can mirror the field on the rate limit deployment for symmetry.

Add EnvoyProxy.spec.provider.kubernetes.envoyDeployment.replicasManagedByExternalAutoscaler.
When true, Envoy Gateway omits the replicas field from the generated proxy Deployment so an
external autoscaler (an external HorizontalPodAutoscaler, a KEDA ScaledObject, etc.) can own
the replica count without Envoy Gateway reverting it on the next reconcile. This reuses the
same server-side-apply ownership behavior already used for the built-in envoyHpa, which only
supports what a native HPA metrics spec can express.

Fixes envoyproxy#9627

Signed-off-by: Andrey Maltsev <maltsev.andrey@gmail.com>
@guanchzhou
guanchzhou requested a review from a team as a code owner July 31, 2026 11:43
@netlify

netlify Bot commented Jul 31, 2026

Copy link
Copy Markdown

Deploy Preview for cerulean-figolla-1f9435 ready!

Name Link
🔨 Latest commit d2496f9
🔍 Latest deploy log https://app.netlify.com/projects/cerulean-figolla-1f9435/deploys/6a6c8e40b313060008decbef
😎 Deploy Preview https://deploy-preview-9628--cerulean-figolla-1f9435.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9d0fadb8a4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread api/v1alpha1/shared_types.go
@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.04%. Comparing base (b710dd4) to head (d2496f9).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #9628   +/-   ##
=======================================
  Coverage   76.04%   76.04%           
=======================================
  Files         259      259           
  Lines       43275    43277    +2     
=======================================
+ Hits        32907    32912    +5     
+ Misses       8178     8176    -2     
+ Partials     2190     2189    -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…nt, regen helm goldens

- Honor replicasManagedByExternalAutoscaler in the ratelimit Deployment renderer, since
  KubernetesDeploymentSpec is shared with rateLimitDeployment. Previously the flag was
  silently ignored there and EG kept owning spec.replicas.
- Add a with-external-autoscaler golden test for the ratelimit deployment.
- Regenerate gateway-crds-helm test goldens to include the new CRD field (gen-check).

Signed-off-by: Andrey Maltsev <maltsev.andrey@gmail.com>
@arkodg

arkodg commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

does #9594 fix this issue ?

@guanchzhou

Copy link
Copy Markdown
Contributor Author

@arkodg Not quite — #9594 and this PR are complementary:

if provider.GetEnvoyProxyKubeProvider().EnvoyHpa != nil ||
    ptr.Deref(deploymentConfig.ReplicasManagedByExternalAutoscaler, false) {
    replicas = nil
}

The motivating case is a KEDA ScaledObject (or a user-managed HPA) scaling the proxy fleet on a Prometheus/event-driven trigger — something the built-in envoyHpa can't express, since it only takes a native HPA metrics spec. With #9594 alone, those users still have to template-unset envoyDeployment.replicas to stop the controller reverting the externally-computed count (the exact workaround this PR removes). The ratelimit Deployment path is covered symmetrically.

Happy to rebase or adjust naming (boolean vs an enum like replicaManagement: External) if you'd prefer.

@zirain

zirain commented Aug 3, 2026

Copy link
Copy Markdown
Member

replicaManagement: External looks better from my POV.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow an external autoscaler (KEDA / external HPA) to own proxy Deployment replicas

3 participants