본문 바로가기

개인공부

[AWS] 9. CloudWatch · CloudTrail로 모니터링하기

리소스가 떠 있으면 그 상태를 들여다보는 눈이 필요하다.

CloudWatch는 "지금 무슨 일이 일어나는가", CloudTrail은 "누가 무엇을 했는가"를 본다.

이번엔 둘의 역할을 정리하고, CloudWatch 알람 → SNS 알림까지 직접 연결해본다.


1. CloudWatch — 상태 모니터링

Amazon CloudWatch는 AWS 리소스와 애플리케이션을 실시간으로 모니터링하는 서비스다. 핵심 구성요소는 셋이다.

  • 지표(Metric): 시간 단위로 수집되는 수치형 값. CPU 사용률(%), 메모리 사용량(MB), 디스크 I/O, 네트워크 트래픽 등
  • 로그(Logs): EC2, Lambda, API Gateway 등에서 발생한 이벤트 기록. Logs Insights로 SQL처럼 쿼리해서 분석
  • 알람(Alarm): 지표가 임계값을 넘으면 자동으로 경고 또는 작업 실행

지표의 구성요소

지표는 단순한 숫자가 아니라 네임스페이스·차원으로 분류된다.

속성 설명
Namespace 지표의 소속 (예: AWS/EC2, AWS/DynamoDB)
Dimension 리소스 식별자 (예: InstanceId, TableName)
Statistic 집계 방식 — Average, Sum, Maximum 등
Period 수집 주기. 기본 5분, 상세 모니터링 활성화 시 1분

여기서 알아둘 점: EC2는 기본 5분 단위 수집이다. 1분 단위가 필요하면 "상세 모니터링(Detailed Monitoring)"을 켜야 하고, 이건 추가 과금 대상이다. Lambda는 로그가 CloudWatch Logs로 자동 전송된다.

알람의 동작

알람은 지표 + 조건으로 정의되고, 임계값을 넘으면 액션이 실행된다.

  • 조건 예시: EC2 CPUUtilization > 80%
  • 액션 예시: SNS 발송, Auto Scaling, EC2 재시작
  • 알람 상태: OK / INSUFFICIENT_DATA / ALARM

INSUFFICIENT_DATA는 데이터가 아직 안 들어온 초기 상태인데, 알람을 막 만들었을 때 이 상태로 한참 떠 있어서 "잘못 만들었나" 착각하기 쉽다.


2. CloudTrail — 행위 추적

AWS CloudTrail은 계정 내에서 발생한 모든 API 호출을 기록하는 서비스다. 콘솔 클릭이든, CLI든, SDK든, 서비스 간 내부 호출이든 전부 누가 / 언제 / 어디서 / 무엇을 했는지 남긴다.

이벤트 3종류

유형 설명 예시 과금
관리 이벤트 (Management) 리소스 생성/삭제/권한 변경 RunInstances, CreateUser 기본 활성화 (무료)
데이터 이벤트 (Data) 리소스 내부 데이터 접근 GetObject(S3), Invoke(Lambda) 명시적 설정 + 추가 과금
인사이트 이벤트 (Insights) 비정상 행동 탐지 이상 호출 급증, 반복 실패 명시적 설정 + 추가 과금

데이터 이벤트가 기본 비활성인 이유는 명확하다. S3 GetObject 같은 건 초당 수천 번도 발생하니 전부 기록하면 로그량과 비용이 폭발한다. 필요한 버킷에만 켜는 구조다.

Event History vs Trail

  • Event History: 콘솔에서 바로 보는 최근 90일 관리 이벤트. 별도 설정 없이 조회 가능
  • Trail: 로그를 S3에 장기 저장. CloudWatch Logs / SNS / EventBridge 연동 가능

90일이 넘는 감사 추적이나 규정 준수(PCI-DSS, HIPAA, ISO)가 필요하면 반드시 Trail을 만들어 S3에 떨궈야 한다. Event History만 믿으면 90일 지난 기록은 사라진다.

로그 한 건 뜯어보기

EC2 인스턴스 종료(TerminateInstances) 이벤트는 이렇게 생겼다.

{
  "eventVersion": "1.08",
  "userIdentity": {
    "type": "IAMUser",
    "arn": "arn:aws:iam::123456789012:user/admin-user",
    "userName": "admin-user"
  },
  "eventTime": "2025-07-26T14:20:00Z",
  "eventSource": "ec2.amazonaws.com",
  "eventName": "TerminateInstances",
  "awsRegion": "ap-northeast-2",
  "sourceIPAddress": "203.0.113.10",
  "userAgent": "aws-cli/2.12.0",
  "requestParameters": {
    "instancesSet": {
      "items": [{ "instanceId": "i-0abc123def4567890" }]
    }
  }
}

읽는 포인트는 userName(누가), eventTime(언제), sourceIPAddress(어디서), userAgent(어떤 도구로), requestParameters(무엇에). 이 다섯 개만 보면 "admin-user가 CLI로 특정 인스턴스를 종료시켰다"가 한 줄로 복원된다.

