개요
운영 중인 EC2 인스턴스와 ECS 서비스 전반에 걸쳐 CloudWatch 알람 체계를 설계하고 구축했다.
단순 CPU 모니터링을 넘어 메모리, 디스크, IOPS, 시스템 상태, ECS Task Count까지 포괄하는 다층 알림 구조를 구성했으며, 심각도에 따라 이메일 / 문자 / 전화 / Slack으로 알림 채널을 분리했다.
알람 설계 원칙
심각도별 알림 채널 분리
| 단계 | 지속 시간 | 알림 방식 | 설명 |
|---|---|---|---|
| 경고 (Warning) | 5분 (5/5) | 이메일 | 초기 이상 감지 |
| 위험 (Critical) | 10분 (10/10) | 문자 | 지속적 이상 상태 |
| 장애 (Down) | 1분 (1/1) | 문자 + 전화 | 즉각 대응 필요 |
| ECS 이상 | 5분 (5/5) | Slack | 태스크 수 변동 감지 |
EC2 모니터링 항목
EC2 인스턴스별로 다음 지표를 모니터링한다.
시스템 리소스
| 지표 | 경고 (5분) | 위험 (10분) |
|---|---|---|
| CPUUtilization | 이메일 | 문자 |
| mem_used_percent | 이메일 | 문자 |
| swap_used_percent | 이메일 | - |
| disk_used_percent (OS 볼륨) | 이메일 | 문자 |
| disk_used_percent (SW 볼륨) | 이메일 | 문자 |
| 평균 IOPS 사용량 | 이메일 | - |
| StatusCheckFailed | 문자 + 전화 (1분) | - |
StatusCheckFailed는 인스턴스 다운을 의미하므로 1분 단위로 즉시 문자 + 전화 알림을 설정했다.
CloudWatch Agent 설치
메모리, 스왑, 디스크 지표는 기본 CloudWatch 지표에 포함되지 않으므로 CloudWatch Agent를 각 인스턴스에 설치해 수집한다.
# CloudWatch Agent 설치 (Amazon Linux 2)
sudo yum install amazon-cloudwatch-agent -y
# 설정 파일 적용
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
-a fetch-config \
-m ec2 \
-s \
-c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.jsonECS 서비스 모니터링 항목
ECS 서비스는 Auto Scaling이 설정되지 않은 서비스의 경우 CloudWatch로 직접 모니터링한다.
모니터링 지표
| 지표 | 알림 방식 | 비고 |
|---|---|---|
| CPUUtilization | 이메일 | 5분 (5/5) |
| mem_used_percent | 이메일 | 5분 (5/5) |
| disk_used_percent | 이메일 | 5분 (5/5) |
| RunningTaskCount | Slack | 태스크 수 감소 시 즉시 알림 |
Auto Scaling이 설정된 서비스는 스케일링으로 자동 대응되지만, 미설정 서비스는 RunningTaskCount 알람으로 태스크 다운을 감지한다.
RunningTaskCount 알람 설정 예시
import boto3
cloudwatch = boto3.client('cloudwatch')
cloudwatch.put_metric_alarm(
AlarmName='ECS-Service-RunningTaskCount-Low',
MetricName='RunningTaskCount',
Namespace='AWS/ECS',
Dimensions=[
{'Name': 'ClusterName', 'Value': '[cluster-name]'},
{'Name': 'ServiceName', 'Value': '[service-name]'},
],
Statistic='Average',
Period=300, # 5분
EvaluationPeriods=1,
Threshold=1,
ComparisonOperator='LessThanThreshold',
AlarmActions=['[sns-topic-arn]'], # Slack 연동 SNS
TreatMissingData='breaching',
)알림 채널 구성
SNS → 다중 채널 연동
CloudWatch Alarm
↓
SNS Topic
├── 이메일 구독 (Warning)
├── SMS 구독 (Critical)
└── Lambda → Slack Webhook (ECS Task)
Slack 알림 Lambda 예시
import json
import urllib.request
def lambda_handler(event, context):
message = json.loads(event['Records'][0]['Sns']['Message'])
alarm_name = message['AlarmName']
state = message['NewStateValue']
reason = message['NewStateReason']
payload = {
"text": f":warning: *{alarm_name}*\n상태: {state}\n사유: {reason}"
}
req = urllib.request.Request(
'[slack-webhook-url]',
data=json.dumps(payload).encode(),
headers={'Content-Type': 'application/json'}
)
urllib.request.urlopen(req)모니터링 대상 범위
구축한 알람의 전체 범위:
EC2 인스턴스
- 애플리케이션 서버 (Active/Standby 구성)
- DB 서버 (Primary + Replica)
- FTP 서버 (Windows, 다중 드라이브 모니터링)
ECS 서비스
- Batch 서비스
- API 서비스 (다수)
- 외부 연동 서비스
모니터링 지표 총계
- EC2 알람: 약 50개 이상
- ECS 알람: 서비스당 4개 (CPU, Memory, Disk, TaskCount)
정리
이번 CloudWatch 알람 구축을 통해 다음을 달성했다.
- 전체 인프라에 대한 실시간 모니터링 체계 확립
- 심각도별 알림 채널 분리로 불필요한 알림 피로 감소
- ECS Task 다운 즉시 감지로 서비스 장애 대응 시간 단축
- Auto Scaling 미적용 서비스에 대한 수동 모니터링 보완
핵심은 단순히 알람을 많이 만드는 것이 아니라, 심각도와 대응 방식에 맞게 알림 채널을 설계하는 것이다.
배운 점
알람을 많이 만들수록 안전해진다고 생각했는데, 실제로는 반대였다. 알림이 늘어나면 사람은 알림을 읽지 않게 된다. 그래서 이 작업의 핵심은 지표를 추가하는 일이 아니라 "이 상황은 이메일인가, 문자인가, 전화인가"를 정하는 일이었다.
기준은 결국 대응 시점이었다. 지금 일어나서 봐야 하는가, 아니면 내일 아침에 봐도 되는가. 이 질문 하나로 채널이 갈렸고, 감지 주기(5분/10분/1분)도 여기에 맞춰 정해졌다.
이 원칙은 이후 알림 작업의 기본값이 됐다. SNS + Lambda 기반 Slack 알림 구축에서 ECS Task 알림을 Slack으로 보낸 것도, AWS Connect 아웃바운드 콜 테스트에서 전화까지 붙인 것도 같은 기준을 따른 결과다.
이어 읽기
- SNS + Lambda 기반 Slack 알림 구축: Slack 채널이 맡는 알림의 범위
- SNS SMS 크로스 리전 구성: 문자 채널을 실제로 구현한 방법
- 통합 모니터링 시스템 구축: 채널 분리 원칙이 전체 체계로 확장된 모습