← 목록

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

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

2024-08-15AWSSlackLambdaMonitoringECS

배경

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',
    )

설계 포인트


ALARM → OK 복구 알림

알람이 해제(OK 상태 복구)될 때도 Slack에 알림을 보내면 장애 해소를 팀 전체가 인지할 수 있다.

Lambda 코드에서 NewStateValue에 따라 색상과 이모지를 분기 처리한다:

# 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 설정으로 채널과 토큰을 관리한다.


정리


배운 점

채널마다 사람이 반응하는 속도가 다르다. 이메일은 쌓이고, 문자는 놀라게 하고, Slack은 대화가 이어진다. ECS Task 수가 0이 되는 상황은 팀이 같이 보면서 원인을 좁혀야 하는 종류라서 Slack이 맞았다.

ALARM만이 아니라 OK도 같이 보내도록 한 게 의외로 컸다. 복구됐다는 신호가 없으면 사람은 계속 확인하러 들어간다. 알림은 상태 변화를 알려주는 것이지 사건만 알려주는 게 아니다.

이후 Windows 서버 프로세스 감시나 자체 알림 서비스도 같은 Webhook 구조를 재사용했다. 자세한 내용은 Windows 서버 프로세스 원격 모니터링과 AlertHub 멀티채널 알림 시스템 구축에 정리해 뒀다.


이어 읽기