Running containers on ECS without per-service CPU, memory and network metrics means guessing during incidents. CloudWatch Container Insights collects those metrics for clusters, services and tasks and stores detailed performance records as logs you can query. For Fargate it needs no agent; for EC2-backed clusters it uses a small daemon container.
State of AWS on this date. Container Insights for ECS supports Fargate (platform version 1.4.0 and later) and EC2 launch types. It is billed as custom metrics plus the ingestion and storage of the performance log events, so it adds to the bill; the sections below show how to keep that small.
What gets collected
flowchart TB
subgraph CL[ECS cluster]
T1[Task A<br/>Fargate] --> AGT
T2[Task B<br/>Fargate] --> AGT
EC[EC2 container instance<br/>CloudWatch agent daemon] --> AGT
end
AGT[Task and instance telemetry] --> PL[Log group /aws/ecs/containerinsights/cluster/performance]
PL --> MET[Metrics in namespace ECS/ContainerInsights<br/>extracted automatically]
MET --> DB[Automatic dashboards in CloudWatch]
MET --> AL[Alarms on CPU memory restarts]
PL --> LI[Logs Insights queries<br/>per task detail]
APP[Application stdout] -->|awslogs driver| AL2[Application log group]
Container Insights and your application logs are separate: the first is infrastructure telemetry, the second is what your code prints. Keep both.
Enable it
For a new cluster:
aws ecs create-cluster --cluster-name prod --settings name=containerInsights,value=enabled
For an existing cluster:
aws ecs update-cluster-settings --cluster prod --settings name=containerInsights,value=enabled
aws ecs describe-clusters --clusters prod --include SETTINGS --query 'clusters[0].settings'
Or make it the default for every new cluster in the region:
aws ecs put-account-setting-default --name containerInsights --value enabled
On EC2 capacity, also run the CloudWatch agent as a daemon service on each container instance (AWS provides a ready-made task definition and quick-start CloudFormation template). Fargate tasks emit the data natively.
Metrics you get
Metric (namespace ECS/ContainerInsights) |
Dimension level | Use |
|---|---|---|
CpuUtilized, CpuReserved |
cluster, service, task | Compare used with reserved to right-size |
MemoryUtilized, MemoryReserved |
cluster, service, task | Memory leaks, out-of-memory risk |
NetworkRxBytes, NetworkTxBytes |
service, task | Traffic and spikes |
StorageReadBytes, StorageWriteBytes |
service, task | Disk usage patterns |
RunningTaskCount, DesiredTaskCount, PendingTaskCount |
cluster, service | Health of deployments |
ServiceCount, ContainerInstanceCount, TaskCount |
cluster | Capacity |
Calculate percentages with metric math: MemoryUtilized / MemoryReserved * 100. Fargate tasks have fixed CPU and memory sizes (for example 0.25 vCPU / 512 MB), so utilisation above 80% of reserved is a signal to move up a size or add tasks.
Alarms that matter
aws cloudwatch put-metric-alarm --alarm-name prod-api-running-low \
--namespace ECS/ContainerInsights --metric-name RunningTaskCount \
--dimensions Name=ClusterName,Value=prod Name=ServiceName,Value=api \
--statistic Minimum --period 60 --evaluation-periods 3 --threshold 2 \
--comparison-operator LessThanThreshold --treat-missing-data breaching \
--alarm-actions arn:aws:sns:ap-south-1:111111111111:ops-alerts
Also alarm on: memory above 85% of reserved for 10 minutes, DesiredTaskCount greater than RunningTaskCount for 5 minutes (a stuck deployment), and load balancer 5xx or unhealthy hosts (from the ALB metrics, not Container Insights).
Query the performance logs
In CloudWatch Logs Insights, pick /aws/ecs/containerinsights/prod/performance:
fields @timestamp, ServiceName, TaskId, CpuUtilized, MemoryUtilized
| filter Type = "Task" and ServiceName = "api"
| sort MemoryUtilized desc
| limit 20
stats avg(CpuUtilized) as cpu, max(MemoryUtilized) as mem by bin(5m), ServiceName
| filter Type = "Task"
This finds the heaviest task, restart patterns and growth over time, with per-task detail the aggregate metrics hide.
Cost controls
- Enable on production clusters; for dev, enable only while testing.
- Set retention on the performance log group (for example 14 days):
aws logs put-retention-policy --log-group-name /aws/ecs/containerinsights/prod/performance --retention-in-days 14. - Prefer few clusters with several services over many tiny clusters; metrics are per cluster, service and task.
- Review the CloudWatch line of the bill in Cost Explorer after the first week.
Troubleshooting
- No data: the setting is enabled but tasks started before enabling need restarting; Fargate platform must be 1.4.0 or later.
- Metrics for stopped tasks disappear: short-lived tasks are visible only in the performance logs.
- Dashboards empty: wrong region, or the cluster name does not match the
ClusterNamedimension. - Application logs missing: check the task definition’s
logConfiguration(awslogsdriver) and the task execution role permissions, which are independent of Container Insights.