kubectl top pod answering “error: Metrics API not available” and an HPA showing no metrics at all in kubectl describe hpa share the same cause: metrics-server isn’t installed. It isn’t a prerequisite for either tool in the usual sense, it’s the data source without which they have nothing to read, never explicitly named in the documentation that explains how to configure an HPA.
What metrics-server collects, and what it doesn’t
metrics-server periodically queries each node’s kubelet, which itself exposes CPU and memory usage statistics collected by cAdvisor, and aggregates everything into the metrics.k8s.io API. That’s the API kubectl top and the HPA controller both consult.
# Once metrics-server is installed and working
kubectl top nodes
kubectl top pods -n production
What metrics-server never does: keep history. Every query returns the most recent instantaneous usage, nothing more; no data is stored beyond the shortest window needed for the calculation. For metric history, dashboards, or trend-based alerting, a full observability solution is needed (Prometheus and the golden signals): metrics-server was never designed for that role, only to feed real-time autoscaling decisions.
The most common certificate error at install time
A default metrics-server install often fails with an error tied to kubelet certificate TLS validation, particularly common on self-managed clusters where the kubelet certificate isn’t signed by an authority metrics-server trusts by default:
# Workaround flag, only after understanding why validation
# actually fails, never as an automatic reflex
args:
- --kubelet-insecure-tls
This flag disables certificate verification, which resolves the symptom without addressing the cause: on a cluster with a properly configured PKI, the real fix is getting metrics-server to trust the kubelet’s certificate authority, not disabling verification. --kubelet-insecure-tls remains an acceptable pragmatic choice on many self-managed clusters, as long as the decision is conscious rather than copy-pasted from a tutorial unread.
Why HPA stays silent without it
An HPA configured on a cluster without metrics-server produces no immediately visible error: it just sits stuck, TARGETS showing <unknown> in kubectl get hpa, never scaling and never explaining why. That silence is the most common reason an HPA “doesn’t work” despite perfectly correct YAML: the problem is never in the HPA itself, but in the absence of the data source it entirely depends on.
What goes beyond metrics-server: custom metrics
An HPA scaling on something other than CPU/memory (a message-queue length, an application request rate) can’t rely on metrics-server, limited to standard resources. That case requires a custom metrics adapter, usually wired to Prometheus, exposing those metrics through a separate API (custom.metrics.k8s.io). It’s an extension of the same principle, not a replacement: metrics-server stays the source for CPU/memory, the custom adapter takes over for everything else.
Takeaway
metrics-server is the silent prerequisite feeding kubectl top and HPA real-time data, with no history and no ambition to replace a full observability stack. An HPA stuck with <unknown> targets almost always signals its absence, not a configuration mistake. The install-time certificate error gets solved by understanding the cluster’s PKI trust chain, not by systematically disabling verification. This foundation is part of what gets laid from the earliest steps of a Kubernetes migration.