CloudWatch Container Insights on EKS

Container Insights is the AWS-native way to get cluster, node, pod and container metrics from EKS into CloudWatch, with ready-made dashboards. It is the fastest route from a new cluster to usable monitoring, and it needs no metrics backend of your own.

What gets installed

The Amazon CloudWatch Observability add-on deploys:

ComponentRuns asCollects
CloudWatch agentDaemonSetNode, pod and container metrics from the kubelet and cAdvisor; control-plane and kube-state metrics
Fluent BitDaemonSetContainer, host and data-plane logs
Agent operatorDeploymentManages the agents; injects Application Signals auto-instrumentation
aws eks create-addon \
  --cluster-name my-cluster \
  --addon-name amazon-cloudwatch-observability \
  --pod-identity-associations \
    serviceAccount=cloudwatch-agent,roleArn=arn:aws:iam::111122223333:role/cloudwatch-agent

The role needs CloudWatchAgentServerPolicy (and AWSXrayWriteOnlyAccess if you use Application Signals), bound through Pod Identity.

How the data flows

The agent does not send individual metrics. It writes performance log events in embedded metric format to the log group /aws/containerinsights/<cluster>/performance, and CloudWatch extracts metrics from them into the ContainerInsights namespace. So the detailed per-container data is always queryable in Logs Insights, even for dimensions that were not turned into metrics.

Log groups created:

Log groupContents
/aws/containerinsights/<cluster>/performanceMetric events
/aws/containerinsights/<cluster>/applicationContainer stdout and stderr
/aws/containerinsights/<cluster>/hostNode system logs
/aws/containerinsights/<cluster>/dataplanekubelet, kube-proxy, runtime

Set retention on all four — the default is to keep them forever.

Enhanced observability

The current default, “Container Insights with enhanced observability”, adds container-level granularity, control-plane metrics (API server request rates and latency, etcd size), kube-state metrics (desired versus ready replicas, pod status), and curated dashboards that drill from cluster to node to pod to container.

It is priced per observation rather than per custom metric, which is usually much cheaper for the same detail and far more predictable. Optional extras include GPU and other accelerator metrics, EBS volume performance metrics and Windows node support.

Application Signals builds on the same agent: it auto-instruments Java, Python, .NET and Node.js services with OpenTelemetry and produces service maps, RED metrics and SLO tracking without code changes.

Metrics worth knowing

MetricUse
node_cpu_utilization, node_memory_utilizationNode saturation
node_filesystem_utilizationDisk pressure before the kubelet starts evicting
pod_cpu_utilization_over_pod_limitPods close to throttling
pod_memory_utilization_over_pod_limitPods close to being OOM-killed
pod_number_of_container_restartsCrash loops
cluster_failed_node_countNodes NotReady
node_number_of_running_podsApproaching maxPods
apiserver_request_total and latencyControl-plane health and noisy clients

What each underlying source means is covered in metrics sources.

Useful Logs Insights queries

Top memory consumers by pod:

fields @timestamp, PodName, Namespace, pod_memory_working_set
| filter Type = "Pod"
| stats max(pod_memory_working_set) as mem by PodName, Namespace
| sort mem desc
| limit 20

Containers that restarted:

filter Type = "Pod" and pod_number_of_container_restarts > 0
| stats max(pod_number_of_container_restarts) as restarts by PodName, Namespace
| sort restarts desc

CPU requested versus used, per namespace (for right-sizing):

filter Type = "Pod"
| stats avg(pod_cpu_request) as requested, avg(pod_cpu_usage_total) as used by Namespace

Alarms to create first

ConditionWhy
cluster_failed_node_count > 0 for 5 minutesCapacity is lost
node_filesystem_utilization > 80%Evictions are coming
pod_memory_utilization_over_pod_limit > 90% for a workloadOOM kills are likely
Container restarts rising for a DeploymentCrash loop
API server 5xx rate or latency anomalyControl plane trouble, or a misbehaving controller

Use anomaly-detection or composite alarms to avoid paging on every pod. These are infrastructure signals; alert on user-facing symptoms as well — alerting.

Container Insights or Prometheus

Container InsightsPrometheus (self-run or managed)
Set-up effortOne add-onMore: scraping, storage, dashboards
Query languageCloudWatch metrics math, Logs InsightsPromQL
Application metricsThrough EMF or the agent’s Prometheus scrapingNative
Ecosystem dashboards and alert rulesAWS-curatedVery large community catalogue
PortabilityAWS onlyAny cluster, any cloud
Cost modelPer observation and log volumePer sample ingested, or your own infrastructure

Many teams run both: Container Insights for infrastructure views and AWS-native alarms, Prometheus for application metrics and SLOs. For a vendor-neutral pipeline that can feed either, see ADOT.

Controlling cost

  • Cost follows the number of pods and containers observed and the log volume. Review the bill after a week.
  • Set log retention; send only the namespaces you need from Fluent Bit — pod logging.
  • Disable optional accelerator or EBS metrics where unused.
  • Non-production clusters may not need container-level granularity.