Skip to main content

텔레그램 봇으로 AWS 비용 알람 받기

오늘 포스팅은 AWS 비용을 텔레그램 봇으로 알람 받는 방법에 대해서 설명드리고자 합니다.

Telegram Bot 생성

Alert_Budget1

먼저 텔레그램 봇을 생성하는 방법입니다. BotFather 계정을 검색한 후에 /newbot를 입력하여 봇을 생성합니다. 봇을 생성한 후에 위 내용처럼 t.me로 시작하는 링크를 받게 되고 이 링크에 접속하여 생성한 봇과의 채팅방에 접속합니다.

Alert_Budget2

봇 이름을 [].[].[]_bot으로 생성할 경우 [].[].[] 이름의 채팅방으로 접속할 수 있는데 대쉬로 구분할 경우에는 다른가봅니다. 다른 실습에서 ghdwlsgur.github.io_bot으로 텔레그램 봇을 생성했더니 ghdwlsgur.github.io 봇이 만들어졌었거든요. 각설하고 채팅방에 접속하였다면 위와 같이 테스트 메시지를 전송하는데 메시지를 하나만 보낼 경우 텔레그램 API URL의 HTTP GET 응답의 result 배열 값이 빈 배열로 오기 때문에 메시지를 한 번 더 전송하여 chat ID를 확인합니다. 이 chat ID는 현재 테스트 메시지를 보낸 대화방의 고유 인덱스가 되며 이 대화방에서 알람을 확인할 겁니다.

Alert_Budget3

Lambda 생성

  • 런타임: Python 3.7
  • 아키텍터: x86_64

위 스펙으로 람다 함수를 생성합니다.

구성 - 환경변수 편집

위에서 발급받은 텔레그램 토큰과 CHAT_ID를 람다 환경 변수에 저장하고 12자리 어카운트 아이디를 ACCOUNT_ID 값으로 저장합니다.

Alert_Budget4

제한시간 10초로 증가

기본 설정의 경우 제한시간이 3초로 설정되어 있으나 간혹 3초가 넘어 Time Out이 발생하기 때문에 10초로 증가시켜줍니다.

Alert_Budget5

람다 함수에 권한 부여

AWS Cost Explorer API를 사용하기 위해서 람다에 Cost Explorer 접근 권한을 부여합니다. 구성 - 권한 - 실행 역할에서 역할 이름을 클릭한 뒤 인라인 정책 생성을 누르고 JSON 탭으로 들어가 아래와 같이 입력합니다.

Alert_Budget6

Alert_Budget7

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "ce:GetCostAndUsage",
"Resource": "*"
}
]
}

파이썬 코드 입력

코드는 다음과 같습니다. 저는 기존에 AWS 크레딧을 사용하고 있기 때문에 레코드 타입에서 Credit과 Refund는 제외하였습니다. Cost Explorer을 다루는 데에 익숙치 않기 때문에 AWS 비용관리 탭에서 Cost Explorer의 대시보드 필터를 사용하여 설정값에 따라 변화되는 비용을 확인하고 아래와 같이 코드로 작성하였습니다.

Alert_Budget8

import datetime
import os
import requests

import boto3
from dateutil import relativedelta

TOKEN = os.environ['TOKEN']
CHAT_ID = os.environ['CHAT_ID']
ACCOUNT_ID = os.environ['ACCOUNT_ID']
TELEGRAM_URL = "https://api.telegram.org/bot{}/sendMessage".format(TOKEN)

def lambda_handler(event, context):
def monthly_service_bill(start, end):
response = client.get_cost_and_usage(
TimePeriod={"Start": start, "End": end},
Granularity="MONTHLY",
Metrics=["UNBLENDED_COST"],
Filter = {
"And": [{
"Dimensions": {
"Key": "LINKED_ACCOUNT",
"Values": [ACCOUNT_ID]
}
}, {
"Not": {
"Dimensions": {
"Key": "RECORD_TYPE",
"Values": ["Credit", "Refund"]
}
}
}]
},
GroupBy=[
{
'Type': 'DIMENSION',
'Key': 'SERVICE'
}
]
)
group = response["ResultsByTime"][0]['Groups']
return group

