MNTSQ Techブログ

「MNTSQ(モンテスキュー)」のTechブログです。

Claude Code に AWS コストを PR 上で試算させる

MNTSQ Tech Blog TOP > 記事一覧 > Claude Code に AWS コストを PR 上で試算させる

はじめに

弊社では AWS 上にマルチテナント構成のインフラを複数の環境にわたって運用しており、その構成管理を Terraform でおこなっています。インフラ側のリソース構成はもちろんのこと、アプリケーション側で管理されている ECS タスク定義の CPU / メモリ割り当てに対しても、折に触れて変更が入ります。

こうしたリソース変更は無論コストに跳ねます。新規コンポーネントの追加やインスタンスサイズの変更が Pull Request(以下 PR、サービスによっては Merge Request 等の呼称もあります)として上がってくるたびに「で、これは月いくら増えるのか?」という問いが生じるわけですが、これまでは手動で料金表を引いて試算するか、試算そのものをおこなわずにマージしてしまうかの二択という格好でした。

本稿では、この問題を Claude Code による自動コスト試算で解決した取り組みと、それを GitHub Actions の Reusable Workflow 構成で全社の主要リポジトリに横展開した方法について紹介します。

モチベーション

きっかけは社内 Slack で「新規コンポーネント追加やリソース割り当て変更の際には、コスト見積もりもセットでおこなう運用にしたい」という声が上がったことです。

ただし、PR のたびに人の手でコスト試算をおこなうというやり方には、以下のような難点が付きまといます。

  • 属人的:試算する向きによって精度にバラつきが出る
  • 忘れがち:「あとでやろう」が「やらなかった」に帰結しがち
  • 骨が折れる:AWS の料金表を引いて、リソース変更の前後差分を計算して、PR にコメントして……という作業を手でやるのは地味に骨が折れる

一方で弊社では Claude Code による PR レビューの自動化を既に導入しており、レビューワークフローの横に「コスト試算」ワークフローを並べるのは自然な延長線上にありました。PR の変更内容からリソースの追加・変更・削除を読み取り料金に照らすような作業は、まさに LLM が得意とする領域です。

実装

インフラリポジトリ(Terraform 変更)

最初の実装はインフラリポジトリに対してのものです。既存のコードレビューワークフロー(claude-code-review.yml)とは別ワークフローとして claude-code-cost-estimate.yml を新設しています。

name: Claude Code Cost Estimate

on:
  pull_request:
    types: [opened, synchronize, ready_for_review]
    branches: [main]
    paths:
      - 'terraform/**'

concurrency:
  group: claude-cost-estimate-${{ github.event.pull_request.number }}
  cancel-in-progress: true

