Horizontal scaling decisions often start with resource utilization because those measurements are widely available. They may not reveal whether work is being completed fast enough or whether a service is approaching an application-specific limit.
On July 14, 2026, the Kubernetes project published a hands-on guide to writing, packaging and deploying a custom metrics exporter. Its walkthrough follows measurements from an application data source through the exporter and verifies that Prometheus can scrape them. Connecting those time series to the Kubernetes Custom Metrics API through an adapter, and then referencing them from a HorizontalPodAutoscaler, is presented as the next step rather than part of the walkthrough itself.
CPU is useful, but it is only one view
A connection-heavy service can run out of session capacity while processor usage remains modest. A batch platform may need to react to the age of unfinished jobs. A queue consumer can also fall behind when each worker spends much of its time waiting on I/O rather than using CPU.
In each case, CPU is a proxy for pressure, not the pressure itself. Scaling on the wrong proxy can make a system react late, add capacity that does not address the bottleneck or scale down while unfinished work is still accumulating.
Custom metrics give teams a way to represent that pressure more directly. Backlog size, job age, concurrent sessions, request latency and other application measurements can become inputs to the autoscaling loop that manages replicas, provided the chosen signal actually responds to added capacity.
The path from application state to the autoscaler
The guide's example models three different shapes of operational data: cumulative job completions, an instantaneous backlog and a distribution of processing times. A Prometheus client library represents them as a counter, a gauge and a histogram, then renders the resulting measurements on a `/metrics` endpoint.
Deployment alone does not put those measurements into Prometheus. The scrape configuration still has to discover the endpoint. The guide provides a Prometheus Operator `ServiceMonitor` example and an annotation-based alternative, then checks both target health and a query result to confirm that data is arriving.
The guide ends after establishing the exporter-to-Prometheus path. Completing the autoscaling path requires a metrics adapter, which can expose selected Prometheus series through Kubernetes' aggregated `custom.metrics.k8s.io` API. A HorizontalPodAutoscaler using the stable `autoscaling/v2` API can then reference an exposed custom measurement in its configuration.
The flow is therefore straightforward in concept:
Application state -> exporter -> Prometheus -> metrics adapter and Custom Metrics API -> HorizontalPodAutoscaler.
Every arrow matters. A healthy exporter does not prove that Prometheus is scraping it, and a visible Prometheus series does not prove that the Custom Metrics API exposes the name the autoscaler expects.
Choose a signal that deserves control
Not every observable number should control capacity. A useful scaling metric should have a clear relationship with the work each replica can absorb. It should update frequently enough to guide decisions and behave predictably when replicas are added or removed.
Queue depth is often a strong candidate for worker systems because it measures waiting work. A per-pod request rate can help when traffic distributes evenly. Latency may matter, but it can also rise because of a slow database or external dependency that additional application pods cannot fix.
Teams should also be careful with labels. Prometheus labels are valuable for separating outcomes or workloads, but unbounded values such as user IDs or request IDs can create excessive time-series cardinality. A custom metric that is expensive or unreliable to collect can become a new operational dependency in the scaling path.
The practical test is simple: if the metric rises, will adding replicas usually reduce it? If the answer is uncertain, the signal may belong in an alert or dashboard before it belongs in an autoscaler.
How Kubernetes turns measurements into replicas
The HorizontalPodAutoscaler periodically compares the observed metric with a configured target and calculates a desired replica count. For custom metrics attached to pods, it can work with raw per-pod values. For object or external metrics, it can compare a single value with the target and, where configured, account for the number of pods.
Kubernetes also supports multiple metrics in one `autoscaling/v2` policy. The controller evaluates each one and uses the largest recommended replica count, subject to the configured maximum. That makes it possible to retain CPU as a safety signal while adding a workload metric that reacts more directly to demand.
More signals do not automatically produce a better policy. Missing data, delayed samples and short-lived spikes can make a controller noisy. Kubernetes provides scaling policies, tolerance and stabilization windows to limit abrupt changes and reduce repeated scale-up and scale-down cycles.
A safer rollout sequence
A production rollout should start with observation rather than immediate control.
First, expose the metric and compare it with real workload behaviour. Confirm its units, labels, update frequency and failure mode. Second, verify the full path from exporter to Prometheus to the Custom Metrics API. Third, run the autoscaler with conservative minimum and maximum replica counts and review its recommendations during both steady load and bursts.
Readiness also matters because a new pod is not useful capacity until it can serve work. The Kubernetes autoscaling documentation handles missing measurements conservatively across scaling calculations, but its special treatment for not-yet-ready pods and startup initialization periods is described specifically for CPU metrics. Object and external metric calculations use the number of running and ready pods, so teams should review probe behavior and the chosen metric source together instead of assuming CPU's startup rules apply unchanged.
Finally, teams need an answer for telemetry failure. If the exporter, scraper or adapter stops reporting, the application should not depend on an unsafe assumption that demand has disappeared. Dashboards and alerts should make a broken metrics path visible, and capacity floors should protect essential workloads.
Why this matters
Autoscaling is often presented as a resource-management feature. Custom metrics turn it into an application-design decision. The team must decide which signal represents useful work, how quickly the system should react and what guardrails prevent a noisy measurement from controlling too much infrastructure.
The July 14 Kubernetes guide is valuable because it makes the plumbing concrete. But the strongest result is not simply a working exporter. It is an autoscaling policy that follows the demand users create, has a verified data path and fails predictably when that data is unavailable.
For teams running queues, streaming services, long-lived connections or other workloads that CPU cannot describe well, custom metrics can make Kubernetes scaling more relevant. The hard part is not exposing another number. It is choosing one that the system can trust.
Sources
• Kubernetes Blog, July 14, 2026, Building a Custom Metrics Exporter for Kubernetes: https://kubernetes.io/blog/2026/07/14/custom-metrics-exporter-kubernetes/
• Kubernetes documentation, Horizontal Pod Autoscaling: https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/
• Kubernetes API reference, Custom Metrics v1beta2: https://kubernetes.io/docs/reference/external-api/custom-metrics.v1beta2/



