운영 중인 EC2가 갑자기 느려져서 CloudWatch 콘솔을 열었는데, CPU 그래프만 있고 메모리와 디스크 사용률 그래프가 아예 없어서 당황한 적이 있을 것이다. 저도 처음 AWS로 넘어왔을 때 온프레미스 모니터링 습관대로 메모리 그래프를 찾다가 한참 헤맸다. 이건 설정을 빼먹은 게 아니라 원래 그렇게 동작한다. 이번 글에서는 왜 안 보이는지, 그리고 어떻게 하면 보이게 만드는지를 순서대로 정리한다.
결론부터 말하면, 메모리와 디스크 사용률은 EC2 기본 메트릭에 포함되지 않는다. 이 값들은 인스턴스 운영체제 안에서만 알 수 있어서, EC2에 CloudWatch Agent를 설치해 mem_used_percent와 disk_used_percent를 커스텀 메트릭으로 직접 수집해야 한다. 에이전트 설치와 설정 배포는 SSM Run Command로 하고, 값이 올라오면 put-metric-alarm으로 경보를 건다.
왜 메모리와 디스크 사용률은 기본으로 안 보이나
CloudWatch가 EC2에서 기본 제공하는 메트릭은 하이퍼바이저 바깥, 즉 AWS 인프라 쪽에서 관측 가능한 값들이다. CPUUtilization, NetworkIn, NetworkOut, 그리고 EBS 볼륨의 디스크 읽기와 쓰기 바이트 같은 것들이 여기에 해당한다.
반면 메모리 사용률과 파일시스템 사용률은 게스트 운영체제 안에서만 계산할 수 있는 값이다. 물리 메모리가 몇 퍼센트 찼는지, 루트 파티션이 몇 퍼센트 남았는지는 인스턴스 내부에서 프로세스가 직접 읽어야 알 수 있다. AWS가 인스턴스 밖에서는 들여다볼 수 없는 영역이라 기본 메트릭에 없는 것이다.
그래서 여기 값을 채우려면 인스턴스 안에 에이전트를 하나 심어야 한다. 그 역할을 하는 게 CloudWatch Agent다.
CloudWatch Agent와 커스텀 메트릭이란
CloudWatch Agent는 EC2나 온프레미스 서버 안에서 돌면서 운영체제 수준의 메트릭과 로그를 수집해 CloudWatch로 보내주는 공식 에이전트다. 설정 파일에 어떤 값을 얼마 간격으로 보낼지 적어두면, 그 값을 사용자 정의 네임스페이스에 커스텀 메트릭으로 올려준다.
커스텀 메트릭은 AWS가 기본으로 주는 메트릭이 아니라 사용자가 직접 정의해서 올리는 메트릭을 말한다. 메모리 사용률(mem_used_percent)과 디스크 사용률(disk_used_percent)이 대표적인 예다. 커스텀 메트릭은 개수와 API 호출량에 따라 요금이 붙으니, 필요한 값만 골라 수집하는 게 좋다.
이제 IAM 역할 준비, 에이전트 설치, 설정 배포, 확인, 경보 순으로 살펴본다.
1. 사전 준비: IAM 역할
SSM으로 에이전트를 다루고 메트릭을 올리려면 인스턴스에 두 개의 관리형 정책이 붙은 역할이 필요하다.
AmazonSSMManagedInstanceCore: 인스턴스를 SSM 관리형으로 만들어 Run Command를 받게 한다.CloudWatchAgentServerPolicy: 에이전트가 메트릭과 로그를 CloudWatch로 쓰게 하고, 설정을 SSM 파라미터 스토어에서 읽게 한다.
인스턴스에 붙은 역할과 정책은 이렇게 확인한다.
$ aws ec2 describe-instances \
--instance-ids i-0123456789abcdef0 \
--query 'Reservations[].Instances[].IamInstanceProfile.Arn'
[
"arn:aws:iam::123456789012:instance-profile/sarc-web-role"
]
역할이 비어 있으면 인스턴스가 SSM 콘솔의 대상 목록에 아예 안 뜬다. 처음엔 이 부분에서 자주 막힌다. 여기서 걸렸다면 역할부터 붙이고, SSM Agent가 새 권한을 인식하도록 sudo systemctl restart amazon-ssm-agent로 한 번 재시작한다.
2. SSM Run Command로 에이전트 설치
에이전트 설치는 SSM의 AWS-ConfigureAWSPackage 문서로 한다. 패키지 이름은 AmazonCloudWatchAgent, 버전은 latest로 둔다. 콘솔에서도 되지만, CLI로 하면 이렇게 한 줄이다.
$ aws ssm send-command \
--document-name "AWS-ConfigureAWSPackage" \
--targets "Key=instanceids,Values=i-0123456789abcdef0" \
--parameters '{"action":["Install"],"name":["AmazonCloudWatchAgent"],"version":["latest"]}'
{
"Command": {
"CommandId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
"DocumentName": "AWS-ConfigureAWSPackage",
"Status": "Pending"
}
}
실행 결과는 CommandId로 조회한다.
$ aws ssm list-command-invocations \
--command-id a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 \
--details --query 'CommandInvocations[].Status'
[
"Success"
]
참고로 Amazon Linux 2와 Amazon Linux 2023에는 에이전트가 패키지로 들어 있어서 sudo yum install amazon-cloudwatch-agent로도 설치된다. 여러 인스턴스에 한 번에 깔 거라면 SSM 쪽이 편하다.
3. 설정 파일 작성과 파라미터 스토어 저장
에이전트는 설정 파일이 있어야 무엇을 수집할지 안다. 메모리 사용률과 루트 파티션 디스크 사용률만 60초 간격으로 보내는 최소 설정은 다음과 같다. 공식 문서의 기본 시스템 메트릭 예제를 그대로 따른 형태다.
{
"agent": {
"metrics_collection_interval": 60
},
"metrics": {
"namespace": "CWAgent",
"metrics_collected": {
"mem": {
"measurement": ["used_percent"]
},
"disk": {
"resources": ["/"],
"measurement": ["used_percent"]
}
},
"append_dimensions": {
"InstanceId": "${aws:InstanceId}"
}
}
}
몇 가지 짚어둘 점이 있다. measurement에는 used_percent라고 적지만, CloudWatch에 올라올 때 에이전트가 섹션 이름을 접두어로 붙여 메트릭 이름이 mem_used_percent, disk_used_percent가 된다. namespace를 적지 않으면 기본값이 CWAgent이고, 여기서는 명시했다.
append_dimensions의 ${aws:InstanceId}는 모든 메트릭에 인스턴스 ID 차원을 붙여준다. 이 값이 있어야 나중에 경보에서 특정 인스턴스를 지목할 수 있다.
이 파일을 SSM 파라미터 스토어에 올려두면 여러 인스턴스가 같은 설정을 내려받을 수 있다. 위 JSON을 amazon-cloudwatch-agent.json으로 저장한 뒤 파라미터로 넣는다.
$ aws ssm put-parameter \
--name "AmazonCloudWatch-linux" \
--type String \
--value file://amazon-cloudwatch-agent.json
{
"Version": 1,
"Tier": "Standard"
}
참고로 EC2 안에서 대화형으로 만들고 싶다면 sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-config-wizard를 실행해 질문에 답하면 설정 파일을 만들어준다. 처음 한 번 감을 잡을 때 쓸 만하다.
4. SSM으로 설정 적용하고 에이전트 시작
설치와 설정 배포는 다른 문서를 쓴다. 설정 적용은 AmazonCloudWatch-ManageAgent 문서로 하고, 설정 소스를 ssm, 위치를 앞서 만든 파라미터 이름으로 지정한다.
$ aws ssm send-command \
--document-name "AmazonCloudWatch-ManageAgent" \
--targets "Key=instanceids,Values=i-0123456789abcdef0" \
--parameters '{"action":["configure"],"mode":["ec2"],"optionalConfigurationSource":["ssm"],"optionalConfigurationLocation":["AmazonCloudWatch-linux"],"optionalRestart":["yes"]}'
optionalRestart를 yes로 주면 설정을 받은 뒤 에이전트를 바로 시작한다. 인스턴스 안에서 직접 상태를 확인하려면 에이전트 제어 명령을 쓴다.
$ sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a status
{
"status": "running",
"starttime": "2026-08-05T04:12:30+00:00",
"configstatus": "configured",
"version": "1.300000.0"
}
버전 번호는 설치 시점에 따라 다를 수 있다. status가 running, configstatus가 configured면 정상이다.
5. 메트릭이 올라오는지 확인
에이전트를 시작하고 1분에서 2분쯤 지나면 CWAgent 네임스페이스에 메트릭이 잡히기 시작한다. 먼저 메트릭이 등록됐는지 목록으로 본다.
$ aws cloudwatch list-metrics \
--namespace CWAgent \
--metric-name mem_used_percent
{
"Metrics": [
{
"Namespace": "CWAgent",
"MetricName": "mem_used_percent",
"Dimensions": [
{"Name": "InstanceId", "Value": "i-0123456789abcdef0"}
]
}
]
}
여기서 disk_used_percent도 같이 조회해 보면, 차원이 하나 더 붙어 있는 걸 볼 수 있다. 이게 다음 단계의 함정과 직결된다.
$ aws cloudwatch list-metrics \
--namespace CWAgent \
--metric-name disk_used_percent
{
"Metrics": [
{
"Namespace": "CWAgent",
"MetricName": "disk_used_percent",
"Dimensions": [
{"Name": "InstanceId", "Value": "i-0123456789abcdef0"},
{"Name": "path", "Value": "/"},
{"Name": "device", "Value": "nvme0n1p1"},
{"Name": "fstype", "Value": "xfs"}
]
}
]
}
메모리 메트릭은 InstanceId 하나지만, 디스크 메트릭에는 InstanceId, path, device, fstype가 함께 붙는다. 값이 어떻게 찍히는지 보려면 get-metric-statistics로 최근 몇 분치를 뽑아본다.
$ aws cloudwatch get-metric-statistics \
--namespace CWAgent \
--metric-name mem_used_percent \
--dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
--start-time 2026-08-05T04:00:00Z \
--end-time 2026-08-05T04:10:00Z \
--period 60 --statistics Average
6. 경보(Alarm) 걸기
값이 올라오면 임계치를 넘을 때 알림을 받도록 경보를 건다. 메모리 사용률이 5분 평균으로 두 번 연속 85%를 넘으면 SNS 주제로 알리는 예다.
$ aws cloudwatch put-metric-alarm \
--alarm-name "sarc-web-mem-high" \
--namespace CWAgent \
--metric-name mem_used_percent \
--dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
--statistic Average --period 300 --evaluation-periods 2 \
--threshold 85 --comparison-operator GreaterThanThreshold \
--alarm-actions arn:aws:sns:ap-northeast-2:123456789012:sarc-ops-alert \
--treat-missing-data missing
디스크 경보에서 실수가 잦다. 앞에서 봤듯이 disk_used_percent에는 차원이 네 개 붙어 있는데, 경보의 --dimensions에 그 네 개를 정확히 다 맞춰야 한다. InstanceId만 적으면 일치하는 메트릭이 없어서 경보가 데이터를 못 받고 INSUFFICIENT_DATA에서 안 벗어난다.
$ aws cloudwatch put-metric-alarm \
--alarm-name "sarc-web-disk-root-high" \
--namespace CWAgent \
--metric-name disk_used_percent \
--dimensions Name=InstanceId,Value=i-0123456789abcdef0 \
Name=path,Value=/ \
Name=device,Value=nvme0n1p1 \
Name=fstype,Value=xfs \
--statistic Average --period 300 --evaluation-periods 1 \
--threshold 80 --comparison-operator GreaterThanThreshold \
--alarm-actions arn:aws:sns:ap-northeast-2:123456789012:sarc-ops-alert
device와 fstype 값은 인스턴스마다 다르다. 앞의 list-metrics 출력에 나온 실제 값을 그대로 넣어야 한다. 경보 상태는 이렇게 확인한다.
$ aws cloudwatch describe-alarms \
--alarm-names sarc-web-disk-root-high \
--query 'MetricAlarms[].StateValue'
[
"OK"
]
자주 걸리는 함정
인스턴스가 SSM 대상에 안 뜬다. IAM 역할에 AmazonSSMManagedInstanceCore가 없거나, SSM Agent 버전이 오래됐을 때다. 에이전트는 2.2.93.0 이상이어야 한다. 역할을 붙였다면 SSM Agent를 재시작해 권한을 다시 읽게 한다.
메트릭이 안 올라온다. 대개 IAM 역할에 CloudWatchAgentServerPolicy가 빠졌거나, 설정 파일 JSON에 문법 오류가 있을 때다. 인스턴스 안에서 /opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log를 열어보면 권한 거부나 파싱 오류가 그대로 찍혀 있다.
디스크 경보가 INSUFFICIENT_DATA에서 안 나온다. 위에서 설명한 차원 불일치가 원인인 경우가 많다. path, device, fstype까지 실제 값으로 채웠는지 다시 본다.
커스텀 메트릭 요금. 수집 간격을 너무 짧게 잡거나 마운트를 전부 수집하면 메트릭 개수가 늘어 요금이 오른다. 필요한 파티션만 resources에 지정하고, 60초 간격이면 충분한 경우가 많다.
정리
EC2의 메모리와 디스크 사용률은 게스트 운영체제 안에서만 알 수 있는 값이라 기본 메트릭에 없다. CloudWatch Agent를 설치해 mem_used_percent와 disk_used_percent를 커스텀 메트릭으로 수집하면 채워진다. 설치는 AWS-ConfigureAWSPackage, 설정 배포는 AmazonCloudWatch-ManageAgent 문서로 SSM에서 처리하고, 설정 파일은 파라미터 스토어에 두면 여러 인스턴스가 공유한다. 마지막으로 put-metric-alarm으로 경보를 걸되, 디스크는 차원이 네 개라는 점만 놓치지 않으면 된다.