Prometheus Adapter for HPA on EKS
Use prometheus-adapter when Horizontal Pod Autoscaler (HPA) should scale on application metrics (request rate, queue lag, business KPIs) defined in PromQL, not only CPU and memory.
Overview: Autoscaling on EKS. k3s lab: Prometheus Adapter HPA on k3s. For CloudWatch-native metrics, see Container Insights for HPA on EKS.
When to use
Section titled “When to use”| Use Prometheus Adapter | Consider KEDA instead |
|---|---|
| RPS, latency, in-cluster PromQL | SQS / Kafka / cron triggers |
| You already run Prometheus or AMP remote write | Minimal metrics plumbing for queues |
| Same metric feeds dashboards and HPA | Event source is outside Prometheus |
Choose your Prometheus backend
Section titled “Choose your Prometheus backend” ┌─────────────────────────────┐ │ prometheus-adapter │ │ (custom.metrics.k8s.io) │ └──────────────┬──────────────┘ │ queries ┌───────────────────────┼───────────────────────┐ ▼ ▼ ▼ In-cluster Prometheus Amazon Managed Prometheus Remote Prometheus URL (Helm / operator) (workspace + remote write) (VPC endpoint / VPN)| Backend | This guide |
|---|---|
In-cluster Prometheus (e.g. kube-prometheus-stack) | Primary walkthrough below |
| Amazon Managed Prometheus (AMP) | Alternative setup — AMP |
You still need metrics-server if the same HPA mixes Resource metrics (CPU) with custom metrics.
Prerequisites
Section titled “Prerequisites”- EKS cluster 1.23+,
kubectlconfigured. - Helm 3 — Helm.
- Prometheus reachable from the adapter pod (in-cluster Service DNS or AMP query endpoint).
- Cluster admin to install APIService and ClusterRole for the adapter.
Verify APIs:
kubectl get apiservice v1beta1.metrics.k8s.io# After adapter install:kubectl get apiservice v1beta1.custom.metrics.k8s.ioInstall prometheus-adapter (in-cluster Prometheus)
Section titled “Install prometheus-adapter (in-cluster Prometheus)”Assume Prometheus from kube-prometheus-stack in namespace monitoring, Service monitoring-kube-prometheus-prometheus on port 9090. Adjust names to your release.
1. Rules ConfigMap
Section titled “1. Rules ConfigMap”Create adapter-rules.yaml:
rules: - seriesQuery: 'http_requests_total{namespace!="",pod!=""}' resources: overrides: namespace: { resource: "namespace" } pod: { resource: "pod" } name: matches: "^(.*)_total$" as: "${1}_per_second" metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)'2. Helm values
Section titled “2. Helm values”Create prometheus-adapter-values.yaml:
prometheus: url: http://monitoring-kube-prometheus-prometheus.monitoring.svc port: 9090
rules: existing: adapter-rules
replicas: 2
resources: requests: cpu: 100m memory: 128Mi3. Install chart
Section titled “3. Install chart”helm repo add prometheus-community https://prometheus-community.github.io/helm-chartshelm repo update
helm upgrade --install prometheus-adapter prometheus-community/prometheus-adapter \ --namespace monitoring \ --create-namespace \ -f prometheus-adapter-values.yaml \ --wait4. Verify adapter and API
Section titled “4. Verify adapter and API”kubectl get pods -n monitoring -l app.kubernetes.io/name=prometheus-adapterkubectl get apiservice v1beta1.custom.metrics.k8s.io
# List custom metrics (names vary with your rules)kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | head -c 2000Expected: adapter pods Running; APIService Available; raw API returns resource kinds.
kubectl logs -n monitoring -l app.kubernetes.io/name=prometheus-adapter --tail=100Sample app and HPA (Pods metric)
Section titled “Sample app and HPA (Pods metric)”Deploy a workload that exports http_requests_total and is scraped by Prometheus ( ServiceMonitor with release: monitoring if using kube-prometheus-stack — see Observability setup).
Example HPA fragment (metric name must match adapter rule output, e.g. http_requests_per_second):
apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: name: sample-app-hpa namespace: defaultspec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: sample-app minReplicas: 2 maxReplicas: 10 metrics: - type: Pods pods: metric: name: http_requests_per_second target: type: AverageValue averageValue: "100"kubectl apply -f sample-app-hpa.yamlkubectl describe hpa sample-app-hpa -n defaultEKS specifics
Section titled “EKS specifics”- Networking: Prometheus in another VPC or AMP private endpoint requires security groups and DNS so adapter pods can query port 9090 / 443.
- IRSA: Adapter pods usually need no AWS API access; workloads scraping AWS metrics may — keep IAM on the app or use Container Insights guide instead.
- AMP: Use workspace query URL in
prometheus.url/prometheus.portand ensure adapter identity can reach the endpoint (VPC endpoints, IAM if using SigV4 proxy). - High availability: Run 2+ adapter replicas; APIService aggregates from any healthy adapter.
Alternative setup: Amazon Managed Prometheus
Section titled “Alternative setup: Amazon Managed Prometheus”- Create an AMP workspace and configure remote write from in-cluster Prometheus or ADOT collectors.
- Point prometheus-adapter
prometheus.urlat the AMP query endpoint for your workspace (see current AMP documentation). - Reuse the same rules ConfigMap; validate metric names exist in AMP with the AMP query editor.
- Install adapter via Helm as above with updated
prometheus-adapter-values.yaml.
AMP networking and authentication change with private VPC endpoints — validate kubectl get --raw from a debug pod before wiring HPA.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely cause | Action |
|---|---|---|
| APIService not Available | Adapter crash, TLS, wrong Prometheus URL | Check adapter logs and prometheus.url |
HPA unable to get metrics | Metric name mismatch | Compare describe hpa with kubectl get --raw .../namespaces/NS/... |
| Metric never appears | No series in Prometheus | Targets UP? PromQL returns data? |
| Forbidden on metrics API | RBAC | Adapter ClusterRole / APIService aggregation |
| Works in Prometheus, not HPA | Rule seriesQuery / metricsQuery wrong | Test PromQL; fix adapter rules |
kubectl describe hpa <name> -n <namespace>kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/<namespace>/pods/*/http_requests_per_second"For on-call commands, see EKS troubleshooting cheat sheet — HPA.