Skip to content

Support autoscaling the API on GKE - #95

Open
brianvans (brianvans) wants to merge 7 commits into
mainfrom
brianvans/support-autoscaling-api-on-gke
Open

Support autoscaling the API on GKE#95
brianvans (brianvans) wants to merge 7 commits into
mainfrom
brianvans/support-autoscaling-api-on-gke

Conversation

@brianvans

Copy link
Copy Markdown
Contributor

Adds optional Horizontal Pod Autoscaling on GKE using native AutoscalingMetric support. When turned on, the API scales on CPU, event-loop utilization, and mean event-loop delay (same signals we use on AWS ECS), and Prometheus metrics are enabled automatically. Requires GKE 1.35.1+.

This has a hard requirement on v2.9.0+ of the API, as this introduced the internal /metrics endpoint capability.

See https://docs.cloud.google.com/kubernetes-engine/docs/how-to/expose-custom-metrics-autoscaling for docs on the GKE preview feature that backs this.

Adds optional Horizontal Pod Autoscaling on GKE using native
AutoscalingMetric support. When turned on, the API scales on CPU,
event-loop utilization, and mean event-loop delay (same signals we use
on AWS ECS), and Prometheus metrics are enabled automatically. Requires
GKE 1.35.1+.

See https://docs.cloud.google.com/kubernetes-engine/docs/how-to/expose-custom-metrics-autoscaling

@erikdw Erik Weathers (erikdw) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two small follow-ups. Neither blocks merge.

{{- end }}
{{- if .Values.api.extraEnvVars }}
{{- toYaml .Values.api.extraEnvVars | nindent 12 }}
{{- end }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

When autoscaling is on, the chart sets ENABLE_PROMETHEUS_METRICS=true before extraEnvVars.

Kubernetes keeps both env entries. The last entry wins.

If extraEnvVars sets ENABLE_PROMETHEUS_METRICS to "false", the gauges do not publish. The HPA then cannot read the custom metrics. Helm does not report an error.

Move this env entry after extraEnvVars, so autoscaling keeps the value "true".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Is this behavior consistent with the rest of the helm chart? I feel like we usually merge anything "extra" in last

@erikdw Erik Weathers (erikdw) Aug 10, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

For this one it’s chart/Braintrust-owned, not a user knob. If extraEnvVars sets ENABLE_PROMETHEUS_METRICS=false, they silently kill autoscaling (no Helm error). Fine for extras to win elsewhere, but here the autoscaling-owned true should come last, or we could be in a world of pain.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated

Comment thread braintrust/README.md
- GKE **1.35.1-gke.1396000** or later
- The Performance HPA profile and the Autoscaling API enabled on the cluster
- `roles/autoscaling.metricsWriter` granted to all node service accounts
- The Autoscaling API included in your service perimeter when using VPC Service Controls

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Google documents this Preview feature for GKE 1.35.1-gke.1396000 or later on the Rapid release channel.

This list names the version and the Performance HPA profile. It does not name the Rapid channel.

Add Rapid to the list here and in values.yaml. Clusters on Regular or Stable will not get this feature.

@brianvans brianvans (brianvans) Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think rapid channel was a launch constraint from when this feature initially became a preview. I was on the stable regular channel while testing this and all required functionality existed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Are you sure the cluster itself was on the stable channel? When I looked right now it showed Rapid in the GCP console.

CleanShot 2026-08-10 at 16 41 52@2x

@brianvans brianvans (brianvans) Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Oops yeah I mis-spoke re: stable. I tested on regular (the channel we default to in the gcp terraform module), and then switched to rapid to test against the newest version. At least in us-central1, these are the channels that meet the requirements

$ gcloud container get-server-config --flatten="channels" --format="yaml(channels.channel,channels.defaultVersion)" --location=us-central1
Fetching server config for us-central1
---
channels:
  channel: EXTENDED
  defaultVersion: 1.35.6-gke.1250000
---
channels:
  channel: RAPID
  defaultVersion: 1.36.2-gke.2064000
---
channels:
  channel: REGULAR
  defaultVersion: 1.35.6-gke.1250000
---
channels:
  channel: STABLE
  defaultVersion: 1.34.9-gke.1065000

I'm not in love with documenting a channel requirement, as a) these change over time (docs burden) and b) there's no guarantee that a cluster in a channel is at the most current version.

How about we see if helm can ensure the CRD is available and fail with a friendly error if not?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added an explicit check for the required CRD in 7acb818

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

wow this channel stuff is so complicated! I like the solution you came up with.

Comment thread braintrust/values.yaml Outdated
# See: https://docs.cloud.google.com/kubernetes-engine/docs/how-to/expose-custom-metrics-autoscaling
autoscaling:
enabled: false
minReplicas: 3

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

api.replicas defaults to 4. minReplicas defaults to 3.

If you turn on autoscaling on an existing deploy and load is low, the HPA can scale the API from 4 pods to 3 pods with no load change.

Set the minReplicas default to 4 so that this does not happen.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hmm — so we'll be inconsistent somewhere. Options:

  1. Drop api.replicas default to 3 to match ECS / minReplicas, or
  2. Keep k8s at a higher floor (minReplicas: 4) because the pod footprint is different (sidecar/helper daemons, etc.).

I'd slightly prefer (2) + a one-line README note that enabling autoscaling may change replica count unless minReplicas is set explicitly — but matching ECS min=3 is also fine if we document the 4→3 step-down.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Okay bumped to 4 minReplicas

@erikdw Erik Weathers (erikdw) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:shipit:

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.

2 participants