😱

【Cloud Run v2】デフォルト設定の罠!cpu_idleを書き忘れて請求予測¥6,408になった話(Terraform)

に公開
2

はじめに

個人開発している初心者です。
GCPの 予算アラート が飛んできました。

「あれ、おかしいな……?」

でも、ちょうど 新しいアプリを追加したばかり だったんです。
「アプリが増えたから、まあそんなもんか」と思って、数日様子を見ることにしました。

……が、数日経っても費用が下がる気配がない。
「これはさすがにおかしい」 と思って請求画面を開くと、こんなことになっていました。


予想される総費用:¥6,408。個人開発で月6,000円超えは普通にキツい。


998%!?そんな%UP初めて見た🤯

2月1日〜10日の時点で総費用¥1,814。このペースだと月末には ¥6,408 になる予測。
LINE botとWebアプリを動かしているだけなのに、なぜ……?

先月は¥0だったのに、なぜ急に?

「先月は何もかかっていなかったはずなのに……」と思って先月のレポートを確認してみると、衝撃の事実が。

Cloud Run ¥2,455 ……しっかりかかっていました。

ただ、「その他のコスト削減」列で -¥2,455 と全額相殺されていて、小計は¥0。
つまり GCPの無料トライアルクレジットが先月まで効いていて、問題を隠してくれていた のです。

今月そのクレジットが切れて、先月からずっと存在していた「設定ミス爆弾」がようやく表面化した ── というのが事の真相でした。

自力では原因がわからず、Claude CodeにTerraformの設定を調査してもらった ところ、あっさり真犯人が見つかりました。

この記事では、Terraformの設定ミスでCloud Runの費用が爆発した原因と、修正してコストを激減させるまでを共有します。
同じミスをする人が一人でも減れば幸いです。

構成

今回問題が起きたのは、以下のようなシンプルな構成です。

  • アプリ: LINE bot + Webアプリ(Python / FastAPI)
  • インフラ: Google Cloud Run
  • IaC: Terraform
  • CI/CD: GitHub Actions → Cloud Run へ自動デプロイ

LINEからのWebhookやWebアプリへのアクセスを処理する構成で、リクエストがないときはインスタンスが0になるはず……だったのですが。

何が起きていたか

Cloud Runのメトリクス画面を見て、背筋が凍りました。


インスタンス数がずっと1に張り付いている。0にならない……。

最小インスタンス数は 0 に設定していたはず。 それなのに、グラフは1のまま。
誰もアプリを使っていない深夜でも、インスタンスが生き続けています。

Cloud Runは「使った分だけ課金」のサーバーレスサービスのはず。
なのに24時間365日課金されている状態は、まさに 「心電図がフラットなのに課金だけ動いている」 ような状態でした。

真犯人:cpu-throttling の設定ミス

「これはおかしい」と確信したものの、自分ではどこが問題なのかわからない。
そこで Claude Code にTerraformの設定ファイルを調査してもらいました。

Claude Codeはプロジェクト内のファイルを読み込んで分析し、gcloud run services describe コマンドで実際のCloud Runの設定を確認。約1分で原因を特定してくれました。

原因は、Terraformの cpu_idle 設定が抜けていたこと でした。

Cloud Runの2つのCPU割り当てモード

Cloud Runには、CPUの割り当て方法が2種類あります。

モード 説明 課金
リクエスト処理中のみ割り当て(デフォルト) リクエストが来たときだけCPUを使う リクエスト処理時間のみ
常にCPUを割り当て インスタンスが起動している間ずっとCPUを確保 インスタンスの生存時間全体

問題は、Terraformで Cloud Run をデプロイした際に、この設定を 明示的に指定していなかった こと。

「書かなかったらデフォルトで安い方になるでしょ?」と思いますよね。私もそう思っていました。
でも実際は 書かなかったら「常にCPUを割り当てる(高い方)」になります。
エラーも警告も出ないし、デプロイも普通に成功する。初心者にこれは気づけない……。

gcloud run services describe で実際の設定を見てみると……

run.googleapis.com/cpu-throttling: 'false'

cpu-throttling: false = 常にCPUを割り当てる = アイドル中もずっと課金。

LINE botのWebhookやWebアプリへのアクセスが断続的に来るので、インスタンスが完全にスケールダウンする暇がありません。
結果として、ほぼ1日中インスタンスが生存し続け、リクエストを処理していないアイドル時間にもCPU課金が発生していたのです。

修正前のTerraform(問題のコード)

cloud_run.tf
template {
  containers {
    image = "us-docker.pkg.dev/cloudrun/container/hello"

    resources {
      limits = {
        cpu    = "1"
        memory = "1Gi"
      }
      # ← cpu_idle の設定がない!
      # この場合、デプロイ方法によっては cpu-throttling: false になり
      # アイドル中もCPU課金が発生する
    }
  }
  # ← scaling の設定もない!
}

足りなかったのは、たった数行。でもその数行のせいで月6,000円が消えるところでした。

修正後のTerraform

