CloudWatch Managed Prometheus Collectors: Setup Guide for EC2 and ECS
CloudWatch Managed Prometheus Collectors: Setup Guide for EC2 and ECS
If you've been running your own OpenTelemetry Collector just to get Prometheus metrics into CloudWatch, AWS shipped the fix in late July 2026: managed Prometheus collectors. You hand CloudWatch a scrape config and a VPC connection, and it provisions, scales, and runs the scraper for you โ no EC2 instance or Fargate task babysitting a Collector binary. This walks through actually setting one up for EC2 and ECS targets, not just the announcement.
What's actually new here
AWS already had Amazon Managed Service for Prometheus (AMP) scrapers โ the aws amp create-scraper API has existed since 2023 for EKS and, later, VPC-based sources. What's new is the destination: a scraper can now write straight into a CloudWatch dataset instead of an AMP workspace. That matters in practice because you skip standing up (and paying for) a separate AMP workspace just to see Prometheus metrics โ they land in CloudWatch, queryable with PromQL right alongside your existing EC2, ECS, and RDS metrics, usable in the same dashboards and alarms.
Supported sources at launch: Amazon EKS (Kubernetes service discovery), Amazon EC2 and ECS (VPC-connected, static_configs / dns_sd_configs), and Amazon MSK and OpenSearch Service (open monitoring endpoints). This guide covers the VPC-connected path โ EC2 and ECS โ since that's where most teams currently have a hand-rolled Collector to retire.
Why this replaces a self-managed Collector
The old way: deploy an ADOT (AWS Distro for OpenTelemetry) Collector on an instance or as a sidecar, write a scrape config, manage its lifecycle, scale it as targets grow, and patch it when CVEs land. The managed collector removes all of that โ CloudWatch creates elastic network interfaces (ENIs) in your subnets, runs the scrape loop, and delivers metrics over the AWS network. You still own the scrape config; you just stop owning the process that executes it.
Prerequisites
- A VPC with DNS resolution enabled
- At least two subnets in different Availability Zones (the collector creates an ENI per AZ)
- A security group that allows the collector to reach your exporter ports (9100 for Node Exporter, whatever port your app exposes
/metricson) - Targets already exposing a Prometheus-compatible
/metricsendpoint - If your subnets are private with no NAT/internet route, an interface VPC endpoint for
com.amazonaws.{region}.monitoringโ without it the collector can scrape but can't deliver metrics to CloudWatch
Step 1: Write a scrape config for EC2
For EC2 instances running Node Exporter, use static_configs with private IPs. Relabeling tags each series so you can tell EC2-sourced metrics apart from everything else once they're mixed into CloudWatch:
1global:
2 scrape_interval: 60s
3
4scrape_configs:
5 - job_name: 'ec2-node-exporter'
6 static_configs:
7 - targets:
8 - '10.0.1.10:9100'
9 - '10.0.1.11:9100'
10 relabel_configs:
11 - source_labels: [__address__]
12 target_label: instance
13 - target_label: compute_platform
14 replacement: 'ec2'
Save this as scrape-config.yaml.
Step 2: Create the scraper via CLI
1aws amp create-scraper \
2 --alias "ec2-metrics-scraper" \
3 --source '{
4 "vpcConfiguration": {
5 "subnetIds": ["subnet-0abc123", "subnet-0def456"],
6 "securityGroupIds": ["sg-0123456789abcdef0"]
7 }
8 }' \
9 --scrape-configuration configurationBlob=$(cat scrape-config.yaml | base64 -w 0) \
10 --destination '{
11 "cloudWatchConfiguration": {
12 "datasetArn": "arn:aws:cloudwatch:us-west-2:123456789012:dataset/default"
13 }
14 }'
The scraper still lives under the amp CLI namespace (it's the same underlying scraper service AMP has used since 2023) โ the only thing that changed is pointing destination at a cloudWatchConfiguration dataset ARN instead of an AMP workspace ARN.
Step 3: ECS โ use Cloud Map service discovery instead
ECS task IPs churn on every deployment and every scaling event, so static targets don't work. Register your services with AWS Cloud Map and use dns_sd_configs โ the scraper queries the Cloud Map DNS records on every scrape interval and picks up new/removed tasks automatically:
1global:
2 scrape_interval: 60s
3
4scrape_configs:
5 - job_name: 'ecs-services'
6 dns_sd_configs:
7 - names:
8 - 'my-service.my-namespace.local'
9 type: A
10 port: 9090
11 relabel_configs:
12 - source_labels: [__meta_dns_name]
13 target_label: service_name
14 - source_labels: [__address__]
15 target_label: instance
16 - target_label: compute_platform
17 replacement: 'ecs'
Same create-scraper call as above, just with this config and a dataset destination scoped to your ECS collector's own alias โ don't reuse the EC2 scraper's alias for a second create-scraper call, or you'll overwrite it.
Querying what you just collected
Once metrics land in CloudWatch, they're queryable with PromQL, mixed with your native AWS metrics:
1100 - (avg by (instance, job) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
That's CPU utilization computed from raw Node Exporter counters โ something you'd otherwise need CloudWatch agent's own metric set for, now derived directly from the same Prometheus data your app teams already instrument with.
Best practices
- Deploy in private subnets and rely on the VPC endpoint for delivery โ don't put the collector's ENIs in a public subnet just because it's simpler to set up.
- Restrict security group ingress to only the scraper's security group, on only the exporter ports you actually use. A wide-open 9100 rule defeats the point of running this inside a VPC.
- Set scrape intervals by workload, not by default. AWS's own guidance: halving your scrape interval doubles ingestion cost. 30s is reasonable for application metrics you alert on; 60s+ is fine for infrastructure metrics; stretch non-prod environments to 90s or more.
- Drop noisy series before they hit CloudWatch, using
metric_relabel_configswith adropaction on high-cardinality or unused metric names โ you're billed on ingestion, so filtering at the scrape config is cheaper than filtering after the fact.
Common mistakes to avoid
- Forgetting the VPC endpoint in private subnets. The collector will scrape targets successfully and still silently fail to deliver metrics if there's no route to the CloudWatch API โ this shows up as "the scraper exists but I see no data," not an obvious error.
- Reusing an AMP workspace scrape config as-is. The scrape config format is identical, but if you're migrating an existing AMP setup, you still need a new
create-scrapercall with acloudWatchConfigurationdestination โ updating an existing scraper's destination isn't supported. - Using
static_configsfor ECS. Task IPs change on every deploy; a static target list goes stale within a day. Use Cloud Map anddns_sd_configsfor anything running on ECS. - Skipping relabeling. Without
compute_platformor similar tags, EC2 and ECS metrics land in CloudWatch with identical metric names and no way to filter one source from another in a shared dashboard.
Troubleshooting
If a scraper shows as active but no metrics appear in CloudWatch:
- Confirm the security group actually allows the collector to reach the exporter port โ check inbound rules on the target's security group, not just the collector's.
- If subnets are private, confirm the interface VPC endpoint for
com.amazonaws.{region}.monitoringexists and its security group allows inbound HTTPS from the collector's security group. - Check that the target's
/metricsendpoint actually returns Prometheus exposition format โ curl it directly from an instance in the same VPC. - For ECS, confirm the Cloud Map service actually has healthy task registrations โ
dns_sd_configsreturns nothing if Cloud Map's DNS records are empty.
FAQ
Does this replace Amazon Managed Service for Prometheus? No โ it's a new destination for the same underlying scraper. If you want long-term Prometheus-native storage, alerting via Alertmanager, or a Grafana-first workflow, AMP workspaces still make sense. If you just want Prometheus metrics inside CloudWatch alongside everything else, the managed collector with a CloudWatch destination is now the simpler path.
Do I need to run anything on my EC2 instances or ECS tasks besides the exporter?
No. Node Exporter (or your app's own /metrics endpoint) is all you need on the target side โ the collector itself runs entirely on AWS-managed infrastructure outside your instances or tasks.
What's the pricing model? Collectors are billed hourly, plus standard CloudWatch OpenTelemetry metric ingestion pricing on top. There's no separate line item for the scrape compute itself beyond the hourly collector charge.
Which regions support this? All AWS Regions where the CloudWatch OTLP endpoint is available, except Asia Pacific (New Zealand), as of the July 2026 launch.
Can one scraper cover both EC2 and ECS targets?
Yes, technically โ a single scrape config can have multiple scrape_configs job entries mixing static_configs and dns_sd_configs. In practice, splitting them into separate scrapers per source type makes relabeling, troubleshooting, and cost attribution simpler.
Key takeaways
| Before | Now |
|---|---|
| Self-managed ADOT Collector on EC2/Fargate | Fully managed collector, no compute to own |
| Separate AMP workspace required for Prometheus data | Optional โ CloudWatch dataset destination works standalone |
| Manual scaling as targets grow | CloudWatch provisions and scales automatically |
| Prometheus metrics siloed from AWS-native metrics | PromQL queries run alongside CloudWatch's own metrics |
Further Reading
- CloudWatch Embraces OpenTelemetry: Simplified Metrics in AWS (Finally!)
- AWS CloudWatch Gets Smarter: Organization-Wide EC2 Metrics & What It Means for Your Cloud in 2026
- AWS OpenSearch Gains Prometheus Agent & Tracing: Goodbye Monitoring Headaches?
- AWS: Amazon CloudWatch announces managed Prometheus collectors
- AWS docs: VPC-connected managed collector