
GCPの予算アラート設定からBigQuery課金エクスポート+データポータル連携までをOpenTofuで構築してみた
はじめに
GCPプロジェクトを運用していて、「今月いくら使ってるんだろう?」「急にコストが跳ね上がったら気づけるのか?」と不安になったことはありませんか?
Cloud Consoleの課金レポートは便利ですが、しきい値を超えたら通知が欲しい、データポータルで他のダッシュボードと一緒にコストも可視化したい、というニーズが出てきました。
この記事では、以下の3つを実際にやってみました。
- gcloud CLIで予算アラートを設定(しきい値の設計含む)
- BigQueryへの課金データエクスポートを有効化
- OpenTofuでBigQueryビューを作成し、データポータルのデータソースとして利用

前提・環境
- GCPプロジェクト: 作成済み
- gcloud CLI: インストール・認証済み
- OpenTofu: v1.12(
brew install opentofuでインストール) - 請求先アカウント: 組織管理(Billing Account IDが必要)
予算アラートの設定
現状のコストを把握する
まず、予算額を決めるために現状のコストを確認します。Cloud Console の お支払い → レポート が最も手軽です。
今回のプロジェクトの場合、主なコスト構成は以下でした。
| サービス | 月額概算 | 備考 |
|---|---|---|
| Cloud Run | 約¥3,500 | min-instances=1で常時起動 |
| Vertex AI | 約¥100 | RAGクエリ(月100件程度) |
| Cloud Storage | 約¥10 | KBファイル保管 |
| その他 | 約¥50 | Cloud Build、Schedulerなど |
| 合計 | 約¥5,000 |
Billing Account IDの確認
予算作成にはBilling Account IDが必要です。Cloud Console の お支払い → アカウント管理 から確認できます。
CLIで確認する場合は以下のコマンドです(Billing Account Viewer以上の権限が必要)。
gcloud billing accounts list
権限がない場合はConsoleから確認するか、組織管理者に問い合わせてください。
Billing Budget APIの有効化
予算の作成には Cloud Billing Budget API が必要です。
gcloud services enable billingbudgets.googleapis.com --project=YOUR_PROJECT_ID
しきい値の設計
予算アラートのしきい値は以下のように設計しました。
| しきい値 | 種別 | 金額目安 | 目的 |
|---|---|---|---|
| 50% | 実績ベース | ¥10,000 | 月半ばのサニティチェック |
| 90% | 実績ベース | ¥18,000 | 予算上限に接近 |
| 100% | 予測ベース | ¥20,000 | 月末超過の早期警告 |
| 120% | 実績ベース | ¥24,000 | 異常検知 |
ポイントは 100%を予測ベース(forecasted-spend) にしていること。実績ベースだと超過してから通知が来ますが、予測ベースなら月の途中で「このペースだと超えそう」と警告してくれます。

予算の作成
gcloud billing budgets create \
--billing-account="YOUR_BILLING_ACCOUNT_ID" \
--display-name="your-project monthly" \
--budget-amount=20000JPY \
--filter-projects="projects/YOUR_PROJECT_ID" \
--threshold-rule=percent=0.5,basis=current-spend \
--threshold-rule=percent=0.9,basis=current-spend \
--threshold-rule=percent=1.0,basis=forecasted-spend \
--threshold-rule=percent=1.2,basis=current-spend
予算額は現状コストの3〜4倍程度に設定するのがおすすめです。今回は月額約¥5,000に対して¥20,000としました。低すぎると頻繁にアラートが飛んで無視されがちに、高すぎると異常を検知できません。
注意点:
- 予算アラートは通知のみで、自動的にリソースを停止したりはしません
- 課金データには数時間のラグがあるため、リアルタイムの監視には向きません
- 自動停止が必要な場合は、Pub/Sub + Cloud Functionsで対応できます
BigQueryへの課金データエクスポート
なぜエクスポートが必要か
Cloud Consoleの課金レポートでも十分な情報が見られますが、BigQueryにエクスポートすることで以下のメリットがあります。
- データポータルでの可視化: 他の運用ダッシュボードと統合できる
- SQLでの分析: SKU別、日別、リージョン別など自由に集計できる
- 長期保存: Consoleのレポートは期間が限られるが、BigQueryなら好きなだけ保持できる
エクスポート用データセットの作成
bq mk --dataset --location=US YOUR_PROJECT_ID:billing_export
エクスポートの有効化
この手順はCloud Consoleから行います(CLIコマンドは提供されていません)。また、Billing Account Administrator権限が必要です。
- Cloud Console → お支払い → レポート → 課金データのエクスポート
- 「標準の使用料金」の設定を編集
- プロジェクトとデータセット(
billing_export)を選択して保存