def monthly_total_bill(start, end):
response = client.get_cost_and_usage(
TimePeriod={"Start": start, "End": end},
Granularity="MONTHLY",
Metrics=["UNBLENDED_COST"],
Filter = {
"Not": {
"Dimensions": {
"Key": "RECORD_TYPE",
"Values": ["Credit", "Refund"]
}
}
},
)
amount = response["ResultsByTime"][0]["Total"]["UnblendedCost"]["Amount"]
output = "%.2f" % float(amount)
return str(output)

this_month = datetime.datetime.today()
next_month = this_month + relativedelta.relativedelta(months=1)

this_month_1st = this_month.strftime("%Y-%m-01")
next_month_1st = next_month.strftime("%Y-%m-01")

client = boto3.client("ce")
this_month_bill = monthly_total_bill(this_month_1st, next_month_1st)

url = "https://quotation-api-cdn.dunamu.com/v1/forex/recent?codes=FRX.KRWUSD"

ex_response = requests.get(url)
ex_html = ex_response.json()
exchange = ex_html[0]['basePrice']

this_month_bill_dollor = this_month_bill
this_month_bill_won = int((float(this_month_bill)) * exchange)
this_month_bill_won = format(this_month_bill_won, ",")

message = "[ AWS 일일 운용 비용 알람 ]\n" \
+ this_month.strftime("- 기준일 : %Y년 %m월 %d일") + "\n" \
+ "- 계정 : HongJinHyeok ( " + str(ACCOUNT_ID) + " )\n" \
+ "- 적용 환율 : " + str(exchange) + "원\n" \
+ "- 총 비용(원) : " + str(this_month_bill_won) + "원 (월 누적)\n" \
+ "- 총 비용($) : " + str(this_month_bill_dollor) + "달러 (월 누적)\n" \
+ "\n[ 서비스별 사용 내역 ]\n"

svc_bill = monthly_service_bill(this_month_1st, next_month_1st)

for svc in svc_bill:
svc_name = svc['Keys'][0]
svc_amount = svc['Metrics']['UnblendedCost']['Amount']
message += "- " + str(svc_name) + " / " + str(svc_amount) + "$\n"


try:
payload = {
"text": message.encode("utf-8"),
"chat_id": CHAT_ID
}
requests.post(TELEGRAM_URL, payload)
except Exception as e:
raise e

코드를 입력하고 람다 함수를 배포한 뒤에 마지막으로 이 람다 함수가 규칙적으로 정해진 시간에 트리거 될 수 있도록 이벤트 브릿지 규칙을 생성합니다. 람다 함수 개요 화면에서 트리거 추가를 클릭한 뒤 아래와 같이 내용을 입력합니다.

Alert_Budget9

예약 표현식에는 크론 표현식을 작성하며 UTC 기준으로 한국 시간 +9시간이므로 0 0으로 설정하여 한국 시간 기준으로 오전 9시마다 람다 함수가 트리거되어 텔레그램 API 서버로부터 받은 응답을 가공하여 CHAT_ID로 등록된 채팅방에 해당 메시지를 전송하게 됩니다. 위 트리거는 이벤트 브릿지의 규칙란에서 편집하여 시간을 수정할 수 있습니다.

Alert_Budget10

이벤트 버스 규칙이 잘 작동되나 확인하기 위해서 규칙을 두 개 생성한 뒤에 하나는 오전 9시, 다른 하나는 람다를 생성하고 있었을 때의 시간에 2분을 더하여 트리거되도록 설정한 규칙입니다.

Alert_Budget11

람다가 정상적으로 트리거 되어 채팅방에 메시지를 보내는 모습입니다 !