RDS 이벤트 Slack으로 알람 받기

dragonappear·2022년 7월 6일
0

AWS

목록 보기
4/6

참고


글 작성 계기

  • 프로젝트에서 사용할 DB에 이벤트(ex: 종료된다던지)가 발생할 때 Slack으로 알람을 받고 싶어서 작성하게 되었다.

방식

RDS -> 이벤트 -> SNS -> Lambda -> Slack 으로 진행할 것이다.


1.SNS 토픽 생성


위 단계대로 주제를 생성한다.

주의


2.RDS 이벤트 구독

RDS -> 이벤트 구독 -> 이벤트 구독 생성

이벤트 구독이 성공적으로 생성되면 리스트에서 확인할 수 있다.


3.Lambda 함수 생성

함수 생성 후 index.js에 아래 코드를 넣는다.

console.log('Loading function');

exports.handler = async (event, context) => {
    console.log('Received event:', JSON.stringify(event));
};

그리고 이벤트 구독을 한 RDS를 재시작해본다.

그러면 Lambda가 찍은 Log를 CloudWatch에서 확인해본다. 확인해보면 아래와 같은 JSON 형태로 메시지가 오는 것을 확인할 수 있다.

2022-07-07T02:08:41.104Z	05a69f22-b890-4945-85bd-ba0b8532ee12	INFO	Received event: 
{
    "Records": [
        {
            "EventSource": "aws:sns",
            "EventVersion": "1.0",
            "EventSubscriptionArn": "arn:aws:sns:ap-northeast-2:123:rds-event-topic:ed7ae436-c4fc-4a2e-abbf-4108b17512de",
            "Sns": {
                "Type": "Notification",
                "MessageId": "a88fabce-a070-5362-9b53-f08ee218bc8a",
                "TopicArn": "arn:aws:sns:ap-northeast-2:123:rds-event-topic",
                "Subject": "RDS Notification Message",
                "Message": "{\"Event Source\":\"db-instance\",\"Event Time\":\"2022-07-07 02:08:27.718\",\"Identifier Link\":\"https://console.aws.amazon.com/rds/home?region=ap-northeast-2#dbinstance:id=dev-moccozy-mysql\",\"Source ID\":\"dev-moccozy-mysql\",\"Source ARN\":\"arn:aws:rds:ap-northeast-2:123:db:dev-moccozy-mysql\",\"Event ID\":\"http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Events.html#RDS-EVENT-0006\",\"Event Message\":\"DB instance restarted\"}",
                "Timestamp": "2022-07-07T02:08:40.942Z",
                "SignatureVersion": "1",
                "Signature": "YkUF9HhPhTNdXZBtsXdbyLsYyonY3xmj2OjcyK8iQt9o9d9LKyBNCGfLTsXzw3YWni7FGt7zLzKSrglGic8XndRf1aAV/sTJyEe/TocwHunF63ZaxPvu/J/tG+tKNF23irAIpKonFg6CnAP4zC2+FO060N6CiMrwegPisWsb3Bk2n+btO0G+/i0zEhRk1C9SoCp6HYHKD3LLLdR3Oyr6N1ImXEgV1KmTzHuIcSwpiFJPpujWaEslOcvMXjzI44yTGFW9vbQw6cAT/Oxi+nKWFjwAV2oRm7PY3M7q9KM+6Y05PamJCh0YTKuFq299YRg+RXgN22SlQCya+/voxJ72uA==",
                "SigningCertUrl": "https://sns.ap-northeast-2.amazonaws.com/SimpleNotificationService-7ff5318490ec183fbaddaa2a969abfda.pem",
                "UnsubscribeUrl": "https://sns.ap-northeast-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-northeast-2:123:rds-event-topic:ed7ae436-c4fc-4a2e-abbf-4108b17512de",
                "MessageAttributes": {}
            }
        }
    ]
}

그러면 이제 받은 메시지를 파싱해서 슬랙으로 보내는 작업을 해보자.

3.1 Lambda 함수 작성

전체코드

const ENV = process.env
if (!ENV.webhook) throw new Error('Missing environment variable: webhook')

const webhook = ENV.webhook;
const https = require('https')

exports.handler = async (event) => {
    await exports.processEvent(event);
}

exports.processEvent = async (event) => {
    console.log('Event:', JSON.stringify(event))
    const snsMessage = event.Records[0].Sns.Message;
    console.log('SNS Message:', snsMessage);
    const postData = exports.buildSlackMessage(JSON.parse(snsMessage))
    await exports.postSlack(postData, webhook);
}

exports.buildSlackMessage = (data) => {
    console.log('DATA:', data);
    const eventSource = data["Event Source"];
    const eventTime = data["Event Time"].split(".")[0];
    const sourceId = data["Source ID"];
    const eventMessage = data["Event Message"];
        
    return {
        attachments: [
            {
                title: "["+eventMessage+"]",
                color: "warning",
                fields: [
                    {
                        title: '이벤트 소스',
                        value: eventSource
                    },
                    {
                        title: '이벤트 시간',
                        value: exports.toYyyymmddhhmmss(eventTime)
                    },
                    {
                        title: '소스 아이디',
                        value: sourceId
                    },
                    {
                        title: '메시지',
                        value: eventMessage
                    }
                ]
            }
        ]
    }
}

// 타임존 UTC -> KST
exports.toYyyymmddhhmmss = (timeString) => {

    if(!timeString){
        return '';
    }

    const kstDate = new Date(new Date(timeString).getTime() + 32400000);

    function pad2(n) { return n < 10 ? '0' + n : n }

    return kstDate.getFullYear().toString()
        + '-'+ pad2(kstDate.getMonth() + 1)
        + '-'+ pad2(kstDate.getDate())
        + ' '+ pad2(kstDate.getHours())
        + ':'+ pad2(kstDate.getMinutes())
        + ':'+ pad2(kstDate.getSeconds());
}

exports.postSlack = async (message, slackUrl) => {
    return await request(exports.options(slackUrl), message);
}

exports.options = (slackUrl) => {
    const {host, pathname} = new URL(slackUrl);
    return {
        hostname: host,
        path: pathname,
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
    };
}

function request(options, data) {

    return new Promise((resolve, reject) => {
        const req = https.request(options, (res) => {
            res.setEncoding('utf8');
            let responseBody = '';

            res.on('data', (chunk) => {
                responseBody += chunk;
            });

            res.on('end', () => {
                resolve(responseBody);
            });
        });

        req.on('error', (err) => {
            console.error(err);
            reject(err);
        });

        req.write(JSON.stringify(data));
        req.end();
    });
}

3.2 테스트

테스트 해보면 아래와 같은 형식으로 Slack 알람이 전송된다.

3.3 실제 RDS 반응 테스트

실제로 운영중인 말고!! 테스트용 DB를 재부팅해본다.

그러면 아래와 같이 Slack 알림이 온다!

0개의 댓글

관련 채용 정보