관리 메뉴

지나가는 이야기

[AWS+Telegram] 텔레그램 봇을 이용한 AWS 비용 확인 자동화 본문

Event & Project : 이벤트 & 프로젝트/Project : 프로젝트

[AWS+Telegram] 텔레그램 봇을 이용한 AWS 비용 확인 자동화

지나가는 이야기 2024. 4. 5. 12:47
728x90
반응형

 

 

# 서론

AWS를 사용하다 보면 현재 얼마의 비용을 사용했는지 꼭 체크가 필요하다. 그 이유는 갑자기 KEY 유출로 인한 비용 급등 등 예기치 못한 비용 증가를 보다 조기에 발견할 수 있고, 자신이 지금까지 사용한 금액을 보면서 어느 정도 관리를 할 수 있기 때문이다.

현재 텔레그램 봇과 AWS의 람다 함수를 이용하여 비용을 확인하는 것을 채팅으로 자동화할 수 있어 자동화 설정을 해본다.

(AWS와 텔레그램 계정이 둘 다 있다는 가정에 진행한다.)

 

 

# 텔레그램 봇을 이용한 AWS 비용 확인 자동화

자동화로 불러올 정보는 위 사진과 같이, 환율, 현재까지 금액에 대한 정보이다.

 

 

## 1. 환율 설정

https://www.exchangerate-api.com/

 

ExchangeRate-API - Free & Pro Currency Converter API

Get the data you need from our exchange rate API - it's perfect for spreadsheets, apps, SaaS, E-Commerce and more!

www.exchangerate-api.com

먼저 환율에 대한 정보를 불러오기 위해 위 사이트에 회원가입을 하여 API Key를 발급받는다.

 

위 사진에서 Get Free Key! 버튼을 누르게 되면 이메일을 통한 회원가입을 할 수 있다.

 

회원 가입을 하면 위 사진에 보이듯이 API Key와 한 달에 최대 1,500번 호출할 수 있다는 내용도 보인다. 매일 한 번씩 호출하기 때문에 1,500번은 충분하여 따로 플랜을 구매할 필요는 없다. API Key 값을 복사한다.

 

 

 

 

 

 

## 텔레그램 설정

텔레그램 설정의 경우 iOS, Android에 따라 UI가 달라 헷갈릴 수 있지만 흐름은 같기 때문에 잘 보고 설정하면 된다.

(본문의 경우 iOS 기준)

 

먼저 봇을 만들기 위해 위 사진과 같이 @botfather을 검색한다.

 

그 후 위 사진 화면이 나오게 되는데 Start 버튼을 눌러 채팅을 시작한다.

 

채팅을 시작하면 위 사진과 같이 BotFather이 무엇인가 많이 보내는데 다 무시하면 된다.

 

/newbot			# 새로운 봇 생성
aws_Username		# aws_계정이름, 봇의 이름
aws_Username_bot	# aws_계정이름_bot, 봇의 id로 무조건 마지막에 bot로 끝나야 됨

봇을 만드는 방법은 위와 같으며 채팅을 통해 만들 수 있다. 먼저 /newbot 명령을 통해 새로운 봇을 생성한 후 자신만의 봇 이름을 정한다. 본문의 경우 봇의 이름은 aws_Username으로 진행했으며, 마지막으로 bot의 id를 정해야 하는데 무조건 bot으로 끝나야 하기 때문에 봇 이름 뒤에 _bot을 추가한다.

이렇게 봇을 생성하면 위 사진에 보이듯이 HTTP API가 나오게 되는데 따로 저장한다. 특수문자 등이 포함되어 있을 수 있으므로 쉽게 Keep your token 이전까지 나온 모든 문자들이 API TOKEN이며 따로 복사하여 저장한다.

 

이제 알림을 받을 그룹을 만들면 된다.

 

위 사진과 같이 우측 상단의 버튼을 클릭한다.

 

 

위 사진은 직후의 사진으로 New Group 버튼을 통해 그룹을 생성한다.

 

그룹을 생성할 때 우리는 2명을 추가로 초대할 건데 먼저 위 사진과 같이 이전에 만들었던 봇(@aws_Username)을 검색하여 가지고 온다.

 

그리고 @get_id_bot을 추가해야 하는데 해당 계정의 경우 현재 그룹 방의 id를 가지고 오기 위함이다. 프로필 사진을 잘 확인하여 헷갈리지 않게 유의하여 Next 버튼을 누른다.

 

