Why CloudWatch Doesn't Show EC2 Memory Usage (And How to Fix It)
You've launched an EC2 instance, opened the CloudWatch console, and found CPU, network, and disk I/O metrics — but no RAM usage. This isn't a bug or an oversight; it's a deliberate architectural boundary that every AWS engineer must understand.
TL;DR
| Aspect | Default CloudWatch Metrics | CloudWatch Agent Metrics |
|---|---|---|
| Source | AWS Hypervisor layer | Guest OS (inside the instance) |
| Memory (RAM) | ❌ Not available | ✅ mem_used_percent, mem_available |
| Disk Space | ❌ Not available | ✅ disk_used_percent per mount point |
| CPU Usage | ✅ CPUUtilization (hypervisor view) | ✅ cpu_usage_user, cpu_usage_system |
| Installation Required | None — automatic | CloudWatch Agent on the instance |
| IAM Permissions | None — AWS-managed | CloudWatchAgentServerPolicy on instance role |
| Cost | Included in EC2 | Custom metrics pricing applies |
The Architectural Boundary: Why the Gap Exists
AWS EC2 runs on a virtualization layer called the Nitro Hypervisor (or Xen for older instance types). CloudWatch's default metrics are emitted by this hypervisor — the host-level infrastructure AWS controls. The hypervisor can observe how much CPU time it allocates to your VM, how many bytes traverse the virtual network interface, and how many I/O operations hit the virtual disk. What it cannot see is what happens inside the guest OS — how the Linux kernel distributes RAM across processes, or how full your /var partition is.
Analogy: Think of AWS as a landlord who owns the building. The landlord can measure how much electricity the apartment consumes (hypervisor metrics) but cannot see how many lights you've left on in each room (OS-level memory/disk). To get that detail, you need a sensor inside the apartment — that sensor is the CloudWatch Agent.
This is the core principle: the hypervisor boundary is the visibility boundary. Anything below it (infrastructure) AWS can measure automatically. Anything above it (OS internals) requires an agent running with OS-level access.
Data Flow: Default vs. Agent-Collected Metrics
df, iostat"] AGENT["CloudWatch Agent
(Daemon)"] OS --> PROC PROC --> AGENT end subgraph CloudWatch ["Amazon CloudWatch"] NS1["Namespace: AWS/EC2
(CPUUtilization, NetworkIn)"] NS2["Namespace: CWAgent
(mem_used_percent, disk_used_percent)"] end HV -- "Hypervisor-level metrics
(automatic, free)" --> NS1 AGENT -- "OS-level metrics
(custom, billed)" --> NS2 HV -. "Cannot see inside
guest OS" .-> OS style AWS_Infrastructure fill:#1a1a2e,stroke:#4a90d9,color:#fff style EC2_Instance fill:#16213e,stroke:#4a90d9,color:#fff style CloudWatch fill:#0f3460,stroke:#4a90d9,color:#fff
- Nitro Hypervisor continuously monitors the virtual machine's resource consumption from the host perspective and pushes metrics like
CPUUtilizationandNetworkIndirectly to CloudWatch — no configuration needed. - Guest OS (your Linux/Windows instance) holds the ground truth for memory and disk. This data lives in kernel space (
/proc/meminfo,dfoutput) and is inaccessible to the hypervisor. - CloudWatch Agent runs as a daemon inside the guest OS, reads OS-level metrics at a configurable interval, and publishes them to CloudWatch under the
CWAgentnamespace as custom metrics. - CloudWatch stores both streams — default hypervisor metrics and agent-pushed custom metrics — allowing unified dashboards and alarms.
Implementation: Installing and Configuring the CloudWatch Agent
Step 1: Attach the Required IAM Policy
The instance needs permission to write metrics to CloudWatch. Attach the AWS-managed policy CloudWatchAgentServerPolicy to the EC2 instance's IAM role. This follows least-privilege — it grants only cloudwatch:PutMetricData, ec2:DescribeTags, and SSM read access needed by the agent.
# Attach via CLI (replace ROLE_NAME with your instance role)
aws iam attach-role-policy \
--role-name ROLE_NAME \
--policy-arn arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
Step 2: Install the CloudWatch Agent
# Amazon Linux 2 / Amazon Linux 2023
sudo yum install -y amazon-cloudwatch-agent
# Ubuntu / Debian
wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
sudo dpkg -i amazon-cloudwatch-agent.deb
Step 3: Create the Agent Configuration
The agent is configured via a JSON file. The wizard (amazon-cloudwatch-agent-config-wizard) can generate this interactively, or you can write it directly. Below is a production-ready configuration capturing memory and disk metrics:
🔽 [Click to expand] — /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json
{
"agent": {
"metrics_collection_interval": 60,
"run_as_user": "cwagent"
},
"metrics": {
"append_dimensions": {
"AutoScalingGroupName": "${aws:AutoScalingGroupName}",
"ImageId": "${aws:ImageId}",
"InstanceId": "${aws:InstanceId}",
"InstanceType": "${aws:InstanceType}"
},
"metrics_collected": {
"mem": {
"measurement": [
"mem_used_percent",
"mem_available_percent",
"mem_used",
"mem_total"
],
"metrics_collection_interval": 60
},
"disk": {
"measurement": [
"disk_used_percent",
"disk_free",
"disk_used"
],
"metrics_collection_interval": 60,
"resources": [
"/",
"/var",
"/tmp"
]
},
"swap": {
"measurement": [
"swap_used_percent"
]
}
}
}
}
Step 4: Start the Agent
# Load config and start the agent
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
-a fetch-config \
-m ec2 \
-c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json \
-s
# Verify the agent is running
sudo systemctl status amazon-cloudwatch-agent
Step 5: Verify Metrics in CloudWatch
After 1–2 minutes, navigate to CloudWatch → Metrics → CWAgent. You will see metrics dimensioned by InstanceId and (for disk) by path. Create an alarm on mem_used_percent exceeding 85% as a baseline production alert.
Metric Namespace Architecture
dim: path=/"] M7["swap_used_percent"] end DASH["CloudWatch Dashboard
(Unified View)"] ALARM["CloudWatch Alarms"] end NS1 --> DASH NS2 --> DASH NS2 --> ALARM NS1 --> ALARM style NS1 fill:#1a3a1a,stroke:#4caf50,color:#fff style NS2 fill:#3a1a1a,stroke:#f44336,color:#fff style DASH fill:#1a2a3a,stroke:#4a90d9,color:#fff style ALARM fill:#2a1a3a,stroke:#9c27b0,color:#fff
- AWS/EC2 namespace contains all hypervisor-emitted metrics. These are free, automatic, and require no agent.
- CWAgent namespace is where the CloudWatch Agent publishes OS-level metrics. This is a custom metrics namespace and is billed per metric per month.
- Dimensions on agent metrics include
InstanceId,InstanceType, and for disk metrics, thepath(mount point) — enabling per-partition alerting. - Both namespaces can be combined in a single CloudWatch Dashboard for a unified operational view.
Setting a Memory Alarm (CLI)
aws cloudwatch put-metric-alarm \
--alarm-name "EC2-HighMemoryUsage" \
--alarm-description "Triggers when memory usage exceeds 85%" \
--metric-name mem_used_percent \
--namespace CWAgent \
--statistic Average \
--period 300 \
--threshold 85 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 2 \
--dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
--alarm-actions arn:aws:sns:us-east-1:123456789012:ops-alerts
Glossary
| Term | Definition |
|---|---|
| Nitro Hypervisor | AWS's lightweight hypervisor that underpins modern EC2 instances, responsible for virtualizing CPU, memory, and I/O at the host level. |
| Guest OS | The operating system running inside the EC2 virtual machine — Linux or Windows — which has full visibility into its own memory and filesystem state. |
| CloudWatch Namespace | A logical container for CloudWatch metrics (e.g., AWS/EC2, CWAgent) that prevents naming collisions between different services or agents. |
| Custom Metrics | Metrics published to CloudWatch by user-controlled processes (like the CloudWatch Agent), as opposed to metrics emitted automatically by AWS services. |
| CloudWatchAgentServerPolicy | AWS-managed IAM policy granting an EC2 instance the minimum permissions required to publish metrics and retrieve configuration via the CloudWatch Agent. |
Next Steps
For fleet-scale deployments, use AWS Systems Manager (SSM) Distributor to install and configure the CloudWatch Agent across hundreds of instances without SSH access. Store your agent configuration in SSM Parameter Store under AmazonCloudWatch-linux and reference it with -c ssm:parameter-name for centralized config management. Official reference: AWS CloudWatch Agent Documentation.
Comments
Post a Comment