データの到着を確認
エクスポートを有効化すると、当月+前月分のデータがバックフィルされます(最大5日かかる場合があります)。
bq ls YOUR_PROJECT_ID:billing_export
テーブル名は gcp_billing_export_v1_XXXXXX_XXXXXX_XXXXXXX のような形式で作成されます。
データが到着したら、簡単なクエリで確認してみましょう。
SELECT
invoice.month AS month,
service.description AS service,
ROUND(SUM(cost), 0) AS total_cost_jpy
FROM `YOUR_PROJECT_ID.billing_export.gcp_billing_export_v1_XXXXXX_XXXXXX_XXXXXXX`
GROUP BY 1, 2
HAVING total_cost_jpy != 0
ORDER BY 1 DESC, 3 DESC
OpenTofuでBigQueryビューを作成
なぜIaCでビューを管理するか
データポータルで課金データを可視化する際、生のエクスポートテーブルをそのまま使うこともできますが、ビューを挟むことで以下のメリットがあります。
- credits(クレジット)を考慮した
net_costを計算できる invoice_monthをDATE型にパースして、データポータルでの時系列チャートが簡単になる- 参照期間を制限して、不要な過去データのスキャンコストを抑えられる
Google公式の terraform-google-billing-dashboard モジュールも同様のアプローチを採用しています。
アプローチ: フラットビュー vs プリアグリゲーション
最初はサービス別月次集計、日次トレンドなど、目的別に複数のプリアグリゲーションビューを作ろうとしました。しかし、Google公式テンプレートを参考にしたところ、1つのフラットビューで計算フィールドを追加し、集計はデータポータル側に任せるアプローチの方が良いとわかりました。
| アプローチ | メリット | デメリット |
|---|---|---|
| プリアグリゲーション(複数ビュー) | クエリが軽い | データポータルでの柔軟性が低い |
| フラットビュー(1つ) | データポータルで自由にスライス&ダイス | クエリ量はやや増える |
データポータルはドラッグ&ドロップでディメンションやメトリクスを自由に変更できるため、フラットビューの方が圧倒的に使いやすいです。
Terraform構成
OpenTofuはTerraformと同じHCL構文を使うため、terraform ブロックやプロバイダ定義はそのまま流用できます。tofu init / tofu plan / tofu apply で実行するだけです。
terraform {
required_version = ">= 1.5"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 6.0"
}
}
}
provider "google" {
project = var.project_id
}
resource "google_bigquery_dataset" "billing_dashboard" {
dataset_id = var.dataset_id
project = var.project_id
location = var.location
labels = {
purpose = "billing-dashboard"
}
}
resource "google_bigquery_table" "billing_view" {
dataset_id = google_bigquery_dataset.billing_dashboard.dataset_id
table_id = "billing_view"
project = var.project_id
view {
use_legacy_sql = false
query = <<-SQL
SELECT
*,
COALESCE((SELECT SUM(c.amount) FROM UNNEST(credits) c), 0) AS credits_sum_amount,
cost + COALESCE((SELECT SUM(c.amount) FROM UNNEST(credits) c), 0) AS net_cost,
PARSE_DATE('%Y%m', invoice.month) AS invoice_month
FROM `${var.billing_export_table}`
WHERE _PARTITIONDATE > DATE_SUB(CURRENT_DATE(), INTERVAL ${var.lookback_months} MONTH)
-- 課金エクスポートには請求アカウント配下の全プロジェクトが含まれるため、対象プロジェクトのみに絞る
AND project.id = '${var.project_id}'
SQL
}
deletion_protection = false
}
variable "project_id" {
description = "GCP project ID"
type = string
default = "YOUR_PROJECT_ID"
validation {
condition = can(regex("^[a-z][a-z0-9-]{4,28}[a-z0-9]$", var.project_id))
error_message = "project_id must be a valid GCP project ID (6-30 chars, lowercase, digits, hyphens)."
}
}
variable "billing_export_table" {
description = "Fully qualified billing export table ID"
type = string
default = "YOUR_PROJECT_ID.billing_export.gcp_billing_export_v1_XXXXXX_XXXXXX_XXXXXXX"
}
variable "dataset_id" {
description = "BigQuery dataset for billing dashboard views"
type = string
default = "billing_dashboard"
}
variable "location" {
description = "BigQuery dataset location"
type = string
default = "US"
}
variable "lookback_months" {
description = "Number of months of billing data to include"
type = number
default = 12
}
ビューのポイント
credits_sum_amount: GCPクレジット(無料トライアル、SUD割引など)の合計額net_cost: クレジット適用後の実質コスト。ダッシュボードではこちらを使うinvoice_month:YYYYMM文字列をDATE型にパースし、データポータルの時系列軸で使えるようにするlookback_months: パーティションプルーニングで不要なデータのスキャンを抑制project.idフィルター: 課金エクスポートテーブルには請求アカウント配下の全プロジェクトのデータが含まれるため、project.idでフィルターしないと他プロジェクトのコストが混入する。var.project_idで対象プロジェクトのみに絞っている
.gitignoreの設定
Terraformの生成ファイルをリポジトリに含めないよう、.gitignoreに以下を追加します。
# OpenTofu / Terraform
**/.terraform/
*.tfstate
*.tfstate.backup
*.tfplan
.tfファイル(ソースコード)と.terraform.lock.hcl(プロバイダのバージョンロック)はコミットしてください。tfstateにはリソースIDなどの情報が含まれるため、リポジトリには入れないのが鉄則です。
デプロイ
cd infra/billing-dashboard
tofu init
tofu plan
tofu apply
tofu plan で作成されるリソースを確認してから tofu apply を実行します。
Plan: 2 to add, 0 to change, 0 to destroy.
Outputs:
dataset_id = "billing_dashboard"
view_id = "billing_view"
データポータルでの利用
ビューが作成されたら、既存のデータポータルレポートに新しいデータソースとして追加します。
- データポータルでレポートを開く
- リソース → 追加済みのデータソースの管理 → データソースを追加
- BigQuery → プロジェクト →
billing_dashboard→billing_viewを選択 - 新しいページを追加して、チャートを作成
おすすめのチャート構成:
| チャート種類 | ディメンション | 指標 | 用途 |
|---|---|---|---|
| スコアカード | — | net_cost (SUM) |
当月合計コスト |
| 時系列グラフ | invoice_month |
net_cost (SUM) |
月次コスト推移 |
| 棒/円グラフ | service.description |
net_cost (SUM) |
サービス別内訳 |
| テーブル | sku.description |
net_cost (SUM) |
SKU別詳細 |
まとめ
GCPのコスト管理を3段階で構築しました。
- 予算アラート: gcloud CLIで¥20,000/月の予算を設定。50%/90%/100%(予測)/120%の4段階で通知
- 課金データエクスポート: BigQueryにエクスポートし、SQLで自由に分析可能に
- OpenTofuでビュー管理: Google公式テンプレートを参考に、フラットビューで
net_costとinvoice_monthを追加。データポータルで自由にスライス&ダイスできる構成に
予算アラートは通知のみで自動停止はしないこと、課金データには数時間のラグがあること、この2点は忘れずに。自動停止が必要な場合はPub/Sub + Cloud Functionsの追加構築が必要です。
コスト管理は後回しにしがちですが、IaCで管理しておけばプロジェクトが増えても同じ構成を横展開できます。まずは予算アラートの設定から始めてみてはいかがでしょうか。


