← 목록으로AWS

SNS + Lambda 기반 Slack 알림 구축 — ECS Task 장애 실시간 알림

CloudWatch Alarm → SNS → Lambda → Slack Webhook 파이프라인으로 ECS Task 장애를 Slack 채널에 실시간 알림하는 구조 구축

AWSSlackLambdaMonitoringECS
2024-08-15

배경

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 생성

  1. Slack 워크스페이스 → 앱 관리 → Incoming Webhooks
  2. "새 Webhook 추가" → 알림을 받을 채널 선택
  3. 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_URLSlack 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 알림을 활용합니다:

LambdaSlack 알림 내용
CheckWindowSvrAppStatusWindows 서버 FileReceiver 프로세스 다운 감지
AlertHub (SpringBoot)HTTP/파일 모니터링 이상 감지

각각 별도의 Slack 채널 또는 동일 채널에 알림을 보내며, YAML 설정으로 채널과 토큰을 관리합니다.


정리

  • SNS → Lambda → Slack Webhook 파이프라인으로 ECS Task 장애 실시간 알림 구축
  • Slack Attachment 형식으로 알람명, 상태, 시간, 사유를 구조화하여 전달
  • ALARM/OK 양방향 알림으로 장애 발생과 해소를 모두 팀에 공유
  • Webhook URL은 Lambda 환경변수로 관리하여 보안 확보
  • ECS 외에도 Windows 서버 모니터링, AlertHub 등에서 Slack 알림 활용