はじめに
AWSのコスト分析には通常、Cost Explorer が利用されますが、複数のAWSアカウントを調査する際には各アカウントにログインする必要があります。
そこで、この記事では Cost and Usage Report(以下:CUR)のデータを S3 に保存し、Athena で分析する仕組みを作成します。
仕事では Terraform を使用することが多いため、本記事では Terraform で設定します。
今回作成するサービスとアーキテクチャ
背景
通常 CUR のデータを Athena を使って分析したい場合、以下のドキュメントやブログを参考にすれば、Cloud Formation で分析する仕組みを作成できます。
Cloud Formation で作成できるアーキテクチャ
ブログは 2019 年に発表されており、Glue クローラーのクローリングの設定は Crawl all sub-folders (すべてのサブフォルダをクローリング)
になっています。
2021 年 10 月から AWS Glue のクローラーが Amazon S3 イベント通知をサポートされ、さらに以下のブログやニュースを読むと、2022 年 10 月に増分クローリングが発表されたことにより、クロール時間とクローラーの実行に必要なデータ処理ユニット(DPU)を削減する方法が紹介されています。
これらの仕組みを Terraform で実現している記事が見当たらなかったので、コードと一緒に記事を書くことにしました。
この記事では、ステップ・バイ・ステップでリソースを作成するため、Terraform のリソースはすべて main.tf ファイルに書いていきます。
バージョン
成果物
最終的に完成したコード(リファクタバージョン)は以下の GitHub に置いておきます。
https://github.com/kntks/blog-code/tree/main/2023/07/terraform-cur-athena
準備
CUR の配信設定
S3 バケットを作成する
CUR のレポート配信先となる S3 バケットに必要な設定を確認してみます。
このときバケットを新規に作成するか、既存のバケットかを選択できます。
どちらかを選択しても、バケットポリシーを表示してもらえます。
バケットポリシーもわかったので、Terraform で S3 を作成します。
※いくつか値は伏せています。
バケットポリシー
```json
{
"Version": "2008-10-17",
"Id": "Policy1335892530063",
"Statement": [
{
"Sid": "Stmt1335892150622",
"Effect": "Allow",
"Principal": {
"Service": "billingreports.amazonaws.com"
},
"Action": [
"s3:GetBucketAcl",
"s3:GetBucketPolicy"
],
"Resource": "arn:aws:s3:::(レポート名)",
"Condition": {
"StringEquals": {
"aws:SourceArn": "arn:aws:cur:us-east-1:(AWSアカウントID):definition/*",
"aws:SourceAccount": "(AWSアカウントID)"
}
}
},
{
"Sid": "Stmt1335892526596",
"Effect": "Allow",
"Principal": {
"Service": "billingreports.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::(レポート名)/*",
"Condition": {
"StringEquals": {
"aws:SourceArn": "arn:aws:cur:us-east-1:(AWSアカウントID):definition/*",
"aws:SourceAccount": "(AWSアカウントID)"
}
}
}
]
}
```
main.tf
CURを作成する
先ほど、S3 を作成しました。次に CUR を設定します。
AWSのリソースは基本 ap-northeast-1
に作成しますが、 CUR は us-east-1
に作成します。
Terraform でこういったケースでは Multiple Provider Configurations を利用するとリージョンを CUR のみ us-east-1
にできます。
providerを追加します。
Resource: aws_cur_report_definition - registry.terraform.io
これで CUR のデータが配信されると S3 バケットの <bucket-name>/<s3_prefix>/<report-name>/<report-name>/year=20xx/month=x/xxxx.parquet
ができます。
ちなみに”背景”でお伝えしたCloud Formation のファイルは <bucket-name>/<s3_prefix>/<report-name>/crawler-cfn.yml
です。
Glue データカタログとクローラー
Glueのデータベースを作成する
ここでは以下のリソースを作成します。
- Glue Catalog database
- Athena workgroup
まず Glue データベースを作成します。
以下を追記します。
Resource: aws_glue_catalog_database
(オプション) ワークグループを作成する
必要に応じてワークグループを作成してください。
ワークグループを作成するとクエリ実行の画面右上でワークグループを切り替えることができるようになります。
Resource: aws_athena_workgroup - registry.terraform.io
クローラーを作成する
クローラーを作成します。
クローラーの仕組み
クローラーには IAM ロールを設定する必要があるため、一緒に作成します。
main.tf
Resource: aws_glue_crawler - registry.terraform.io
terraform apply
を実行すると、IAM ロールは以下のようになります。
クローラーを実行してみる
手動でクローラーを実行してみます。 ドキュメント通りならテーブルが作成されるはずです。
クローラーは 1 回の実行で複数のデータストアをクロールできます。完了すると、クローラーはデータカタログで 1 つ以上のテーブルを作成または更新します
引用:AWS Glue でのクローラーの定義 - AWS Documentation
成功後、Glue と Athena のページでテーブルを確認できました。
試しにクエリを実行してみると、データをとれていそうです。
データカタログの自動更新設定
S3のPutイベントでクローラーを起動する
先ほどクローラーを手動実行することで、Athena からデータを確認することができました。
しかし、これでは最新の情報を取得することができません。
定期実行でクローラーが起動されるようにします。
ここからは S3 のイベント通知を利用して、クローラーを実行できるように設定します。
SQSのキューとデッドレターキューを作成し、クローラーが S3 イベントによって起動するように設定を変更します。
main.tf
参考:https://github.com/hashicorp/terraform-provider-aws/issues/22577#issuecomment-1086122047
設定完了したらマネジメントコンソールから設定を確認してみます。
Subsequent crawler runs
の項目が Crawl based on events
になっています。
SQS も設定されていることが確認できます。
S3 にイベント通知を設定する
最後に S3 のイベント通知を SQS に送信できるように設定します。
SQS にはキューにアクセスできるポリシーを設定する必要があるので、ポリシーを作成し、キューに設定します。
Resource: aws_s3_bucket_notification
s3 バケットのプロパティをクリックします。
ページを下にスクロールするとイベント通知の設定を見ることができます。
参考:
クローラーを定期実行させる
クローラーがすべてのファイルをクローリングするなら、クローリングの間隔を短くすればするほどコストがかかるはずです。
しかし、今回はAmazon S3 イベント通知を使用した加速クロールを利用し、クロールコストが削減されるようにしたのでクローリングの間隔は短くても問題なさそうです。
今回は、3 時間に 1 回定期実行しようと思います。以下の設定では、午前 0時から3時間毎に実行します。
これで完成です。
動作確認
最後にS3にオブジェクトが作成されたらクローラーが動作するのか確認します。(すでに CUR が配信されており、S3 にデータがあるとします。)
S3 イベント作成後、手動で実行する
動作確認方法
- S3 から CUR のデータをダウンロードする
- S3 から CUR のデータを削除する
- 削除したデータが存在していたディレクトリに、ダウンロードしたデータをアップロードする
SQS にメッセージが入っていることを確認できます。
手動でクローラーを実行すると、問題なく実行されました。
SQS にデータがない状態で、クローラーを手動で実行する
SQS にデータがない状態で手動実行してみると、Status = Stopped
になりました。
ドキュメント通り、キューにイベントがない場合は、実行されませんでした。
Amazon S3 イベントクロールは、クローラーのスケジュールに基づいて SQS キューから Amazon S3 イベントを使うことで実行します。キューにイベントがない場合、費用はかかりません
引用:Amazon S3 イベント通知を使用した加速クロール - AWS Documentation
最後に
作成したファイルはこんな感じです。実装の参考になれば幸いです。
main.tf