🦔

AWSでやらかしたので料金をWebhook(Discord)に通知できるようにした振り返り

13 min read 1

TL;DR

目的

作成したAWSのBillingから料金を取得し、Webhook経由でDiscordに通知するプログラムをAWS Lambdaに作成し、Amazon CloudWatchで定期実行できるようにします。

方針

他の方が書いた記事に沿いながら、Discord用に書き換えて作成しました。

https://cpu100per.aminchu.net/aws/aws-cost-post-to-slack/

ソースコード

https://github.com/satory074/awscost_to_discord_sample

モチベーション


(図1) 月次コスト履歴


はじめに

  • 他の方の記事に沿いながら、Webhook(Discord)での投稿を目的として、最小限のコードになるように書き換えました。
  • 誰かの為になればと思いつつ、思い出しながら記事にしました。
  • (怪しい部分も多々あると思いますので、間違いがあったら申し訳ないです)

想定

  • AWSアカウントを作成済み
  • IAMユーザを作成済み
  • IAMユーザのアクセスキーIDとシークレットアクセスキーを控えます。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/create-access-key/

構成


1. 設定の概要

概要は参考記事と同じです。

  1. AWS BillingのBudgetsを利用
  2. 料金や予算をDiscordへ通知するAWS Lambdaを用意する
  3. 2のAWSLambdaをAmazon CloudWatchイベントで定期的に実行

2. Budgetsを作成する

参考記事と同様にAWS BillingのBudgetsを作成します。

Budgetsの名前は後ほどプログラムのlambda.jsonに記載することになります。


3. Lambdaが実行するIAM Roleを設定する

参考記事と同様に、LambdaがAWS Billingを取得できるようにIAM Role(読み書き等のアクセス権限)を作成します。

ロールARNも後ほどプログラムのlambda.jsonに記載することになります。


4. SlackのWebhook URLを取得する

ここではDiscordのWebhook URLを取得します。

  1. チャンネル一覧から、予算を投稿したいチャンネルの「チャンネルの編集」をクリック
  2. 「連携サービス」をクリック
  3. Webhookのの「ウェブフックURLをコピー」をクリックしてコピー

Webhook URLも後ほどプログラムのlambda.jsonに記載することになります。

投稿時の画像や名前はプログラムから指定可能ですので、ここでは変更してもしなくてもOKです。


2.

3.


5. Lambdaを作る

参考記事ではAWSのWeb上でLambdaを作成していますが、後ほどCLIでアップロードするため、この操作は不要かと思います。

  • 「5.1 プログラムを用意する」へ進む

5.1 プログラムを用意する

この記事用に書き換えたソースコードをGitHubに上げています。

https://github.com/satory074/awscost_to_discord_sample

以下、詰まった部分とGitHubのソースコードで書き換える部分を記載します。

5.1.1 lambda.json

データ構造

JSON Key 内容 備考
name Lambdaの関数名 (※1)
description Lambdaの関数の説明
runtime ランタイム (※2)
region lambdaを作成するリージョン 今回はアジアパシフィック(東京)に作成したのでap-northeast-1
handler ハンドラ [最初に実行する関数名].handler?
role 関数のロール 要書き換え: 手順3で控えたロールARN
timeout タイムアウト 今回はそのまま300
memory メモリ 今回はそのまま128
variables 関数を実行する為に必要な引数
accountId AWSアカウントのID(数字12桁?) 要書き換え(※3)
WebhookURL WebhookのURL 要書き換え: 手順4で控えたWebhookのURL
budgetName BudgetsのURL 要書き換え: 手順2で作成したBudgetsの名前

(※1) name
"awscost to discord"のように、nameにスペースが入っているとエラーになる。

zsh
satory074@MacBook-Pro ~/src/awscost_to_discord$ lambda-uploader
λ Building Package
λ Uploading Package
⁉️ Unexpected error. Please report this traceback.
Uploader: 1.3.0
Botocore: 1.18.38
Boto3: 1.21.38

Traceback (most recent call last):
...
    raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (ValidationException) when calling the CreateFunction operation: 1 validation error detected: Value 'awscost to discord' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?

(※2) runtime
ここでruntimeを指定しなかったため、自動的にpython2.7が選択され、後の手順でAWS CLIからアップロードするときに、requirements.txtのpip installが失敗しまくった。

zsh
satory074@MacBook-Pro ~/src/awscost_to_discord $ lambda-uploader
λ Building Package
⁉️ Unexpected error. Please report this traceback.
Uploader: 1.3.0
Botocore: 1.18.38
Boto3: 1.21.38

Traceback (most recent call last):
...
Exception: pip returned unsuccessfully

(※3) accountId
AWS画面の自分のアカウント名をクリックすると12桁の数字が出てくる

5.1.2 lambda.json

データ構造: Webhook

JSON Key 内容
username 表示名
avatar_url アイコン画像のURL
content 投稿メッセージ

Webhook経由での投稿の仕方は下記も参考にしてみてください。

