エムオーテックス株式会社が運営するテックブログです。

AWS Cost and Usage Reportsを活用したコスト可視化の取り組み

はじめに

こんにちは、インフラチーム改め、SREチームの植松です。

以前の記事にてチームで取り組んでいるAWSコストのモニタリングや、コスト最適化のために取り組んでいることを紹介しました。
今回はそこからのアップデートとして、AWS Cost and Usage Reportsと呼ばれるサービスを活用した可視化の取り組みをご紹介したいと思います。

tech.motex.co.jp

AWS Cost and Usage Reports(CUR)とは

AWSコストに関する詳細なデータをS3に出力してくれるサービスです。AWS曰く「最も包括的なコストと使用状況のデータ」であり、その名の通り200以上のカラムからなるcsvデータを出力します。

デフォルトではこの機能は無効で、使いたい場合は有効化作業が必要です。時間単位、日単位、月単位の集計が可能で、エムオーテックスでは日単位で集計しています。

docs.aws.amazon.com

CURと他のサービスとの連携

ExcelやOpenOffice CalcなどでCURを表示することも可能ではありますが、QuickSightやAthenaと連携することで効率的にコストの可視化や分析が可能になります。ここから、CURを活用したコスト可視化の構成や、実際の活用例を紹介していきます。

可視化基盤の構成

エムオーテックスでは開発、ステージング、本番環境・・・などの用途別にAWSアカウントを分離しており、アカウントの管理はAWS Organizationsで行っています。OrganizationsのルートアカウントでCURを有効化することで配下のアカウント全てのコストデータを取得できます。
ルートアカウントのCURをアカウントにレプリケーションし、QuickSightでのダッシュボード、Athenaでの検索ができるように設定しています。

QuickSightやAthenaを見られるように、IAM Identity Centerで開発メンバー全員にアーカイブアカウントの閲覧権限を付与しています。

可視化基盤の構成図

より詳細な構築手順は以下のページが参考になります。 catalog.workshops.aws

QuickSight

QuickSightにはSQLのクエリ結果をデータソースとする機能があります。

半年以上の期間を遡っての可視化・分析はAthenaで行いたい、QuickSightに取り込むデータも課金対象なので、なるべくコストを抑えたいという理由で、CURを半年分取得してダッシュボードを構築するような運用をしています。

エムオーテックスで運用しているコストダッシュボード

AWSアカウント別のコスト

横軸を日付、縦軸をコスト、AWSサービス名でグループ化したグラフをAWSアカウントごとに作成しています。Cost Explorerでも同様のグラフは出せますが、ダッシュボード化しておくことでコスト異常があれば一目ですぐに気づけるようになります。

サービス別のコスト

コストが特に高いAWSサービスについては、個別にグラフを作成しています。横軸が日付、縦軸がコスト、AWSリソース名でグループ化しています。アカウント別と同様にCost Explorerでも見ることは可能ですが、あらかじめグラフを用意しておくことでコスト異常の発見や調査をスムーズに行えるようになります。

Athena

発見したコスト異常の原因分析や、過去に遡ってサービス別のコスト推移を分析したい時などにAthenaによるCUR分析をしています。

よく使うカラム

CURのカラムは非常に多く、私自身も全てを把握しているわけではないですが分析でよく使っているカラムは以下になります。

カラム名 概要
line_item_usage_account_id コストが発生したアカウントIDを指します。OrganizationsのルートアカウントにCURを適用した場合は、管理アカウントもしくはメンバーアカウントの値が記録されます。
line_item_product_code コストが発生したAWSサービス名を指します。例えばS3の場合はAmazonS3が、Lambdaの場合はAWSLambdaが記録されます。
line_item_operation コストが発生したAPIオペレーションを指します。CloudWatchのログ取り込みなら​PutLogEvents、EC2起動ならRunInstancesが記録されます。
line_item_resource_id コストが発生したサービスのリソース名が記録されます。コストが高いリソースのランキングを出したり、リソースを絞って月毎の推移を見たい時などに使っています。各AWSサービスに対して具体的にどのようなフォーマットで記録されるかは、以下が参考になります。

明細項目の詳細 - AWS コストと使用状況レポート
line_item_usage_start_date コストが発生した日付が記録されています。
year 見たままですが、コストが発生した年が記録されます。
month これも見たままですが、月が記録されます。
line_item_unblended_cost リザーブドインスタンス(RI)やSavings Plansの割引を含めないコストが記録されます。割引後のコストのみだとコスト異常を見逃す場合があるため、こちらの値を主に確認しています。

クエリ例

コスト分析でよく使っているクエリをご紹介したいと思います。

特定リソースのコスト推移を確認する

あるAWSリソースの月毎のコスト推移を確認したい時に以下のクエリを使っています。例はLambdaとしていますが、line_item_product_codeを変えることで他のサービスにも適用できます。Cost Explorerでも同じことはできますが、Athenaだと即座に確認できます。

SELECT
    month,
    SUM(line_item_unblended_cost) AS cost
FROM cur WHERE
year = '2023'  
AND line_item_resource_id like '%YOUR RESOURCE ID%'
AND line_item_product_code = 'AWSLambda'
GROUP BY month

本番環境よりコストが高い開発環境のリソースを抽出する

Cost Explorerではできない例を紹介します。

以下は、本番よりコストが高い開発のリソースを抽出するクエリになります。ざっくりした例ですが本番リソースはhogehoge-prod、開発リソースはhogehoge-devのような命名規則になっているため、JOINしてコスト比較ができます。

あるリソースのコストが、開発 > 本番となることはほぼありません。このクエリを実行することで、例えばLambdaが予想外に呼び出されてるであったり、開発のS3にゴミデータが溜まっているというようなコスト異常の検出ができるようになりました。

SELECT dev.resource_name AS "リソース名",
    dev.cost as dev_cost,
    prod.cost prod_cost,
    dev.cost - prod.cost AS cost_diff
FROM (
        SELECT SUBSTRING(
                resource_tags_user_r_e_s_o_u_r_c_e
                FROM 1 FOR POSITION('-dev' IN resource_tags_user_r_e_s_o_u_r_c_e) - 1
            ) AS resource_name,
            SUM(line_item_unblended_cost) AS cost
        FROM cur
        WHERE resource_tags_user_r_e_s_o_u_r_c_e LIKE '%-dev'
        and date_format(line_item_usage_start_date, ('%Y-%M')) = date_format(now() - interval '1' MONTH, ('%Y-%M'))

        GROUP BY resource_tags_user_r_e_s_o_u_r_c_e
    ) AS dev
    JOIN (
        SELECT SUBSTRING(
                resource_tags_user_r_e_s_o_u_r_c_e
                FROM 1 FOR POSITION('-prod' IN resource_tags_user_r_e_s_o_u_r_c_e) - 1
            ) AS resource_name,
            SUM(line_item_unblended_cost) AS cost
        FROM cur
        WHERE resource_tags_user_r_e_s_o_u_r_c_e LIKE '%-prod'
        and date_format(line_item_usage_start_date, ('%Y-%M')) = date_format(now() - interval '1' MONTH, ('%Y-%M'))

        GROUP BY resource_tags_user_r_e_s_o_u_r_c_e
    ) AS prod ON dev.resource_name = prod.resource_name
where (dev.cost - prod.cost) >= 0
and dev.cost >= 1

終わりに

QuickSightとAthenaを利用した、AWSコスト可視化の仕組みをご紹介しました。

AWSコストのモニタリングなどに関わっている方の参考になれば幸いです。