저장된 로그는 Athena(SQL 쿼리), CloudWatch Logs Insights, S3(장기 보관)로 분석한다.

💡 CloudWatch vs CloudTrail, 헷갈리는 지점

  • 처음엔 둘 다 "로그 보는 거 아닌가" 싶었는데, CloudTrail은 행위(API 호출), CloudWatch는 상태(지표·로그)로 축이 완전히 다르다. "EC2가 종료됐다"는 사실은 CloudWatch 지표에서 인스턴스가 사라진 걸로, "누가 종료했나"는 CloudTrail에서 본다.
  • 비유로 정리하니 명확해졌다. CloudTrail = CCTV(누가 언제 무슨 행동을 했는지 기록), CloudWatch = 센서 + 알람(상태를 감지하고 경고).
  • 연계 서비스도 갈린다. CloudTrail은 Athena·S3·EventBridge(감사/분석 쪽), CloudWatch는 SNS·Lambda·Alarm(운영/대응 쪽)으로 붙는다.
  • 실무에선 둘을 같이 쓴다. CloudTrail에서 특정 API 호출(예: 보안그룹 변경)을 EventBridge로 잡아 → CloudWatch/SNS로 알림 보내는 식으로 엮으면, "수상한 행위 발생 즉시 통보"가 된다.
항목 CloudTrail CloudWatch
목적 행위 추적 (무엇을 했는가) 상태 모니터링 (무엇이 일어났는가)
데이터 API 호출 로그 지표(Metrics), 로그(Logs)
예시 EC2 생성, IAM 권한 변경 EC2 CPU 사용률, 로그 이벤트
주 사용처 보안, 감사, 규정 준수 운영, 모니터링, 자동 대응

3. SNS / SQS — 알림의 전달 계층

알람이 울렸을 때 그걸 사람한테 보내는 게 SNS다.

SNS (Simple Notification Service)

Publisher가 SNS Topic에 메시지를 던지면, Topic을 구독한 모든 엔드포인트(Email, SMS, Mobile Push, HTTP(S))로 푸시된다. 일대다 발송이고, 구독자가 여럿이면 동시에 다 받는다.

SQS (Simple Queue Service)

완전 관리형 메시지 큐. SNS와 자주 비교된다.

  SNS SQS
메시지 지속성 X O (큐에 쌓임)
전송 방식 Push (구독자에게 밀어줌) Polling (소비자가 가져감)
모델 게시/구독 (1:N) 생산자/소비자 (1:1)

핵심 차이는 지속성과 방향이다. SNS는 던지고 끝(받는 쪽이 없으면 유실), SQS는 큐에 남아 있어서 소비자가 나중에 처리한다. 그래서 트래픽 폭증·장애 흡수가 필요하면 SNS → SQS를 앞에 두는 fan-out 패턴을 쓴다. (SNS Topic이 여러 SQS 큐로 뿌리고, 각 큐 뒤의 워커가 독립적으로 소비)


4. 콘솔 데모 — CloudWatch 알람 + SNS 연동

목표: DynamoDB board 테이블에 쓰기가 발생하면 이메일 알림을 받는다.
흐름: SNS Topic 생성 → 모니터링 대상(DynamoDB) 생성 → 알람 생성 → 테스트

4-1. SNS Topic 생성 + 구독

  1. SNS 콘솔 접속 → Create topic
  2. Topic 이름: mytopic (타입은 Standard)
  3. 생성한 Topic에서 Create subscription → Protocol Email, Endpoint 본인 이메일 입력

📸 [스크린샷: SNS Topic mytopic 생성 완료 화면]

여기서 끝이 아니다. 등록한 이메일로 확인(Confirm) 메일이 오고, 링크를 눌러 수락해야 구독이 활성화된다.

📸 [스크린샷: 수신한 Subscription Confirmation 메일 + Confirm 클릭 후 Status Confirmed]

4-2. 모니터링 대상 생성 (DynamoDB)

  1. DynamoDB 콘솔 → Create table
  2. 테이블 이름: board, 파티션 키 적당히 지정

📸 [스크린샷: DynamoDB board 테이블 Active 상태]

4-3. CloudWatch 알람 생성

  1. CloudWatch 콘솔 → Create alarm
  2. Select metric → DynamoDB → Table Metrics → board 테이블의 ConsumedWriteCapacityUnits
  3. 조건(Conditions): Threshold type Static, Greater than 0
  4. 알림 수단(SNS): 앞서 만든 mytopic 선택
  5. 알람 이름·설명 작성 후 생성

📸 [스크린샷: 알람 생성 직후 상태 — Insufficient data]

4-4. 테스트

board 테이블에 아이템을 하나 넣어 쓰기를 발생시킨다. ConsumedWriteCapacityUnits가 0을 초과하면 알람이 ALARM으로 전환되고, SNS를 통해 이메일이 날아온다.

📸 [스크린샷: 알람 상태 ALARM 전환 + 수신한 경고 이메일]

