배경
ECS 서비스의 RunningTaskCount가 0이 되는 장애 상황을 팀 전체가 즉시 인지할 수 있도록 Slack 알림을 구축했습니다. 이메일은 확인이 늦을 수 있고, SMS/전화는 심각도가 높은 장애에 사용하므로, ECS Task 수준의 알림은 Slack이 적합했습니다.
아키텍처
CloudWatch Alarm (ECS RunningTaskCount <= 0)
↓
SNS Topic: ecs-task-alerts (Seoul)
↓
Lambda: SendSlackNotification
↓
Slack Incoming Webhook → 알림 채널
Slack Incoming Webhook 설정
Webhook URL 생성
- Slack 워크스페이스 → 앱 관리 → Incoming Webhooks
- "새 Webhook 추가" → 알림을 받을 채널 선택
- Webhook URL 복사
https://hooks.slack.com/services/T.../B.../...
이 URL로 HTTP POST 요청을 보내면 해당 채널에 메시지가 게시됩니다.
Webhook URL은 외부에 노출되면 누구나 메시지를 보낼 수 있으므로, Lambda 환경변수에 저장하고 코드에 직접 포함하지 않습니다.
Lambda: SendSlackNotification
SNS 메시지를 받아 Slack 메시지 형식으로 변환하여 Webhook으로 전송합니다.
import json
import urllib.request
import os
SLACK_WEBHOOK_URL = os.environ['SLACK_WEBHOOK_URL']
def lambda_handler(event, context):
# SNS 메시지 파싱
sns_message = event['Records'][0]['Sns']
subject = sns_message.get('Subject', 'ECS Alert')
message = json.loads(sns_message['Message'])
alarm_name = message.get('AlarmName', 'Unknown')
new_state = message.get('NewStateValue', 'Unknown')
reason = message.get('NewStateReason', '')
state_change_time = message.get('StateChangeTime', '')
# 상태에 따른 색상 설정
color = '#ff0000' if new_state == 'ALARM' else '#36a64f'
emoji = ':rotating_light:' if new_state == 'ALARM' else ':white_check_mark:'
# Slack 메시지 구성 (Attachment 형식)
slack_message = {
'text': f'{emoji} *ECS Task Alert*',
'attachments': [
{
'color': color,
'fields': [
{
'title': 'Alarm',
'value': alarm_name,
'short': True
},
{
'title': 'State',
'value': new_state,
'short': True
},
{
'title': 'Time',
'value': state_change_time,
'short': True
},
{
'title': 'Reason',
'value': reason[:200],
'short': False
}
]
}
]
}
# Slack Webhook으로 전송
req = urllib.request.Request(
SLACK_WEBHOOK_URL,
data=json.dumps(slack_message).encode('utf-8'),
headers={'Content-Type': 'application/json'}
)
urllib.request.urlopen(req)
return {'statusCode': 200}환경변수
| 변수 | 설명 |
|---|---|
SLACK_WEBHOOK_URL | Slack Incoming Webhook URL |
IAM 권한
Lambda 실행 역할에는 기본 실행 권한(AWSLambdaBasicExecutionRole)만 필요합니다. Slack Webhook은 외부 HTTP 호출이므로 별도 AWS 권한이 불필요합니다.
SNS Topic 연결
SNS Topic 생성
AWS 콘솔 → SNS → 주제 → 새 주제 생성
이름: ecs-task-alerts
유형: 표준(Standard)
Lambda 구독 등록
Lambda 콘솔 → SendSlackNotification → 트리거 추가
트리거 유형: SNS
SNS 주제: ecs-task-alerts
SNS → Lambda 연결 시 Lambda의 리소스 기반 정책에 SNS 호출 권한이 자동으로 추가됩니다.
CloudWatch Alarm 연결
ECS 서비스별로 RunningTaskCount 알람을 생성하고, 알람 액션으로 ecs-task-alerts SNS Topic을 지정합니다.
import boto3
cloudwatch = boto3.client('cloudwatch')
def create_ecs_task_alarm(cluster_name, service_name, sns_topic_arn):
cloudwatch.put_metric_alarm(
AlarmName=f'{service_name}-RunningTaskCount-Zero',
MetricName='RunningTaskCount',
Namespace='AWS/ECS',
Dimensions=[
{'Name': 'ClusterName', 'Value': cluster_name},
{'Name': 'ServiceName', 'Value': service_name},
],
Statistic='Average',
Period=60,
EvaluationPeriods=5,
Threshold=0,
ComparisonOperator='LessThanOrEqualToThreshold',
AlarmActions=[sns_topic_arn],
TreatMissingData='breaching',
)설계 포인트
- 5분 연속 조건: 배포 중 일시적으로 Task가 0이 되는 상황(롤링 업데이트)에서 오탐 방지
- TreatMissingData = breaching: 서비스 자체가 삭제되거나 메트릭 수집이 불가능한 상황도 감지
- 서비스별 개별 알람: 어떤 서비스에서 문제가 발생했는지 즉시 식별
ALARM → OK 복구 알림
알람이 해제(OK 상태 복구)될 때도 Slack에 알림을 보내면 장애 해소를 팀 전체가 인지할 수 있습니다.
Lambda 코드에서 NewStateValue에 따라 색상과 이모지를 분기 처리합니다:
ALARM→ 빨간색 + 🚨OK→ 초록색 + ✅
# CloudWatch Alarm에 OKActions도 추가
cloudwatch.put_metric_alarm(
# ... 기존 설정
AlarmActions=[sns_topic_arn],
OKActions=[sns_topic_arn], # OK 복구 시에도 알림
)다른 모니터링에서의 Slack 활용
ECS Task 알림 외에도 다음 Lambda 함수에서 Slack 알림을 활용합니다:
| Lambda | Slack 알림 내용 |
|---|---|
CheckWindowSvrAppStatus | Windows 서버 FileReceiver 프로세스 다운 감지 |
| AlertHub (SpringBoot) | HTTP/파일 모니터링 이상 감지 |
각각 별도의 Slack 채널 또는 동일 채널에 알림을 보내며, YAML 설정으로 채널과 토큰을 관리합니다.
정리
- SNS → Lambda → Slack Webhook 파이프라인으로 ECS Task 장애 실시간 알림 구축
- Slack Attachment 형식으로 알람명, 상태, 시간, 사유를 구조화하여 전달
- ALARM/OK 양방향 알림으로 장애 발생과 해소를 모두 팀에 공유
- Webhook URL은 Lambda 환경변수로 관리하여 보안 확보
- ECS 외에도 Windows 서버 모니터링, AlertHub 등에서 Slack 알림 활용