はじめに
Google Cloudのコストを確認する方法にはCloud Billingの画面、Budget通知、BigQuery Exportなどがありますが、日次の簡易的なBillingレポートをJSONやCSVで保存し、後から履歴として確認したいケースもあると思います。
こうしたレポートを生成する処理の実行基盤としては、Cloud Runが選択肢になりますが、Cloud Runのコンテナ内に作成したローカルファイルは、インスタンスの再作成・再デプロイ・スケールインなどで失われます。そのため、後から参照したいレポートファイルはCloud Storageなどの外部ストレージに保存する設計が必要です。
本記事では、Cloud Runサービスで簡易的なBillingレポートJSONを生成し、Cloud Storageボリュームマウント先に日付付きファイルとして保存する構成を検証します。
今回検証すること
今回の検証では、Cloud Runサービス上で簡易的なBillingレポートJSONを生成し、以下の2箇所に保存します。
| 保存先 | 内容 |
|---|---|
/tmp/cost-report.json |
Cloud Runコンテナ内のローカルファイル |
/mnt/gcs/billing-reports/YYYY-MM-DD-HHMMSS.json |
Cloud Storageをマウントしたディレクトリ上の履歴ファイル |
検証の流れと構成イメージは以下になります。

Cloud Storageボリュームマウントとは
Cloud Runでは、Cloud Storageバケットをコンテナ内のディレクトリとしてマウントできます。例えば、Cloud Storageバケットを/mnt/gcsにマウントすると、アプリケーションからは通常のディレクトリのように扱えますが、その実体はCloud Storageバケットです。
そのため、Cloud Runのインスタンスが再作成されても、ファイルはCloud Storage上のオブジェクトとして残ります。
今回のように、日次レポートや処理結果を履歴として残したい場合、Cloud Storageボリュームマウントが役立ちます。
本記事では、まず「Cloud Runで生成したファイルをCloud Storageに履歴として残す」という基本的な使い方に絞って検証します。
検証用リソース
今回の検証では、以下のリソースを作成しました。
| リソース | 名前 | 用途 |
|---|---|---|
| Cloud Runサービス | billing-report-demo |
検証用アプリケーションの実行 |
| Cloud Storageバケット | billing-report-demo-20260706231311 |
Billingレポート履歴の保存先 |
| Artifact Registryリポジトリ | billing-report-demo-repo |
コンテナイメージの保存 |
| サービスアカウント | billing-report-demo-sa |
Cloud Runの実行用(GCS書き込み権限を付与) |
Cloud Storageバケットは、Cloud Runサービスから/mnt/gcsとしてマウントします。
Cloud Run上のアプリケーションが/mnt/gcs/billing-reports/に日付付きファイルとして書き込んだレポートは、Cloud Storageバケット上のオブジェクトとして保存されます。
Cloud Storageバケット

Cloud Runサービスからこのバケットへ書き込めるように、Cloud Runの実行サービスアカウントに対してroles/storage.objectUserを付与しました。

Cloud Runサービス
Cloud Runサービスでは、Cloud Storageバケットを/mnt/gcsにマウントしています。

検証用アプリケーション
今回の検証では、簡易的なBillingレポートJSONを生成するアプリケーションを用意しました。
このアプリケーションには、以下のエンドポイントがあります。
| パス | 内容 |
|---|---|
/ |
アプリケーションの説明を表示 |
/write-report |
簡易BillingレポートJSONを生成し、/tmpとCloud Storageマウント先に保存 |
/read-report |
/tmpとCloud Storageマウント先のレポートファイルを確認 |
/list-reports |
Cloud Storageマウント先の履歴ファイル一覧を表示 |
/write-reportにアクセスすると、以下の2箇所にレポートファイルを書き込みます。
- /tmp/cost-report.json
- /mnt/gcs/billing-reports/YYYY-MM-DD-HHMMSS.json
なお、今回はCloud Storageマウントによる履歴保存の挙動を確認するのが目的のため、実際のコスト値ではなくBillingレポートを模したJSONをCloud Run上で生成しています。
Billingレポートを書き込む
/write-reportにアクセスして、簡易Billingレポートを生成します。
実行結果は以下です。
{
"gcs_report_path": "/mnt/gcs/billing-reports/2026-07-11-062123.json",
"local_report_path": "/tmp/cost-report.json",
"message": "billing report written",
"report": {
"currency": "JPY",
"generated_at": "2026-07-11T06:21:23.459078+00:00",
"note": "This is a sample billing report generated by Cloud Run.",
"project_id": "xxxxxxxxxx",
"report_date": "2026-07-11",
"service_costs": [
{
"cost": 120,
"service": "Cloud Run"
},
{
"cost": 35,
"service": "Cloud Storage"
},
{
"cost": 80,
"service": "Cloud Build"
}
],
"total_cost": 235
}
}
結果を見ると、以下の2つのパスにレポートが書き込まれていることが分かります。
- /tmp/cost-report.json
- /mnt/gcs/billing-reports/2026-07-11-062123.json
/tmp/cost-report.jsonはCloud Runコンテナ内のローカルファイルです。
一方で、/mnt/gcs/billing-reports/2026-07-11-062123.jsonはCloud Storageバケットをマウントしたディレクトリ上のファイルです。
レポートファイルの存在を確認する
書き込み直後に/read-reportにアクセスすると、ローカルファイルとCloud Storageマウント先の両方にレポートが存在していました。
{
"latest_gcs": {
"content": { ... },
"exists": true,
"path": "/mnt/gcs/billing-reports/2026-07-11-062123.json"
},
"local": {
"content": { ... },
"exists": true,
"path": "/tmp/cost-report.json"
}
}
latest_gcsとlocalの両方がexists: trueになっており、書き込み直後の時点ではCloud Storageマウント先とローカルの両方にファイルが存在することが分かります。
この時点では、同じCloud Runインスタンス上にアクセスできているため、/tmp/cost-report.jsonも存在しています。
Cloud Storage側の履歴ファイルを確認する
Cloud Run上では/mnt/gcs/billing-reports/2026-07-11-062123.jsonに書き込んでいますが、その実体はCloud Storageバケット上のオブジェクトです。バケットのbilling-reports/配下を確認すると、書き込んだJSONファイルが保存されています。

