안녕하세요 서후아빠입니다. ^_^
이번 세션은 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 구성요소 생성하기
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)을 업로드
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": ""
}
}
설정 후, 실제 수신된 메시지를 확인해 보시기 바랍니다. |
'Management' 카테고리의 다른 글
[실습] Control Tower 구성하기 - 1편 (배포, AWS 계정 관리, LifeCycle 이벤트, 메뉴) (0) | 2023.02.10 |
---|---|
[이론] Control Tower (Organizations, SSO) 기본 개념 (0) | 2023.02.10 |
[실습] AWS Systems Manager (Session Manager, Parameter Store, Run Command)-1편 (0) | 2022.09.23 |
[실습] AWS Trusted Advisor 사용하기 (0) | 2022.09.02 |
[이론] AWS Trusted Advisor 기본 개념 (0) | 2022.09.02 |