https://qiita.com/Eai/items/1165d08dce9f183eac74

5.1.3 requirements.txt

そのまま書き換えなくて大丈夫だと思います。

5.2 (追記)作成したコードをLambdaにアップロード

参考記事にはありませんが、詰まったので追記しました。

方針

作成したファイルを AWS にアップロードします。
Lambda へコードをアップロードするには一度、 zip で圧縮して AWS コンソールか、 AWS CLI でアップロードします。
ただ、それだとめんどくさいので、 lambda-uploader でアップロードします。

下記アップロード手順がめんどくさくさければ、AWSのWeb上から、zipファイルを直接アップロードでも大丈夫かと思います。

やること

  1. AWS CLIのインストール(不要な手順かもしれない)
  2. lambda-uploaderのpip install
  3. AWS Lambdaにアップロード

1. AWS CLIのインストール(不要な手順かもしれない)

Macだったので、pkgファイルをインストールし、何も無ければOK連打。

https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-mac.html

AWS CLIの設定をする。

zsh
satory074@MacBook-Pro ~/src/awscost_to_discord $ aws configure
AWS Access Key ID [****************QNCB]:
AWS Secret Access Key [****************wOxm]:
Default region name [ap-northeast-1]:
Default output format [json]:
項目 内容 備考
AWS Access Key ID アクセスキーID 「想定」項目で控えているアクセスキーID: 英大文字 + 数字20桁?
AWS Secret Access Key シークレットアクセスキー 「想定」項目で控えているシークレットアクセスキー: 英大小文字 + 数字
Default region name リージョン名 とりあえずでアジアパシフィック(東京)のap-northeast-1にしています
Default output format formatタイプ とりあえずでjsonにしています

2. lambda-uploaderのpip install

zsh
satory074@MacBook-Pro ~/src/lambdatest $ pip install lambda-uploader

参考記事の「pip install lambda-uploadera」をそのままペーストして沼にはまった

参考記事のcredentialの設定はしていません(大丈夫かな)。

3. AWS Lambdaにアップロード

このようになれば正常にアップロードできています。

zsh
satory074@MacBook-Pro ~/src/awscost_to_discord $ lambda-uploader
λ Building Package
λ Uploading Package
λ Fin

6. テスト実行してみる

ボタンの位置等は若干違うかもしれませんが、参考記事と同様に、テストボタンをクリックして動作を確認します。
実行結果が成功していることと、Discordに投稿されていることを確認します。

7. CloudWatch Eventsから定期実行する

手順6で料金を通知するプログラムをAWS Lambdaに作成して実行するところまでできました。
これを定期的に実行するための設定をします。

参考記事通りにCloudWatch Eventsの設定をします。
ルールの作成は、サイドバーの「イベント > ルール」から行います。

AWSのcron式の記法は下記が参考になるかもしれません。

https://qiita.com/da-sugi/items/ef3bb45a8a99a4acacb1

私が毎日09:00に実行するよう設定したcron式は以下になります。
時差を考慮して、9時間マイナスして設定しています。

cron式
0 0 * * ? *

おわりに

不要なインスタンスやサービスは削除しよう。絶対に。


付録

未使用のAmazon RDSを起動しっぱなしにしてたおかげで無事AWSやらかし芸人になりましたが、ダメ元でAWSサポートに相談したところ、今回に限り支払いを免除して頂けることになりました!
ありがたいと同時に大変申し訳無いです...。

以下の場所からサポートにメッセージを送る形で問い合わせを行いました。

最後に、AWSのうっかり請求が1人でも減ることを願い、サポートからの返信をコピペして本記事の締めくくりと致します。

AWSサポート回答
ご担当者様

今回限りの対応となりますが、意図しない課金が発生したとのことですので、請求額の調整が可能か検討致します。
(その結果、必ず返金ができるといったお約束はできませんこと予めご留意ください)

ついては下記①②につきご対応の程宜しくお願い申し上げます。

////////////////////////////////////////////////
①意図しない課金が発生したサービスおよび期間
////////////////////////////////////////////////

意図しない課金が発生したサービスと期間を確認させていただきたく存じます。
例:「EC2:〇月〇日から×月×日まで」、「RDS:△月の課金すべて」等

意図しない課金は以下と認識しておりますが、念のため確認させていただきたくよろしくお願い申し上げます。

「RDS:2021年8、9月の課金すべて」

////////////////////////////////////////////////
②リソースの削除に関して
////////////////////////////////////////////////

本アカウント状況を確認しましたところ、下記のリソースがございました。
ご確認の上は、不要なものは削除くださいますようお願い申し上げます。

・A
---------------------------------------
サービス:RDS
リージョン:東京
リソース:DBインスタンス×2、スナップショット×1
---------------------------------------

RDSマネジメントコンソール(東京):https://ap-northeast-1.console.aws.amazon.com/rds/home?region=ap-northeast-1#