再デプロイ後の挙動を確認する
次に、Cloud Runサービスを再デプロイし、ローカルファイルとCloud Storageマウント先のファイルの違いを確認しました。再デプロイは、Cloud Runサービスの「新しいリビジョンの編集とデプロイ」から、設定を変更せずにそのままデプロイしました。これにより新しいリビジョンが作成され、コンテナが新しく起動します。

その後、/read-reportにアクセスした結果は以下です。
{
"latest_gcs": {
"content": { ... },
"exists": true,
"path": "/mnt/gcs/billing-reports/2026-07-11-062958.json"
},
"local": {
"content": null,
"exists": false,
"path": "/tmp/cost-report.json"
}
}
Cloud Storageマウント先のレポートはexists: trueのままで、再デプロイ後も参照できました。
一方で、Cloud Runローカルの/tmp/cost-report.jsonはexists: falseとなり、存在しませんでした。
この結果から、Cloud Runのローカルファイルシステムは永続化先として扱うべきではなく、後から参照したいレポートファイルはCloud Storageなどの外部ストレージに保存する必要があることを確認できます。
検証結果
今回の検証結果を整理すると、以下の通りです。
| 保存先 | 再デプロイ後 | 用途 |
|---|---|---|
/tmp/cost-report.json |
存在しない | 一時ファイル |
/mnt/gcs/billing-reports/2026-07-11-062958.json |
存在する | 後から参照したいレポート履歴 |
表のとおり、ローカルの/tmpは再デプロイで失われますが、Cloud Storageマウント先に書き込んだファイルはバケット上のオブジェクトとして残るため、インスタンスが入れ替わってもレポート履歴を継続して参照できます。また、同じファイルを上書きするのではなく、日付や時刻を含めたファイル名で保存すれば、過去のレポートを履歴として蓄積できます。
BigQuery Exportとの使い分け
Google Cloudのコスト情報を詳細に分析する場合は、Cloud BillingのBigQuery Exportを利用する構成も有効です。BigQuery Exportを利用すると、サービス別、SKU別、ラベル別など、より詳細なコスト分析が可能になります。
本記事の構成は、詳細な分析基盤というより、Cloud Runで生成したレポートを日付付きファイルとして保存し、運用上の履歴として残すことを目的にしています。そのため、使い分けとしては以下のイメージです。
| 用途 | 選択肢 |
|---|---|
| 詳細なコスト分析をしたい | BigQuery Export |
| 日次の簡易レポートを履歴として保存したい | Cloud Run + Cloud Storage |
| 予算超過やしきい値を通知したい | Budget通知 |
| 通知内容を後から確認したい | Cloud Storageへの履歴保存 |
今回の構成は、BigQuery Exportの代替というより、日次レポートや通知内容を履歴として残すための軽量な仕組みとして考えるとよいと思います。
利用時の注意点
Cloud Storageボリュームマウントは便利ですが、完全なローカルディスクと同じように扱えるわけではないため、以下の点に注意が必要です。
高頻度な小さいファイル更新には注意
Cloud Storageはオブジェクトストレージです。ローカルディスクのように、高頻度で小さいファイルを何度も更新する用途には向かない場合があります。今回のように、1実行につき1つのレポートファイルを追加する用途であれば扱いやすいです。
同じファイルへの同時書き込みに注意
複数のCloud Runインスタンスから同じファイルへ同時に書き込むような設計は注意が必要です。Cloud Runはスケールアウトにより複数インスタンスが同時に動作する可能性があります。
そのため、同じファイル名へ同時に書き込むと、意図しない上書きや競合が発生する可能性があります。
公式ドキュメントのCloud Runでのボリュームマウントでも、Cloud Storage FUSEは同一ファイルへの複数書き込みに対する排他制御(ファイルロック)を提供せず、複数の書き込みが同じファイルを置き換えようとした場合は最後の書き込みが優先され、それ以前の書き込みは失われる、と説明されています。
そのため、履歴保存では以下のように日付や時刻、実行IDを含めたファイル名にするのが安全です。
billing-reports/2026-07-11-062123.json
billing-reports/2026-07-11-062123-${UUID}.json
おわりに
本記事では、Cloud RunサービスでCloud Storageボリュームマウントを利用し、生成した簡易BillingレポートをCloud Storageに履歴保存する構成を検証しました。ローカルの/tmpは再デプロイで失われる一方、Cloud Storageマウント先に書き込んだファイルはオブジェクトとして残り、日付付きのファイル名にすることで履歴として蓄積できることを確認できました。
Cloud Runを使うときは、生成したファイルが「一時的なもの」なのか「後から参照したいもの」なのかを整理しておくと、保存先の設計で迷いにくくなります。同じような構成を検討している方の参考になれば幸いです。