RDS 이벤트 Slack으로 알람 받기

dragonappear·2022년 7월 6일
0

AWS

목록 보기
4/6
post-custom-banner

참고


글 작성 계기

  • 프로젝트에서 사용할 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 알림이 온다!

post-custom-banner

0개의 댓글