LoginSignup
56
59

More than 3 years have passed since last update.

AWS利用金額と予測請求金額を日次で自動通知する

Last updated at Posted at 2019-09-07

はじめに

今回はLambdaでget_cost_and_usage(),get_cost_forecast()
のメソッドを使ってAWS利用金額と予測請求金額を取得しSNSで通知するLambdaを作成しました。

各メソッドは以下のように動作します。

  • get_cost_and_usage()
    AWSの利用額を取得するメソッドです。
    2019年8月24日に8月に利用した金額を知りたい場合は、
    STARTを2019年8月1日にしてENDを2019年8月24日にします。
    すると2019年8月1日 00:00 ~ 2019年8月24日 00:00 (8月23日 24:00)の間に取得した金額が取得できます。
    なので2019年8月全体の金額を知りたい場合は、STARTを2019年8月1日にしてENDを2019年9月1日

  • get_cost_forecast()
    AWSの予測金額を取得するメソッドです。
    2019年8月24日に2019年8月の予測金額を知りたい場合は、
    STARTを2019年8月25日にしてENDを2019年9月1日(8月31日 24:00)にします。
    すると2019年8月の予測金額を取得できます。
    注意として予測なのでSTARTは明日以降の日付しか設定できません。
    本日より前の日付を指定すると以下のようなエラーメッセージが返されます。

メソッドの詳細はこちらの公式サイト

[ERROR] ClientError: An error occurred (ValidationException) when calling the GetCostForecast operation: Earliest supported Start is 2019-08-25

APIで取得可能な請求情報(通知する金額)

1日・・・前月の金額の通知と。当月の予測金額
最終日・・・それまでに利用した金額(最終日は明日が無いので当月予測金額の取得ができない)
その間・・・当月の利用金額と当月の予測請求金額

表にすると以下のような形(逆に解り難いかな???)

日程 get_cost_and_usage()の範囲 get_cost_forecast()の範囲
1日 前月の1日から当月の1日(前月最終の 24:00)で前月の用金額 明日から来月初め(月末24:00)まで利用した場合の予測金額
最終日 当月の1日から本日までの利用金額 月末最終日=当月の明日が無いので使わない(使えない)
その間 当月の1日から本日までの利用金額 明日から来月初め(月末24:00)まで利用した場合の予測金額

事前準備

事前準備1. boto3のバージョンアップ

get_cost_forecast()を使うにはLambdaデフォルトのランタイムPython3.7のboto3のバージョンを上げる必要があります。
今回はLambda Layerを用いてboto3のバージョンを上げた状態で実行します。
※上げないとこのようなメソッド対応してないので使えませんエラーが出るなのでboto3のバージョンを上げます。

  "errorMessage": "'CostExplorer' object has no attribute 'get_cost_forecast'",
  1. Cloud9(が楽だったので)で以下のコマンドを実行しzipファイルをローカルにダウンロード
$ mkdir python
$ pip install -t ./python boto3
$ zip -r boto3.zip python

002.PNG
2. Lambdaコンソールの画面でLayersを押下
003.PNG
3. レイヤーの作成を押下
004.PNG
4. 名前の入力/先ほどCloud9からダウンロードしたzipファイルをアップロード/ランタイムを入力し作成を押下
005.PNG
5. 作成されたことを確認
006.PNG
6. LambdaのLayersを選択しレイヤーの追加を押下
007.PNG
7. 先ほど作成したレイヤーを選択し追加を押下
008.PNG

こちらの記事を参考にさせていただきました。すごくわかりやすかったです。

事前準備2. Lambdaにロールの作成と付与

  1. Lambda関数でロールを表示を押下
    009.PNG

  2. ポリシーを押下
    012.PNG

  3. ポリシーの作成を押下
    013.PNG

  4. Cost Explorer Service と SNSのポリシーを選択し以下の設定でポリシーの確認を押下
    020.PNG

  5. 名前を入力しポリシーの作成を押下
    021.PNG

  6. 最初の画面でポリシーをアタッチしますを押下
    016.PNG

  7. 先ほど作成したポリシーをチェックしポリシーのアタッチを押下
    017.PNG

  8. policyが付与されていることを確認
    018.PNG

LambdaのソースコードとCloudWatchのスケジュール

Lambdaのコードの中身は以下のようになっております。

import boto3
from datetime import date
from dateutil.relativedelta import relativedelta
ce = boto3.client('ce')
sns = boto3.client('sns')

def lambda_handler(event, context):
    today = date.today() #今日
    tomorrow = today + relativedelta(days=1) #明日
    lastmonth_first = today + relativedelta(day=1, months=-1) #先月1日
    lastmonth_end = today + relativedelta(day=1, days=-1) #先月最終
    thismonth_first = today + relativedelta(day=1) #今月1日
    thismonth_end = today + relativedelta(day=1,months=1, days=-1) #今月最後
    nextmonth_first = today + relativedelta(day=1, months=1) #来月最初

    cost_end = str(today)
    forecast_start = str(tomorrow)
    forecast_end = str(nextmonth_first)

    if today == thismonth_first:#1日
        cost_start = str(lastmonth_first)
        message_cost = get_cost(cost_start,cost_end)
        message_forecast = get_forecast(forecast_start,forecast_end)
        message = ('先月の利用金額は $'+message_cost+' で今月の利用予測金額は $'+message_forecast+' です!!')

    elif today == thismonth_end:#最終日
        cost_start = str(thismonth_first)
        message_cost = get_cost(cost_start,cost_end)
        message = ('今月の現在までの利用金額は $'+message_cost+' です!!')

    else:#他の日
        cost_start = str(thismonth_first)
        message_cost = get_cost(cost_start,cost_end)
        message_forecast = get_forecast(forecast_start,forecast_end)
        message = ('今月の現在までの利用金額は $'+message_cost+' で今月の利用予測金額は $'+message_forecast+' です!!')

    topic = 'arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:Myaddress' #送付したいARNを入力
    subject = 'AWS利用料金'
    region = '{ap-northeast-1}'
    sns_response = sns.publish(
        TopicArn=topic,
        Message=message,
        Subject=subject,
        MessageStructure='raw'
    )

def get_cost(cost_start,cost_end):
    cost = ce.get_cost_and_usage(
        TimePeriod={
            'Start': cost_start,
            'End': cost_end
        },
        Granularity='MONTHLY',
        Metrics=['UnblendedCost',],
    )
    format_cost = round(float(cost['ResultsByTime'][0]['Total']['UnblendedCost']['Amount']),2)
    return str(format_cost)

def get_forecast(forecast_start,forecast_end):
    forecast = ce.get_cost_forecast(
        TimePeriod={
            'Start': forecast_start,
            'End': forecast_end
        },
        Granularity='MONTHLY',
        Metric='UNBLENDED_COST',
    )
    format_forecast = round(float(forecast['Total']['Amount']),2)
    return str(format_forecast)

CloudWatchは以下のような設定です。
CloudWatch EventはUTCのため日次で日本時間のAM09:00に通知が来ます。
019.PNG

届いたメール

届いたメールはこんな感じです。

1日

1日.PNG

最終日

月末.PNG

その間

その間.PNG

56
59
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
56
59