cloud_run.tf
template {
  scaling {
    min_instance_count = 0   # 最小インスタンス数を明示的に0に
    max_instance_count = 3   # 暴走防止
  }

  containers {
    image = "us-docker.pkg.dev/cloudrun/container/hello"

    resources {
      limits = {
        cpu    = "1"
        memory = "512Mi"     # 1Gi → 512Mi に削減
      }
      cpu_idle          = true  # ★ これが最重要!リクエスト処理中のみCPU割り当て
      startup_cpu_boost = true  # コールドスタートの高速化
    }
  }
}

ポイントは3つ:

  1. cpu_idle = true(最重要):リクエストが来ていないときはCPUを割り当てない。これだけでアイドル時のCPU課金がゼロになる
  2. startup_cpu_boost = truecpu_idle を有効にするとコールドスタートが遅くなりがちなので、起動時だけCPUをブーストして補う
  3. memory = "512Mi":個人開発のアプリには1GiBも要らない。半分に削減してメモリ課金も減らす

なぜ検索しても出てこないのか?(v2 APIの罠)

今回、私がこの情報になかなか辿り着けなかったのには理由がありました。

1. 情報が古い(v1 APIばかり)

「Cloud Run CPU 常に割り当て」などで検索しても、出てくるのは古い google_cloud_run_service(v1)の記事ばかり。そこでは metadataannotations に書く方法が紹介されていますが、最新の google_cloud_run_v2_service(v2)では書き方がガラッと変わっています。

バージョン 設定のしやすさ デフォルト設定(書かない場合)
v1(旧) annotations に長い呪文を書く必要がある
(面倒)
安い 💰
(リクエスト中のみ割り当て)
v2(新) resourcescpu_idle と書くだけ
(スッキリ!)
高い 😱
(常にCPUを割り当て)

つまり、「v2になってコードはスッキリ書きやすくなったのに、デフォルト設定は『意地悪(高額請求)』になった」 ということです。

検索して出てくる v1 の記事(デフォルト安)を読んで安心していると、手元の v2(デフォルト高)で爆死する……これが情報の断絶の正体でした。

2. WebコンソールとTerraformで「デフォルト」が違う

ここが一番の落とし穴です。Cloud RunをWeb画面(コンソール)で作る場合、CPUの割り当てはデフォルトで 「リクエストの処理中のみ(安い方)」 が選択されています。

しかし、Cloud Run v2の場合、cpu_idle を明示的に書かないと、デフォルトで 「常にCPUを割り当てる(高い方)」 になってしまうようです。

エラーも出ず、デプロイも成功するため、請求画面を見るまで気づけません。
Cloud Run v2 を使っている方は、今すぐ cpu_idle の設定を確認してください!

結果

修正をデプロイした後、Cloud Runの課金グラフを確認すると……


2月10日を境に、費用がガクッと下がった!


リクエストがない時間はしっかり 「0」 に戻るようになりました。

Cloud Runの課金は秒単位で反映されるので、デプロイした瞬間から効果が出ます。
月額¥6,000超えの予測が今後下がるはずです。

Terraformの罠!始める前に見てほしいこと

過去の自分の記事にも追記しました

実はこのブログで以前、Terraformの導入記事 を書いています。
その記事の cloud_run.tf にも cpu_idle = true の設定が入っていませんでした。

つまり、あの記事を参考にしてくれた方がいたら、同じ罠にハマっている可能性があります。
すでに該当記事の冒頭に注意書きを追記しましたが、もし心当たりのある方は、ぜひ設定を確認してみてください。

自分の過去記事のミスを公開するのは正直恥ずかしいですが、同じ落とし穴にハマる人を減らす方が大事なので書きました。

1. Terraformは「書かなかったこと」が一番怖い

明示的にエラーが出るわけでもなく、デプロイも正常に成功する。
でもデフォルト値が意図と違っていて、静かにお金が消えていく。
これが一番怖いパターンです。

特にCloud Runの cpu_idle のように、書かなかったら高い方の設定になるものは初心者殺しすぎます。
「知らなかった」だけで月数千円飛ぶのは正直キツい。


Google Cloud公式ドキュメントのTerraformサンプル。
しっかり cpu_idle = false と書かれている(2026年2月時点)

「公式ドキュメントを見れば安心」ではありません。
コスト面は自分で意識して、cpu_idle = true を明示的に書きましょう。

さらに、Terraform providerのGitHub issue(2024年)では「resources ブロックを指定すると cpu_idle のデフォルトが勝手に false に変わる」というバグが報告されていました。
このissueは現在Closeされていますが、少なくとも私は2026年2月に同じ挙動を踏んでいます。報告者はこの修正でCPU割り当てが20〜50倍改善したそうです。

Qiitaにも「TerraformでCloud Runを管理する際はcpu_idleは明示的に書くべき」という記事がありました。
2年以上月100円で動いていたサービスが、リソースを変更しただけで課金方式が変わったケースが紹介されています。
自分だけじゃなかった……。

2. Cloud Runのコスト設定チェックリスト

個人開発でCloud Runを使うなら、最低限これだけは確認しましょう。

# ✅ リクエスト処理中のみCPU課金にする
cpu_idle = true