인원 추가를 했으면 위 사진과 같이 그룹의 이름을 정하는 것인데 쉽게 AWS Cost로 설정한다.

 

위 사진은 생성된 그룹이다. 여기서 그룹 방의 id가 필요하기 때문에 @get_id_bot을 불러온다.

여기서 주의할 점은 터치를 통해 불러오게 되면 채팅을 보내는 기능이 안 된다. 그 이유는 @get_id_bot 뒤에 한 칸의 공백이 들어가기 때문에 직접 해당 계정을 다 작성하거나 @get 했을 때 터치를 하여 자동으로 불러온 뒤 한 칸의 공백을 지우면 호출할 수 있다. 또한 호출을 한 후 즉각적으로 답을 안 할 수 있기 때문제 바로 답장이 오지 않더라도 기다리면 된다. 경험상 24시간 이내에는 응답한다.

 

위 사진은 @get_id_bot이 응답한 후의 모습으로 처음에 나오는 내용은 별로 중요한 내용이 아니기 때문에 스크롤을 내린다.

 

스크롤을 내리다 보면 위 사진과 같이 Your group Chat ID 부분이 보인다. 여기서 중요한 것은 ID 숫자 앞에 - 기호가 있는데 해당 기호도 포함한 것이 ID 값이다. 이를 주의해서 -를 포함하여 따로 복사한다. 이후 get_id_bot의 경우 방에서 추방해도 된다.

 

이렇게 총 3개의 값이 있어야 한다.

1. 환율 정보를 얻기 위한 API KEY

2. 봇의 TOKEN

3. Group Chat ID

 

 

 

 

 

 

## AWS 설정

AWS에 접속하여 Lambda로 검색한 후 새로운 함수를 생성한다.

 

위 사진과 같이 세팅을 하고, 함수 이름의 경우 aws_Username_Daily_Cost_Report로 설정한다. 그리고 Python을 이용하여 자동화를 할 예정이기 때문에 런타임을 Python으로 설정한 후 함수를 생성한다.

 

위 사진은 함수를 생성한 직후의 모습이다. 자동화 코드를 작성하기 전 기본적인 설정을 해야 하기 때문에 Configuration으로 이동한다.

 

 

 

 

 

 

제일 먼저 수정해야 하는 것은 General configuration이다. 위 사진과 같이 Edit 버튼을 눌러 수정한다.

 

위 사진과 같이 15초로 설정한 후 Save를 눌러서 저장한다. 해당 시간의 경우 람다 함수가 동작하는 최대 시간을 의미한다. 자동화 코드를 실행하다 보면 3초 이내에 동작되는 경우가 드물기 때문에 시간을 15초로 넉넉하게 늘려야 한다.

 

다음으로 권한에 대해 수정한다 위 사진과 같이 PemissionsRole name을 클릭한다.

 

클릭하게 되면 위 사진과 같이 Create inline policy를 추가적으로 생성한다.

 

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

위 사진과 같이 JSON을 들어가서 설정하면 된다. 해당 코드의 뜻은 계정의 비용에 대해 람다가 접근하기 위한 권한이다. 코드를 수정하는 부분은 2줄이지만 헷갈릴 거 같으면 위 코드를 복사해서 붙여 넣은 후 Next를 눌러 다음으로 넘어간다.

 

그다음은 위 사진과 같이 해당 룰의 이름을 정해야 한다. aws_Username_Get_Cost_Usage로 설정한 후 생성한다.

 

룰을 생성하면 위 사진과 같이 Policy 부분에 2개가 있으면 정상적으로 설정된 것이다.

 

그다음으로는 함수 내부에 사용할 변수를 설정해야 한다. Environment variables로 들어가 Edit을 눌러 변수를 설정한다.

 

변수의 경우 이전에 저장한 3가지

1. 환율 정보를 얻기 위한 API KEY [API_KEY]

2. 봇의 TOKEN [TOKEN]

3. Group Chat ID [GROUP_ID]

를 위 사진과 같이 저장한 후 Save 버튼을 눌러 저장한다. 주의할 점은 Group ID의 경우 - 기호를 포함해야 한다.

이제 코드를 작성할 차례이다.

 

import datetime
import os
import json
import boto3
from dateutil import relativedelta
import urllib.request
import urllib.parse as parse

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

def get_exchange_rate(api_key):
    url = f"https://v6.exchangerate-api.com/v6/{api_key}/pair/USD/KRW"
    with urllib.request.urlopen(url) as response:
        source = response.read().decode("utf-8")
        data = json.loads(source)
        exchange_rate = data["conversion_rate"]
        return exchange_rate