💡 알람 + SNS 연동에서 막혔던 점

  • 구독 확인을 안 하면 알림이 절대 안 온다. Topic만 만들고 Confirm 메일을 무시한 채로 테스트하면, 알람은 ALARM으로 잘 가는데 이메일이 안 와서 한참 헤맸다. SNS subscription의 Status가 Confirmed인지부터 확인하는 게 먼저다.
  • 알람을 만들자마자 상태가 Insufficient data라 "설정이 틀렸나" 싶었는데, 지표 데이터가 아직 수집 전이라 정상이었다. 쓰기가 한 번 발생하고 Period가 지나야 OK 또는 ALARM으로 평가된다.
  • 임계값을 > 0으로 잡은 건 데모용이라 쓰기가 한 번이라도 일어나면 무조건 울리는 세팅이다. 실무에선 이렇게 하면 알람 폭탄을 맞는다. 정상 트래픽 baseline 위로 의미 있는 임계값을 잡거나, Period·Datapoints to alarm을 조정해서 일시적 스파이크를 걸러내야 한다.
  • DynamoDB 지표는 온디맨드 모드면 프로비저닝 용량 개념이 없어서 ConsumedWriteCapacityUnits 해석이 달라진다. 데모는 용량 단위를 그대로 쓰지만, 실제 테이블 모드에 따라 어떤 지표를 볼지 달라진다는 점은 기억해둘 만하다.

5. CLI로 가능

콘솔로 한 작업은 전부 CLI로도 된다. 반복 세팅이나 IaC 직전 단계에선 CLI가 빠르다. 위 데모를 명령으로 옮기면 이렇다.

SNS Topic 생성 + 구독

# Topic 생성 (출력된 TopicArn을 이후 단계에 사용)
aws sns create-topic --name mytopic

# 이메일 구독 (실행 후 메일함에서 Confirm 필요)
aws sns subscribe \
  --topic-arn arn:aws:sns:ap-northeast-2:123456789012:mytopic \
  --protocol email \
  --notification-endpoint me@example.com

# 구독 상태 확인 (PendingConfirmation → 정상 ARN 으로 바뀌면 확인 완료)
aws sns list-subscriptions-by-topic \
  --topic-arn arn:aws:sns:ap-northeast-2:123456789012:mytopic

CloudWatch 알람 생성

aws cloudwatch put-metric-alarm \
  --alarm-name board-write-alarm \
  --namespace AWS/DynamoDB \
  --metric-name ConsumedWriteCapacityUnits \
  --dimensions Name=TableName,Value=board \
  --statistic Sum \
  --period 60 \
  --evaluation-periods 1 \
  --threshold 0 \
  --comparison-operator GreaterThanThreshold \
  --alarm-actions arn:aws:sns:ap-northeast-2:123456789012:mytopic

알람 상태 확인

aws cloudwatch describe-alarms \
  --alarm-names board-write-alarm \
  --query "MetricAlarms[0].StateValue" \
  --output text

💡 CLI로 해보니 달랐던 점

  • 콘솔은 metric 선택을 트리(DynamoDB → Table Metrics → board)로 클릭하지만, CLI는 --namespace + --metric-name + --dimensions를 직접 명시해야 한다. 네임스페이스와 차원 이름을 정확히 모르면 알람이 만들어져도 데이터가 안 붙는다. aws cloudwatch list-metrics로 실제 존재하는 지표를 먼저 확인하는 게 안전하다.
  • 콘솔에서 SNS Topic 선택은 드롭다운이지만, CLI --alarm-actionsTopicArn 문자열을 직접 넣어야 한다. ARN을 잘못 적어도 에러 없이 생성되고, 막상 알람이 울려도 알림만 안 온다. 조용히 실패하는 케이스라 주의.
  • put-metric-alarm은 생성/수정이 같은 명령이다. 동일 이름으로 다시 실행하면 덮어쓴다. 콘솔처럼 "수정" 버튼이 따로 없고, idempotent하게 동작하는 게 자동화엔 오히려 편하다.

학습 정리

  • CloudWatch는 상태(지표·로그·알람)를, CloudTrail은 행위(API 호출)를 본다. 축이 다르다
  • CloudWatch 지표는 Namespace + Dimension + Statistic + Period로 식별된다. EC2 기본 수집은 5분, 상세 모니터링 시 1분(+과금)
  • CloudTrail 관리 이벤트는 기본 무료, 데이터/인사이트 이벤트는 명시적 설정 + 과금. Event History는 90일, 그 이상은 Trail로 S3 저장
  • 알람 → SNS 알림은 구독 Confirm이 안 되면 동작하지 않는다. 새 알람의 Insufficient data는 정상 초기 상태
  • SNS(Push, 1:N, 비지속) vs SQS(Polling, 1:1, 지속). 폭증·장애 흡수는 SNS→SQS fan-out
  • 실무 임계값을 > 0 같은 데모 값으로 두면 알람 폭탄. baseline 기준 + 평가 주기 조정 필요