(ご参考ページ)Amazon RDS リソースを削除または終了するにはどうすればよいですか?
 https://aws.amazon.com/jp/premiumsupport/knowledge-center/delete-terminate-rds/

・B
---------------------------------------
サービス:Route53
リソース:ホストゾーン×1
---------------------------------------

Route53マネジメントコンソール:https://console.aws.amazon.com/route53/v2/home#Dashboard

(ご参考ページ)Route 53 ホストゾーンを削除する方法を教えてください。
 https://aws.amazon.com/jp/premiumsupport/knowledge-center/delete-hosted-zone/

////////////////////////////////////////////////
■請求書ページ
////////////////////////////////////////////////

下記ページにて課金の詳細をご確認いただけます。

▼請求書ページ
https://console.aws.amazon.com/billing/home?#/bill?year
※課金状況の詳細につきましては、『+すべて展開』によりご確認いただけます。
※請求書ページは即時反映ではございません。次回の反映に24時間程度要する場合がございます。

なお、AWS の課金体系として、実際のご利用有無に関わらず、リソースが削除されず稼動しておりますと稼働時間や保持している容量に対して料金が発生してまいります。
そのため今後のご利用におかれまして十分ご注意いただきますようお願い申し上げます。
※リソースやアカウントの管理はお客様の責任のもと行っていただく必要がございます。不要なリソースはお客様にて適宜削除いただきますようお願い申し上げます。

////////////////////////////////////////////////
■利用状況のモニタリング等について
////////////////////////////////////////////////

既にBudgetsをご設定いただいたとのことでございますが、モニタリングについての一般的なご案内についても以下の通り記載いたします。

CloudWatch [参考1] にて請求アラートを作成いただき利用状況をモニタリングいただくことを推奨いたしております。
また AWS Budgets [参考2および3] を利用いただくことで予想されるコストがお客様の作成した予算を上回る場合や予算を超えた場合にアラートを通知するよう設定いただけます。
CloudTrail [参考4] では S3 の料金が発生いたしますが、アカウントアクティビティをログに記録し、こちらのイベント履歴によりセキュリティ分析やリソース変更の追跡、トラブルシューティングをより簡単に実行いただけます。
これらの機能をご活用いただき、今後 AWS の運用にお役立ていただけますようお願い申し上げます。

[参考1] https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/monitor_estimated_charges_with_cloudwatch.html
[参考2] https://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/budgets-managing-costs.html
[参考3] https://aws.amazon.com/jp/getting-started/tutorials/control-your-costs-free-tier-budgets/
[参考4] https://aws.amazon.com/cloudtrail/getting-started/

////////////////////////////////////////////////
■『責任共有モデル』と『AWS カスタマーアグリーメント』
////////////////////////////////////////////////

大変恐縮ではございますが、AWS では責任共有モデルを採用させていただいており、アカウントやリソースの管理はお客様の責任範囲に該当いたします。
また、カスタマーアグリーメントでは発生理由を問わず、お客様が管理するアカウント上で発生した
すべてのアクティビティについてお客様が責任を負うことが規定されております。

・責任共有モデル
https://aws.amazon.com/jp/compliance/shared-responsibility-model/

・AWS カスタマーアグリーメント
https://aws.amazon.com/agreement/

上記により、意図されずに発生したご利用料金であっても必ず減免ができるといったお約束は出来かねますので、その旨を予めご承知おきいただけますと幸いでございます。

それではご返信の程宜しくお願い申し上げます。

深井
Amazon Web Services
今回の担当者の対応は適切でしたでしょうか?よろしければ下記リンクから5段階でご評価ください。
=======================================

このメールの内容に関して返信をされたい場合は以下のURLからAWS Support Centerへアクセスしてください。
https://console.aws.amazon.com/support/home#/case/?displayId=2244888593&language=ja
(フェデレーティッドユーザーをご利用の場合には、リンクを開く前にログインしてください)

*注意:このe-mailは返信を受け付けておりません。この件について再び連絡を取りたい場合は上記のリンクからアクセスして頂く必要があります。

------------------------------------------------------------------------------------------------
導入に関する日本担当チームへのお問い合わせ
AWS クラウド導入に関する構成相談・お見積りなど担当者からの連絡をご希望のお客様は、以下のフォームよりお気軽にご相談ください。
http://amzn.to/1VsmaYG

AWS国内のクラウドセミナー・イベントスケジュールはこちら
http://amzn.to/24tSPAt

AWSオンラインセミナー・トレーニングスケジュールはこちら
http://amzn.to/1U87f75
------------------------------------------------------------------------------------------------

Amazon Web Services, Inc. は Amazon.com, Inc. の関連会社です。Amazon.comはAmazon.com, Inc.

またはその関連会社の登録商標です。
GitHubで編集を提案

Discussion

credential のところですが、 direnv を使って設定するとディレクトリごとに環境変数が定義できるんです。
毎回 aws configure する必要なくなって便利!って話だと思いますよ。

https://dev.classmethod.jp/articles/direnv/
ログインするとコメントできます