def month_to_date_cost(start, end):
    client = boto3.client("ce")
    response = client.get_cost_and_usage(
        TimePeriod={"Start": start, "End": end},
        Granularity="MONTHLY",
        Metrics=["UnblendedCost"]
    )
    amount = response["ResultsByTime"][0]["Total"]["UnblendedCost"]["Amount"]
    output = "%.2f" % float(amount)
    return str(output)

def lambda_handler(event, context):
    exchange = get_exchange_rate(API_KEY)

    this_month = datetime.datetime.today()
    next_month = this_month + relativedelta.relativedelta(months=1)
    this_month_start = this_month.strftime("%Y-%m-01")
    next_month_start = next_month.strftime("%Y-%m-01")
    total_cost = month_to_date_cost(this_month_start, next_month_start)
    
    total_cost_dollar = float(total_cost)
    total_cost_dollar_formatted = "{:,.2f}".format(total_cost_dollar)
    
    total_cost_main = int(float(total_cost) * exchange)
    total_cost_main_formatted = format(total_cost_main, ',')

    ### Telegram message ###
    message = "[ AWS Cost(Daily) ]\n" \
              + this_month.strftime("● Date : %B-%d-%Y\n") \
              + "● Account : Username\n" \
              + "● Exchange Rate : ₩" + str(exchange) + "\n" \
              + "● Cost(₩) : ₩" + str(total_cost_main_formatted) + " (Month)\n" \
              + "● Cost($) : $" + str(total_cost_dollar_formatted) + " (Month)"

    try:
        data = parse.urlencode({
            "chat_id": GROUP_ID,
            "text": message,
            "parse_mode": "Markdown"
        }).encode()
        req = urllib.request.Request(TELEGRAM_URL, data=data)
        with urllib.request.urlopen(req) as response:
            response.read()
    except Exception as e:
        print(e)

위 사진과 같이 코드 부분으로 들어간 후 코드 전체를 복사하여 붙여 넣는다. 여기서 해당 코드를 저장하기 위해 Deploy를 클릭한 후 Test를 진행한다.

 

Deploy를 누른 후 Test 버튼을 클릭하면 위  사진과 같이 나오는데 이벤트 이름을 TEST로 설정한 후 저장한다. 그리고 다시 Test 버튼을 눌러 코드를 테스트하면 된다.

 

변수 설정 및 코드를 제대로 수정했다면 위 사진과 같이 성공이라고 나오게 되며

 

위 사진과 같이 텔레그램 방에서도 정상적으로 보인다. 실제 금액의 경우 AWS에서 확인하여 동일한지 꼭 확인한다. 동일한 것을 확인했다면 이제 해당 알림을 정기적으로 받는 것을 설정한다.

 

 

 

 

 

 

위 사진과 같이 Add trigger을 클릭한다. 

 

위 사진은 Add trigger을 클릭한 이후의 모습으로 여기서 EventBridge를 선택한다.

 

선택을 하게 되면 위와 같이 룰을 설정하는 것이 있는데 룰의 이름은 aws_Username_Daily로 한 후 Schedule expression으로 하여 cron 설정을 하면 된다. 일단 cron(0 0 * * ? *)로 설정을 하고 추가한다. 시간대 설정을 이후 다시 진행한다.

 

추가를 하면 위 사진과 같이 트리거 추가가 되며 시간을 다시 수정하기 위해 룰의 이름을 클릭한다.

 

룰 이름을 클릭한 후 Edit 버튼을 눌러 시간 수정을 한다.

 

시간 수정을 하기 전 먼저 Local time zone로 설정을 하고 cron의 다른 숫자는 변경하기 말고 분과 시간만 수정하여 원하는 시간대로 설정하면 된다. 다른 값들을 수정하는 경우 매일 알림이 오지 않기 때문에 분 또는 시간만 수정한 후 Next 버튼을 누른다.

 

그다음 수정하는 것의 경우 변경할 게 없어 바로 Next 버튼을 누른다.

 

다음 부분 또한 수정할 게 없어 그대로 Next 버튼을 누른다.

 

마지막의 경우 변경한 설정을 확인하는 것이라 업데이트를 하면 이제 자신이 원하는 시간대에 텔레그램 채팅으로 현재 비용을 알 수 있다.

 

 

 

728x90
반응형
Comments