본문 바로가기

Management

[실습] Telegram Bot or Slack Channel연동하여 CloudWatch Alarm 메시지 받기

반응형

안녕하세요 서후아빠입니다. ^_^

이번 세션은 CloudWatch에서 발생하는 Alarm을 Telegram Bot이나 Slack Channel로 수신받는 실습을 해보겠습니다.

파일선 코딩은 초보자 수준이니 귀엽게 봐주세요.

 


구성도

기본적으로 VPC endpoint가 필요없지만, EC2의 MEM 및 HDD 사용량까지 관리하기 위해서는 구성이 필요합니다. 

사전 작업

인프라 생성 : vpc, subnet, igw, routing table, iam, ec2, tgw  등은 설명 생략합니다. 

2022.07.02 - [Networking] - [실습] Amazon VPC 구성요소 생성하기

 

[실습] Amazon VPC 구성요소 생성하기

안녕하세요 서후아빠입니다. ^_^ 이번 세션은 VPC 관련 구성요소에 대해서 실습을 해보겠습니다. 구성도 1단계 : VPC 생성 VPC > Your VPCs > Create VPC 구분 VPC settings (VPC Only 방식) VPC settings (VPC a..

sh-t.tistory.com

1단계 : Telegram Bot 준비 (Telegram 경우)

PC에 Telegram 설치하고 브라우저에서 https://telegram.me/BotFather로 접속하여 "SEND MESSAGE" 클릭

PC에 설치된 Telegram > BotFather > START > 봇 생성 > 봇 이름 정의 > 사용자(Username) 생성 > Token 별도 저장 > 링크 클릭(ex : t.me/AlarmBot_bot)

# 봇 생성
/newbot

# 봇 이름 정의
AlarmBot

# 사용자(Username) 생성 : 시작은 ‘@’, 끝은 ‘bot’, 다른 사용자와 중복되지 않도록
@AlarmBot_bot

… 
You will find it at t.me/AlarmBot_bot.  // 링크
…
Use this token to access the HTTP API:
5897573414:AAFIHpm76uo_09Hm2ZdR7Z7eSr8nelrEXQg  // Token(bot id)
…

PC에 설치된 Telegram > AlarmBot > START

PC에 설치된 Telegram > Search에 “Get My Id”로 검색 > Get My ID > START > Current chat ID(ex : 123456789) 확인

1단계 : Slack Channel 준비 (Slack 경우)

https://slack.com > "TRY FOR FREE" > 가입(ID예시: slackuser) 및 메일 인증 > 워크스페이스 생성(ex : AlarmChannel)

AlarmChannel > 좌측 메뉴에서 "Browse Slack(Slack 찾아보기)" > Apps(앱) >검색란 “incoming webhooks”로 검색 > Add(추가) > Add to Slack(Slack에 추가)

Post to Channel(채널에 포스트)에서 “#AlarmChannel” 선택 > Add Incoming WebHooks integration(수신 웹후크 통합 앱 추가) > Webhook URL 확인(ex : https://hooks.slack.com/services/T03VbeH) > Save Settings

2단계 : SNS Topic 설정

SNS > Topics > Create topic

Type Name Delivery status logging (옵션, 전송상태 확인하고자 할 경우만 설정)
Standard AlarmTopic Log delivery status for these protocols : Platform application endpoint
Success sample rate : 100
IAM roles : Create new service role 선택 > Create new roles 클릭> 기본값 유지 > Allow
※ Roles 기본값
  - IAM Role : Create a new IAM Role
  - Role Name : SNSSuccessFeedbak, SNSFailureFeedback
Delivery status logging : SNS 전송 상태(성공/실패) CloudWatch (Logs, Metrics Event 등)에 로깅됩니다.

3단계 : CloudWacth Alarm 설정

CloudWatch > All alarms > Create alarm

Specify metric and conditions (EC2 CPU 예시) Configure actions
Select metric : EC2 > EC2의 CPUUtilization 선택
Metric name : PRD-WEB-CPUUtilization85UP
Conditions
- Threshold type : Static
- Whenever CPUUtilization is... : Greater/Equal
- than : 85
Alarm state trigger : In alarm
Send a notification to the following SNS topic : Select an existing SNS topic
Send a notification to… : AlarmTopic
위 구성도의 Targets에 대한 항목별로 Alarm을 설정합니다.
동일 Type(ex : EC2)에 대해서 일괄적으로 등록이 불가능합니다. 개별 리소스별로 등록해야 합니다.

4단계 : Lambda 설정

Lambda > Functions > Create function

Select Function Name Runtime Architecture Execution role
Author from scratch AlarmTelegram Python 3.9 x86_64 새로 생성 or 기본 Role 선택
Author from scratch AlarmSlack Python 3.9 x86_64 새로 생성 or 기본 Role 선택

Lambda > Functions > AlarmTelegram or AlarmSlack > Function overview의 “+Add trigger” > SNS 선택 > SNS topic(AlarmTopic) > Add

Lambda > Functions > AlarmTelegram or AlarmSlack> Code(tab) > Upload from > .zip file > 코드 파일(ex : AlarmTelegram.zip)을 업로드

AlarmTelegram.zip
1.79MB

Slack 경우는 파일 업로드없이 아래 코드 내용을 lambda_function.py에 입력해도 동작합니다.
# lambda_function.py 샘플(Telegram 경우)

import sys
sys.path.append("./modules")
import telegram
import json
import os

telegram_token = os.environ['telegram_token']
telegram_chat_id = os.environ['telegram_chat_id']
bot=telegram.Bot(token = telegram_token)

def lambda_handler(event,context):

	print(event)

	# event 내용에서 Records 항목의 Message 내용만 뽑아내기
	msg = json.loads(event["Records"][0]["Sns"]["Message"])
	
	# msg 내용에서 특정 항목만 뽑아내기
	msgAlarmName = msg["AlarmName"]
	msgNewStateReason = msg["NewStateReason"]
	msgTriggerNamespace = msg["Trigger"]["Namespace"]
	msgTriggerDimensionsValue = msg["Trigger"]["Dimensions"][0]["value"]

	# msg 내용 전체를 json으로 출력
	#msgjson=json.dumps(msg, indent=4)
	#body="Message : %s" % (msgjson)

	# message 내용에서 특정 항목만 줄바꿈으로 출력
	body = "[AWS Alarm]" + "\n\n" + "- AlarmName : " + msgAlarmName + "\n" + "- Reason : " + msgNewStateReason + "\n" + "- ResourceType : " + msgTriggerNamespace + "\n" + "- ResourceID : " + msgTriggerDimensionsValue

	# 텔레그램으로 전송하기
	bot.sendMessage(chat_id = telegram_chat_id, text = body)
    

# lambda_function.py 샘플(Slack 경우)

import urllib3
import json
import os
http = urllib3.PoolManager()

slack_hook_url = os.environ['slack_hook_url']
slack_channel = os.environ['slack_channel']
slack_username = os.environ['slack_username']

def lambda_handler(event, context):

	print(event)

	# event 내용에서 Records 항목의 Message 내용만 뽑아내기
	msg = json.loads(event["Records"][0]["Sns"]["Message"])

	# message 내용에서 특정 항목만 뽑아내기
	msgAlarmName = msg["AlarmName"]
	msgNewStateReason = msg["NewStateReason"]
	msgTriggerNamespace = msg["Trigger"]["Namespace"]
	msgTriggerDimensionsValue = msg["Trigger"]["Dimensions"][0]["value"]

	# message 내용에서 특정 항목만 줄바꿈으로 출력
	body = "[AWS Alarm]" + "\n\n" + "- AlarmName : " + msgAlarmName + "\n" + "- Reason : " + msgNewStateReason + "\n" + "- ResourceType : " + msgTriggerNamespace + "\n" + "- ResourceID : " + msgTriggerDimensionsValue

	msgslack = {
		"channel": slack_channel,
		"username": slack_username,
		"text": body,
		"icon_emoji": ""
	}

	# Message 내용을 UTF-8로 인코딩하여 json 포맷으로 변환
	bodyjson = json.dumps(msgslack).encode('utf-8')

	# 슬랙으로 전송하기
	resp = http.request('POST', slack_hook_url, body = bodyjson)
Code(tab) > Runtime settings의 Handler (ex : lambda_function.lambda_handler) 관련 주의사항
- lambda_function : AlarmTelegram.zip에서 실행되는 파일명 (ex : lambda_function.py)
- lambda_handler : lambda_function.py의 def명 (ex : def lambda_handler)

Handler값을 맞추지 않을 경우 발생하는 Error 메시지
{  "errorMessage": "Unable to import module 'lambda_function': No module named 'lambda_function'",  "errorType": "Runtime.ImportModuleError",  "requestId": "b3efa0ef-2206-4b0f-a4c5-742c0a901408",  "stackTrace": []}

Lambda > Functions > AlarmTelegram or AlarmSlack > Configuration(tab) > General configuration > Edit > Timeout (30sec) > Save

Timeout값이 부족한 경우 발생하는 Error 메시지
"errorMessage": "2023-01-25T04:36:19.983Z 13b31a1c-648d-4fd0-9d2f-a0b6670b6abc Task timed out after 3.11 seconds“

Lambda > Functions > AlarmTelegram or AlarmSlack > Configuration(tab) > Environment variables > Edit  > Add envirionment variable

구분 Key Value
AlarmTelegram 경우 telegram_chat_id 123456789
telegram_token 5897573414:AAFIHpm76uo_09Hm2ZdR7Z7eSr8nelrEXQg
AlarmSlack 경우 slack_hook_url https://hooks.slack.com/services/T03VbeH
slack_channel #AlarmChannel
slack_username slackuser

Lambda > Functions > AlarmTelegram or AlarmSlack > Code(tab) > Test > Configure test event

Test event action Event name Event JSON
Create new event test 아래 샘플 입력
{
  "Records": [{
      "EventSource": "aws:sns",
      "EventVersion": "1.0",
      "EventSubscriptionArn": "arn:aws:sns:ap-northeast-2:111111111111:AlarmTopic:d6b01aae-b8f2-49f3-93a5-fa7f4a9b1997",
      "Sns": {
        "Type": "Notification",
        "MessageId": "e5eff11a-b67b-5097-a735-ad50620e1ebc",
        "TopicArn": "arn:aws:sns:ap-northeast-2:111111111111:AlarmTopic",
        "Subject": "ALARM: \"PRD-WEB-CPUUtilization85UP\" in Asia Pacific (Seoul)",
        "Message": "{\"AlarmName\":\"PRD-WEB-CPUUtilization85UP\",\"AlarmDescription\":null,\"AWSAccountId\":\"111111111111\",\"AlarmConfigurationUpdatedTimestamp\":\"2023-01-25T06:53:42.033+0000\",\"NewStateValue\":\"ALARM\",\"NewStateReason\":\"Threshold Crossed: 1 out of the last 1 datapoints [89.10999950029536924 (25/01/23 06:50:00)] was greater than the threshold (85) (minimum 1 datapoint for OK -> ALARM transition).\",\"StateChangeTime\":\"2023-01-25T06:54:45.854+0000\",\"Region\":\"Asia Pacific (Seoul)\",\"AlarmArn\":\"arn:aws:cloudwatch:ap-northeast-2:111111111111:alarm:PRD-WEB-CPUUtilization85UP\",\"OldStateValue\":\"OK\",\"OKActions\":[],\"AlarmActions\":[\"arn:aws:sns:ap-northeast-2:111111111111:AlarmTopic\"],\"InsufficientDataActions\":[],\"Trigger\":{\"MetricName\":\"CPUUtilization\",\"Namespace\":\"AWS/EC2\",\"StatisticType\":\"Statistic\",\"Statistic\":\"AVERAGE\",\"Unit\":null,\"Dimensions\":[{\"value\":\"i-0221e8fdef8dbba25\",\"name\":\"InstanceId\"}],\"Period\":60,\"EvaluationPeriods\":1,\"DatapointsToAlarm\":1,\"ComparisonOperator\":\"GreaterThanThreshold\",\"Threshold\":0.01,\"TreatMissingData\":\"missing\",\"EvaluateLowSampleCountPercentile\":\"\"}}",
        "Timestamp": "2023-01-25T06:54:45.906Z",
        "SignatureVersion": "1",
        "Signature": "YMyg7oiQQsaPq6UwheX9Qnzm5NHk9PMM/slxDscNVVBX1nJj2naki+pstlpToFnTK76wyileZrTc7HMJ4ZFMZpU8uFN7bHkAIqrlMkSZ2WzY7WPhRYcxTeEl+3Y6gcBah8XVkRqQq+GgQNCZ0IT/vKcxw929jwWDN/NYxfX7qFjd5YNE3Q5y8uyKjOKbx6BrYX50O1wbTZFVzdKcKKA0sDP/lI/4yy9BBemerzDkDI2crJyY0ItLXeL9y4rRt22GeYeZw+fRWNQzYVOqbpo5c4IXplk3YJgoNg7LVlHHUzRYJOQ+i5eZ5H19OtP7ub7Sy04Wj9aSMAn1ROqefwEH3w==",
        "SigningCertUrl": "https://sns.ap-northeast-2.amazonaws.com/SimpleNotificationService-56e67fcb41f6fec09b0196692625d385.pem",
        "UnsubscribeUrl": "https://sns.ap-northeast-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-northeast-2:111111111111:AlarmTopic:d6b01aae-b8f2-49f3-93a5-fa7f4a9b1997",
        "MessageAttributes": {}
      }}]}

Lambda > Functions > AlarmTelegram or AlarmSlack > Code(tab) > Test > 테스트를 통하여 Telegram에 수신된 메시지 확인

# 수신 메시지 샘플 : 특정 항목만 출력한 경우
[AWS Alarm]
- AlarmName : PRD-WEB-CPUUtilization85UP
- Reason : Threshold Crossed: 1 out of the last 1 datapoints [0.10999950029536924 (25/01/23 06:50:00)] was greater than the threshold (0.01) (minimum 1 datapoint for OK -> ALARM transition).
- ResourceType : AWS/EC2
- ResourceID : i-0221e8fdef8dbba25


# 수신 메시지 샘플 : 전체를 json으로 출력한 경우
Message : {
    "AlarmName": "PRD-WEB-CPUUtilization85UP",
    "AlarmDescription": null,
    "AWSAccountId": "111111111111",
    "AlarmConfigurationUpdatedTimestamp": "2023-01-25T06:53:42.033+0000",
    "NewStateValue": "ALARM",
    "NewStateReason": "Threshold Crossed: 1 out of the last 1 datapoints [89.10999950029536924 (25/01/23 06:50:00)] was greater than the threshold (85) (minimum 1 datapoint for OK -> ALARM transition).",
    "StateChangeTime": "2023-01-25T06:54:45.854+0000",
    "Region": "Asia Pacific (Seoul)",
    "AlarmArn": "arn:aws:cloudwatch:ap-northeast-2:111111111111:alarm:PRD-WEB-CPUUtilization85UP",
    "OldStateValue": "OK",
    "OKActions": [],
    "AlarmActions": [
        "arn:aws:sns:ap-northeast-2:111111111111:AlarmTopic"
    ],
    "InsufficientDataActions": [],
    "Trigger": {
        "MetricName": "CPUUtilization",
        "Namespace": "AWS/EC2",
        "StatisticType": "Statistic",
        "Statistic": "AVERAGE",
        "Unit": null,
        "Dimensions": [
            {
                "value": "i-0221e8fdef8dbba25",
                "name": "InstanceId"
            }
        ],
        "Period": 60,
        "EvaluationPeriods": 1,
        "DatapointsToAlarm": 1,
        "ComparisonOperator": "GreaterThanThreshold",
        "Threshold": 0.01,
        "TreatMissingData": "missing",
        "EvaluateLowSampleCountPercentile": ""
    }
}
설정 후, 실제 수신된 메시지를 확인해 보시기 바랍니다.
반응형