なお paths:terraform/** を指定しているのは、このリポジトリでは Terraform コードを terraform/ 配下にまとめる構成を採っているためです。Terraform に触れない PR ではワークフロー自体が発火しません。

レビューとコスト試算を分離したことの嬉しさは以下の通りです。

  • レビューコメントとコスト試算コメントが混在しない
  • Terraform に触れない PR ではスキップされる
  • concurrency group が独立しているため互いにブロックしない

ワークフロー内では Claude Code CLI を直接インストールし、プロンプトをファイル経由で渡す方式を採っています。当初は anthropics/claude-code-action を使用していたのですが、2026 年 4 月中旬頃から本ワークフローの実行が継続的に失敗する事象に遭遇し1、切り分けを重ねた末に回避策として CLI 直接実行方式へ切り替えました。

プロンプトの骨子は以下です。

  1. gh pr diff で PR の差分を取得する
  2. 追加・変更・削除される AWS リソースを特定する
  3. 必要に応じて変更ファイルを Read で読み、リソースの設定値を確認する
  4. リソースのリージョン(原則 ap-northeast-1、CloudFront・WAF 等は us-east-1)に応じた料金に基づき月額コストを試算する
  5. 試算結果を PR コメントとして投稿する

試算対象のリソースについては、プロンプト内で以下のように列挙しています。

## 試算対象リソース

以下のリソースはコストインパクトが大きいため、必ず試算に含めること:

- **コンピューティング**: ECS (Fargate vCPU/メモリ), Lambda (リクエスト数/実行時間), EC2
- **データベース**: RDS (インスタンスクラス/ストレージ/Multi-AZ), ElastiCache (ノードタイプ/ノード数), DynamoDB
- **ストレージ**: S3, EBS, EFS
- **ネットワーク**: NAT Gateway ($0.062/h + データ処理料), ALB/NLB ($0.0243/h + LCU), VPC Endpoint
- **検索**: OpenSearch (インスタンスタイプ/ノード数/ストレージ)
- **監視**: CloudWatch Logs (取り込み/保存), CloudWatch Metrics/Alarms
- **CDN/グローバル**: CloudFront (リクエスト/転送量, us-east-1 料金), WAF (WebACL/ルール/リクエスト)
- **その他**: KMS (キー/リクエスト), Route53 (ホストゾーン/クエリ)

試算の際の細則についてもプロンプトで指示しており、コスト影響のない変更をどう扱うかもここに含めています。

## 試算ルール

- 料金は USD で算出する(JPY 換算は不要)
- リージョンは原則 ap-northeast-1(東京)だが、CloudFront・WAF・ACM(us-east-1 発行)等のグローバルサービスは us-east-1 の料金を使用すること
- リソースの削除はコスト削減として負の値で表記する
- コスト影響がゼロまたは無視できる変更(タグ変更、IAM ポリシー変更、セキュリティグループルール変更等)の場合は「コスト影響なし」と簡潔に報告する
- 正確な料金が不明な場合は保守的(高め)に見積もり、前提条件を明記する
- 環境ごとのコスト差が明確な場合(インスタンスサイズ違い等)は環境別に記載する

アプリケーションリポジトリ(ECS タスク定義変更)

弊社ではアプリケーションリポジトリを複数運用しており、いずれも ECS の起動タイプとして Fargate を採用しています。これらのリポジトリでは Terraform を直接取り扱うことはなく、ECS タスク定義テンプレート(JSON)の CPU / メモリ割り当て変更が主なコスト変動要因です。こちらは Terraform 版とは異なる設計が必要でした。

とりわけ重要だったのは Fargate 料金の動的取得です。当初は料金をプロンプト内にハードコードしていましたが、x86_64 と ARM64(Graviton)では Fargate の料金が異なるにもかかわらず、プロンプトに記載していたのは x86_64 の料金のみでした。そのため ARM64 タスクに対する PR であっても x86_64 価格で試算されてしまう状態になっており、ARM64 移行が進みつつあった当時の実態と乖離した見積もりが出てしまっていたのです。

最終的には AWS 公開の Pricing Bulk API から最新の Fargate On-Demand 料金を動的に取得し、タスク定義テンプレートの runtimePlatform.cpuArchitecture からアーキテクチャを判定して適切な料金を適用しています。プロンプト内では以下のように料金取得手順を明示しています。

## Fargate 料金の取得

料金をハードコードせず、以下の手順で動的に取得すること:

1. タスク定義テンプレートを `Read` で読み、各タスクの CPU アーキテクチャ(ARM64 / X86_64)を特定する
   - `runtimePlatform.cpuArchitecture` の値を確認する
   - テンプレート変数や条件分岐でアーキテクチャが切り替わる場合は、変数定義側も参照して実際の値を確定する
   - `runtimePlatform` が存在しない場合は X86_64 とみなす
2. 以下のコマンドで ap-northeast-1 の最新 Fargate On-Demand 料金を取得する:
   ```shell-session
   $ curl -s "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonECS/current/ap-northeast-1/index.json" | jq '
       .terms.OnDemand as $terms |
       [.products | to_entries[] |
        select(.value.attributes.usagetype | test("Fargate")) |
        select(.value.attributes.usagetype | test("Windows|Ephemeral") | not) |
        .key as $sku |
        {usagetype: .value.attributes.usagetype,
         price_usd: ($terms[$sku] | to_entries[0].value.priceDimensions | to_entries[0].value.pricePerUnit.USD)}]'
   ```
3. usagetype とアーキテクチャの対応:
   - `Fargate-vCPU-Hours:perCPU` / `Fargate-GB-Hours` → X86_64
   - `Fargate-ARM-vCPU-Hours:perCPU` / `Fargate-ARM-GB-Hours` → ARM64
4. タスクのアーキテクチャに対応する料金と 730h/月 で試算する

タスク定義の `cpu`/`task_cpu` は vCPU ユニット(1024 = 1 vCPU)、`memory`/`task_memory` は MiB 単位です。

横展開:Reusable / Caller 構成への移行

当初、複数のアプリケーションリポジトリへの横展開は、ワークフロー YAML をそのままコピペする格好でおこないました。

しかしこの方式はすぐに破綻しました。横展開を完了した直後から、料金算出ロジックを実情に適うものにするためのプロンプトなどの修正や、利用中アクションの SHA pin 更新といった作業が連続で必要になったのです。すべてのリポジトリに同じ修正 PR を展開して回るというのは、地味に手間のかかる作業です。ワークフロー定義におけるリポジトリ固有の内容は一部に限られ、ゆえに大半が共通化可能なものでした。そこに修正が入るたびに、リポジトリ間での辻褄合わせの為に全リポジトリへ同じ変更を行う必要が生じていました。

そこで GitHub Actions の Reusable Workflows を活用し、以下の二層構成に整理し直す格好としました。

  • Reusable Workflow(テンプレートリポジトリ)
    • 共通プロンプト(Fargate 料金取得ロジック、試算ルール、コメントフォーマット、セキュリティ指示)
    • workflow_call トリガにて外部から呼び出し可能
    • inputs.repo_context(リポジトリ固有のタスク定義構成説明)と inputs.additional_rules(追加ルール)を受け取る
  • Caller Workflow(各アプリケーションリポジトリ)
    • トリガ条件(paths フィルタ)の定義
    • repo_context にリポジトリ固有の構成説明を記述
    • Reusable Workflow を呼び出すのみ

Caller 側のコードは以下のように簡素です。

name: Claude Code Cost Estimate

on:
  pull_request:
    types: [opened, synchronize, ready_for_review]
    paths:
      - 'app/task-definition/**'

concurrency:
  group: claude-cost-estimate-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  cost-estimate:
    uses: <自組織>/<テンプレートリポジトリ>/.github/workflows/reusable-claude-code-cost-estimate.yml@main
    with:
      repo_context: |
        ## リポジトリ構成
        このリポジトリでは ECS タスク定義を以下のように管理しています:
        - `app/task-definition/template-*.json`: タスク定義テンプレート
        - `app/task-definition/variables-*/`: 環境ごとの変数オーバーライド
        ...
    secrets:
      CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

uses: の記法は <owner>/<repo>/<path>@<ref> の形式で、別リポジトリにある Reusable Workflow を参照します(GitHub 公式ドキュメント)。@<ref> にはブランチ・タグ・コミット SHA のいずれも指定できます。

repo_context は Reusable Workflow 側のプロンプトにそのまま埋め込まれる文字列入力です。リポジトリ固有のタスク定義の置き場所や YAML 構造、その他の注意事項を自然言語で記述しておけば、Claude は PR 差分をその文脈で解釈してくれます。従来であればリポジトリごとに構造解析ロジックを書き分ける必要があったところを、自然言語で補足を書くだけで済ませられるのは LLM を挟む大きな利点です。

この構成の嬉しさは明白です。Fargate 料金取得ロジックの修正や利用中アクションの SHA pin 更新が必要になった際、テンプレートリポジトリの 1 箇所を修正するだけで全リポジトリに反映されます。各リポジトリの Caller は自身の構成説明(repo_context)にのみ責任を持てばよく、共通部分の保守から解放されました。

なお Reusable Workflow を別リポジトリから参照するにあたっては、以下 2 つの設定が必要です。詳細は GitHub 公式ドキュメント を参照してください。

  1. 呼び出し元リポジトリ: Settings > Actions > General にて "Allow <自組織>, and select non-<自組織>, actions and reusable workflows" を有効化する
  2. テンプレートリポジトリ: Settings > Actions > General の "Access" セクションにて、他リポジトリからの参照を許可する

運用風景

実際に投稿されているコメントの例を以下に紹介します(機密情報は適宜マスクしています)。

コスト影響がない変更の場合

Fluent Bit のログフィルタ設定追加のような、AWS リソースの追加・変更・削除を伴わない PR に対しては、以下のように簡潔に報告されます。

コスト影響なしの報告例: Fluent Bit のログフィルタ設定追加 PR に対するコメント

コスト影響がある変更の場合

具体的な金額差を伴う試算結果の例として 2 つ挙げます。

ECS タスクのアーキテクチャを x86_64 から ARM64 に変更する PR では、Fargate 料金の差分がタスクごとに算出されます。

コスト影響ありの報告例: ECS タスク定義の ARM64 移行 PR に対するコメント

Terraform 側の例としては、OpenSearch マスターノードのインスタンスタイプ変更 PR に対して、インスタンス単価の根拠とともに月額差分が算出されます。

コスト影響ありの報告例: OpenSearch マスターノードのインスタンスタイプ変更 PR に対するコメント

前者のようにコード変更量は小さいがコスト影響が見えづらいケースや、後者のように一見スペックアップに見えてコスト削減となる直感に反するケースにおいて、数値根拠と併せて即座に金額影響が可視化されるのはレビュアーにとっての判断材料として有用です。

おわりに

PR 上の Terraform 変更や ECS タスク定義変更に対して Claude Code にコスト影響を自動試算させる仕組みと、Reusable Workflow による全リポジトリへの横展開について紹介しました。

今回の取り組みで得られた利点は以下の通りです。

  • 試算の自動化:コスト影響の有無が PR 上で自動的に可視化され、手動での料金表引きが不要になった
  • レビュー観点の底上げ:「このリソース変更はいくらかかるのか」が PR コメントとして残るため、レビュアーがコスト観点でも判断できるようになった
  • 保守性:Reusable Workflow への集約により、共通ロジックの修正が 1 箇所で済むようになった

一方で、横展開の過程ではプロンプトの修正や利用中アクションの SHA pin 更新など、全リポジトリに修正 PR を展開する羽目になる場面が複数ありました。最初から Reusable Workflow 構成にしておけばよかったと思わないでもないですが、まずは動くものを 1 リポジトリで作り、その後横展開しつつ構成を洗練させてゆくアプローチは結果的には妥当だったと考えています。実際に横展開をおこなって初めて見えてくる問題(アーキテクチャごとの料金差異など)もあり、最初から完璧な設計を目指すよりも実地で鍛えてゆくほうが確実なものが出来あがる向きもあります。

また、横展開とは別の文脈ですが、実装初期に遭遇した小さな事件として、コスト試算コメントを gh pr comment --body オプションにインラインで渡していたところ、本文中の $0 が bash のシェル変数として展開され /bin/bash に化けるというものもありました。--body-file 経由に変更して解決しましたが、LLM を GHA 上で取り扱う際にはシェルとの境界に注意が必要であるという学びを得ています。

Terraform のコスト試算ツールとしては Infracost のような専用ツールもあります。今回それらを採用しなかったのは、PR 上でザックリ差額感を掴めれば充分で、専用ツールを導入・運用するほどに精緻な分析を求めていたわけではない、という向きが大きいです。また弊社では既に Claude Code を PR レビューの自動化で使っており、その延長線上で賄えるという点も後押しとなりました。その点、Claude Code を使うアプローチは「diff の文脈を理解した上で、コスト影響のない変更を適切にスキップできる」「プロンプトの修正のみで試算ルールを柔軟に変更できる」という固有の嬉しさがあり、要求水準に充分適うものとなりました。

PR レビュープロセスにコスト観点を自然に組み込みたい向きに、本稿で紹介した事例が一助となれば幸いです。

文責:MNTSQ 株式会社 SRE 秋本

注記:この記事は文責者の過去記事と弊社内のドキュメントをもとに Claude Opus 4.7 が作成した内容をほぼそのまま使用しています


  1. 当時の調査では anthropics/claude-code-action の #1205#1126 といったものを参照していました。原因の完全な特定には至らなかったのですが、CLI 直接実行への切り替えにより事象は解消しています。