Skip to content

Container Insights for HPA on EKS

First PublishedByAtif Alam

This guide wires Amazon CloudWatch metrics into Horizontal Pod Autoscaler (HPA) on EKS using:

  1. Amazon CloudWatch Observability EKS add-on (Container Insights metrics and agents).
  2. CloudWatch metrics adapter for Kubernetes (external.metrics.k8s.io) — the pattern AWS documents for scaling deployments with CloudWatch metrics.

Overview: Autoscaling on EKS. PromQL-based scaling: Prometheus Adapter for HPA on EKS. CloudWatch basics: AWS Monitoring.

Use this pathUse Prometheus Adapter instead
AWS-centric operations and dashboardsPortable PromQL, multi-cloud
Scale on ALB, SQS, RDS, or Container Insights namespacesRich in-cluster app metrics already in Prometheus
Standardize on CloudWatch alarms and billingAvoid CloudWatch custom metric API charges for high-cardinality apps

CloudWatch custom metrics and high-cardinality dimensions can increase cost — review AWS cost management before production.

Pods / nodes → CloudWatch agent (Observability add-on) → CloudWatch metrics
HPA ← external.metrics API ← CloudWatch metrics adapter ←──┘

metrics-server remains required if you combine CPU/memory Resource metrics with External metrics on the same HPA.

  • EKS 1.23+.
  • AWS CLI and kubectl with cluster admin.
  • IAM permissions to create IRSA roles (or use the add-on’s recommended IAM policy attachment flow).
  • Cluster name and region for metric dimensions.

Step 1: Install CloudWatch Observability add-on

Section titled “Step 1: Install CloudWatch Observability add-on”

Use the EKS console, eksctl, or AWS CLI. Example with AWS CLI (replace cluster name, region, and account):

Terminal window
aws eks create-addon \
--cluster-name my-cluster \
--addon-name amazon-cloudwatch-observability \
--resolve-conflicts OVERWRITE

Wait until the add-on is ACTIVE:

Terminal window
aws eks describe-addon \
--cluster-name my-cluster \
--addon-name amazon-cloudwatch-observability \
--query addon.status

Verify agent pods (namespaces can vary by version):

Terminal window
kubectl get pods -n amazon-cloudwatch
kubectl get pods -A | grep -i cloudwatch

Official reference: Install CloudWatch Observability on EKS.

In the CloudWatch consoleContainer Insights → your cluster, confirm node and pod metrics appear after a few minutes. Metrics commonly live under the ContainerInsights namespace.

Step 2: IAM for the CloudWatch metrics adapter

Section titled “Step 2: IAM for the CloudWatch metrics adapter”

The adapter needs cloudwatch:GetMetricData (and related read actions) on the metric namespaces you query.

Create an IAM policy (adjust ARNs and optional namespace scoping):

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudwatch:GetMetricData",
"cloudwatch:GetMetricStatistics",
"cloudwatch:ListMetrics"
],
"Resource": "*"
}
]
}

Associate the policy with an IRSA role for the adapter ServiceAccount. If your cluster already uses IRSA from Terraform: EKS cluster, follow the same OIDC provider pattern for a dedicated cloudwatch-adapter role.

Step 3: Install CloudWatch metrics adapter

Section titled “Step 3: Install CloudWatch metrics adapter”

Deploy the Kubernetes CloudWatch metrics adapter (implements External Metrics API). Options include the maintained amazon-cloudwatch-metrics / SIG adapter manifests or your platform’s packaged Helm chart — pin a version tested on your EKS version.

Typical install pattern:

Terminal window
# Example: apply upstream manifests for your release tag (verify before production)
kubectl apply -f https://raw.githubusercontent.com/awslabs/k8s-cloudwatch-adapter/master/deploy/adapter.yaml

Then patch the ServiceAccount with your IRSA annotation:

apiVersion: v1
kind: ServiceAccount
metadata:
name: cloudwatch-adapter
namespace: amazon-cloudwatch
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<account-id>:role/cloudwatch-adapter

Verify:

Terminal window
kubectl get apiservice v1beta1.external.metrics.k8s.io
kubectl get pods -n amazon-cloudwatch -l app=cloudwatch-adapter
kubectl logs -n amazon-cloudwatch -l app=cloudwatch-adapter --tail=50

Adapter configuration maps CloudWatch metric names and dimensions to Kubernetes external metrics. Example ConfigMap fragment (exact schema depends on adapter version):

apiVersion: v1
kind: ConfigMap
metadata:
name: cloudwatch-adapter-config
namespace: amazon-cloudwatch
data:
config.yaml: |
metrics:
- awsNamespace: AWS/SQS
awsMetricName: ApproximateNumberOfMessagesVisible
awsDimensions:
- QueueName
kubernetesNamespace: default
kubernetesMetricName: sqs_approximate_number_of_messages_visible

Reload or restart the adapter per your manifest docs after changing config.

List external metrics:

Terminal window
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1" | head -c 2000

Example HPA scaling a Deployment when an SQS queue depth metric is exposed (metric name must match adapter config):

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: worker-hpa
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: worker
minReplicas: 1
maxReplicas: 20
metrics:
- type: External
external:
metric:
name: sqs_approximate_number_of_messages_visible
selector:
matchLabels:
queue_name: my-queue
target:
type: AverageValue
averageValue: "30"
Terminal window
kubectl apply -f worker-hpa.yaml
kubectl describe hpa worker-hpa

For queue-driven workloads without maintaining adapter config, KEDA is often simpler — see Autoscaling on EKS — KEDA.

Some teams collect OpenTelemetry metrics with ADOT, query via AMP or in-cluster Prometheus, then use prometheus-adapter instead of CloudWatch external metrics. Use that path when PromQL is the source of truth — Prometheus Adapter for HPA on EKS.

SymptomLikely causeAction
No Container Insights dataAdd-on not ACTIVE, IAM on agentsdescribe-addon, agent pod logs
APIService external.metrics unavailableAdapter not runningPod status, RBAC, APIService registration
HPA unable to get metricsWrong metric name or labelsget --raw external API; match adapter config
AccessDenied in adapter logsIRSA policy or trustRole trust policy, eks.amazonaws.com/role-arn annotation
Metric flat / staleWrong region or dimensionsCloudWatch console vs adapter config
Terminal window
kubectl describe hpa <name> -n <namespace>
aws cloudwatch list-metrics --namespace AWS/SQS --region <region>
Container Insights + CW adapterPrometheus Adapter
Metric sourceCloudWatchPrometheus / AMP
HPA typeOften ExternalPods / Object / custom
AWS integrationNativeOptional via exporters
Ops modelCloudWatch alarms and dashboardsGrafana / AMP