# ✅ 最小インスタンスを0にする(アイドル時に完全停止)
scaling {
  min_instance_count = 0
}

# ✅ リソースは必要最小限にする
resources {
  limits = {
    cpu    = "1"       # 0.5 でも十分な場合が多い
    memory = "512Mi"   # 256Mi でも動くかも
  }
}

3. 無料クレジット期間中こそ、請求レポートを確認する

今回の一番の教訓はこれかもしれません。先月も実は¥2,455かかっていたのに、無料トライアルクレジットで相殺されていたので¥0に見えていた。クレジットが切れた途端に爆弾が爆発しました。

ここで厄介なのが、予算アラートはクレジット適用後の「実際の請求額」で判定される ということ。クレジットで¥0になっている間は、どんなにリソースを使っていてもアラートは鳴りません。つまり「アラート設定してるから安心」では不十分なんです。

おすすめの対策:GCPの請求レポートページをブックマークしておいて、週1回チェックする習慣をつけましょう。

レポート画面の「使用費用」列を見れば、クレジット適用前の実コストがわかります。これを見ていれば、「クレジットがなかったら¥2,455かかってるじゃん!」と先月の時点で気づけていたはずです。

GCPコンソール → お支払い → レポート

このページをブラウザのお気に入りに入れておくだけで、クレジット切れの爆弾を事前に発見できます。

4. 請求アラートは設定しておこう(そして届いたら放置しないこと)

今回、GCPの「予算とアラート」を設定していたおかげで異変に気づけました。これがなかったら、月末に請求を見て青ざめていたと思います。

ただ、アラートが来ても「アプリ増やしたし、こんなもんか」と数日放置してしまった のは反省点です。アラートが届いたら、すぐに原因を調べる癖をつけましょう。

5. わからなかったらAIに聞く

今回、自分ではなかなか原因にたどり着けませんでしたが、Claude Codeにプロジェクトのコードを調査してもらったら、1分ほどで cpu-throttling: false という真犯人を特定してくれました。 Terraformの設定ファイルを読んで、gcloud コマンドで実際の状態を確認して、修正コードまで出してくれる。こういう「設定の抜け漏れ」を探す作業は、AIの得意分野だと実感しました。

おわりに

「サーバーレスだから安い」と油断していると、設定ミス一つで予想外の請求が来ます。
特にTerraformを使っている場合は、デフォルト値が何になるか を必ず確認しましょう。

「最小インスタンス数は0なのに、なんで課金されるの!?」と焦りまくった数日間でしたが、原因がわかってみればCloud Run v2の仕様によるものでした。
2年以上前にリリースされた機能ですが、検索してもこの「cpu_idle」の落とし穴について書かれた日本語記事はほとんど見当たりません。
もしかしたら、企業で使っている方は金額が小さすぎて気づいていないだけかもしれません……😱

今回の失敗を通じて、過去の自分の記事にもミスがあることに気づけました。
失敗は恥ずかしいけど、気づいて、直して、共有する。 それがエンジニアとして大事なことだと思っています。

私の ¥1,814 という勉強代が、この記事を読んでいる皆さんの「クラウド破産」を防ぐ役に立てば幸いです。

Cloud Runで個人開発をしている方は、ぜひ一度 gcloud run services describe で自分のサービスの設定を確認してみてください。
もしかしたら、あなたのインスタンスも今この瞬間、静かにお金を燃やしているかもしれません🔥

# 今すぐ確認!
# Windows / Mac 共通(1行で実行)
gcloud run services describe YOUR_SERVICE_NAME --region YOUR_REGION --format="value(spec.template.metadata.annotations)"

run.googleapis.com/cpu-throttling: 'false' が見えたら、この記事の修正を今すぐ適用しましょう!

コマンドを実行すると、私の環境では赤いエラー(アクセス拒否)が出ちゃいましたが、

run.googleapis.com/cpu-throttling=true

これが出ていれば成功です!🎉
「CPUを節約するモード(Throttling)」が true(有効)になっている証拠です。
これで安心して眠れます!

最後に:AI時代の歩き方

私はまだ学習中で、Terraformの細かい構文はAIに書いてもらっています。
でも、「書き方はAIに、責任(中身の理解)は自分」 というスタンスを大切にしています。

これからも、AIを相棒にしながら「中身」をしっかり理解していこうと思います。
今回も、身銭を切ってすごく勉強になりました🤣

(独学で勉強中のため、もし間違っている箇所があれば優しくご指摘いただけると嬉しいです!🙇‍♀️)

Discussion

rakiraki

terraform v2 って書き方は語弊があります。
terraform のバージョンは今日現在でも v1.14.5 ですし、書きたいのは terraform google provider の google_cloud_run_v2_service リソースについてなので、 google provider v2 でもありません。

miki-minimiki-mini

rakiさん、ご指摘ありがとうございます!Terraform本体のバージョンではなく、Cloud Runのv2リソースのことでした。勘違いしてタイトルにまで書いてしまっていたので、すぐに修正しました!勉強になります、大変助かりました。ありがとうございます!🙏✨