はじめに
Cloud Run はコンテナをサーバーレスで実行できる便利なサービスですが、手軽さの反面、意図しないコストが発生することがあります。代表的なのは、「リクエストがないはずなのにインスタンスが増え続ける」「静的ファイルを配信しているだけで、アウトバウンド通信費用がかさむ」といった問題です。
本記事では、これらの課題が発生する原因を解明し、設定の見直しによるインスタンス数の制御と、Cloud CDN を活用したアウトバウンド通信費用の削減方法を、具体的な手順を追いながら検証します。
今回実現した構成
本記事では、次の2つのシナリオを検証します。
1.インスタンス増加の検証
最小インスタンス数を設定した Cloud Run サービスをデプロイし、リクエストがない状態でのインスタンスの挙動を確認します。
2.通信費用の最適化
静的な JavaScript ファイルを配信する Cloud Run サービスに対し、 Cloud CDN を経由してアクセスする場合のCloud Run への負荷とアウトバウンド通信の挙動を確認します。
検証手順と結果
1. 予期せぬインスタンス増加の再現と対策
Cloud Run では、コールドスタート対策としてインスタンスを常時待機させる「最小インスタンス (min-instances)」という設定があります。これが意図せず設定されていると、リクエストがない時間帯もインスタンスが起動し続け、不要なコストが発生する原因となります。
サービスの最小インスタンス数を設定する | Cloud Run
手順
1.最小インスタンスを設定してデプロイ:
gcloud コマンドラインツールを使い、最小インスタンス数を 1 に指定してサンプルコンテナをデプロイします。
gcloud run deploy min-instance-sample \ --image=us-docker.pkg.dev/cloudrun/container/hello \ --min-instances=1 \ --region=asia-northeast1
2.インスタンス数の確認:
デプロイ完了後、Google Cloud コンソールで Cloud Run サービスの「指標」タブを開き、「インスタンス数」のグラフを確認します。


最小インスタンス起動しており、無アクセスでも課金が発生し続けていることがわかります。

少し時間をおいてみると、さらに課金対象の時間が積み上がりました。
結果:
コマンド実行後、サービスに一切アクセスしなくても、インスタンス数が常に 1 で維持されることを確認できました。 最小インスタンス数の設定は、サービスの可用性を高めるために有効ですが、開発環境や常時稼働が不要なサービスでは 0 (デフォルト) に設定しておくことがコスト管理上重要です。
また、CPU の割り当て 設定も重要な観点です。デフォルトの「リクエスト処理中にのみ CPU を割り当てる」ではなく「CPU を常に割り当てる」に設定している場合、インスタンスが起動している間は常に CPU リソースに対する課金が発生します。これも予期せぬコスト増に繋がるため、バックグラウンド処理が不要な限り、デフォルト設定の利用を推奨します。
サービスの課金設定 | Cloud Run
2. Cloud CDN 導入によるアウトバウンド通信費用の最適化
Cloud Run から直接、画像や JavaScript、CSS などの静的コンテンツを配信すると、そのすべてがアウトバウンド通信として課金対象になります。特にアクセス数が多いサイトでは、この費用は無視できません。「中身が同じなのに、毎回フルでコストを払っている」のは無駄であるため、Cloud CDN を導入し、コンテンツをユーザーの近くにキャッシュすることで、Cloud Run へのリクエストとアウトバウンド通信量を大幅に削減できます。
手順
1.静的コンテンツを配信する Cloud Run の作成:
index.js というファイルを作成し、これを配信する Cloud Run サービスをデプロイします。(今回はコンテナ作成の詳細は割愛します)
2.外部アプリケーションロードバランサと Cloud CDN の設定:
a. 外部アプリケーションロードバランサを作成します。
b. バックエンドサービスとして「サーバーレス ネットワーク エンドポイント グループ」を選択し、先ほど作成した Cloud Run サービスを紐付けます。
c. バックエンドサービスの設定で Cloud CDN を有効化 します。
d. フロントエンドとして、グローバル外部 IP アドレスと HTTP プロトコルを設定します。
【補足】本検証で HTTP を用いている理由
本来、外部公開するロードバランサは HTTPS で構成すべきです。HTTPS 化には独自ドメインと SSL 証明書(Googleマネージド証明書を使う場合は管理下のドメイン)が必要になりますが、本記事の目的は Cloud CDN のキャッシュ挙動(CACHE_MISS → HIT)と、それによる Cloud Runへのリクエスト・アウトバウンド通信の削減効果を確認することにあります。この挙動は HTTP / HTTPSのいずれでも同一であり、証明書管理の手順は本筋から外れるため、検証では構成を簡素化する目的で HTTPを採用しています。実運用では必ずHTTPS(および HTTP→HTTPS リダイレクト)を設定してください。

3.キャッシュヒットの確認:
ロードバランサの IP アドレスに対して複数回アクセスし、Cloud CDN のログを確認します。初回アクセスはキャッシュミス (CACHE_MISS) となり Cloud Run までリクエストが到達しますが、2回目以降はキャッシュヒット (HIT) となり、エッジからコンテンツが返却されることを確認します。
# ロードバランサのログを確認するクエリ例 resource.type="http_load_balancer" jsonPayload.cacheId!=""

結果:
2回目以降のアクセスでは、Cloud Run サービスのログにリクエストが記録されなくなり、ロードバランサのログで jsonPayload.statusDetails: "response_from_cache" が確認できました。これにより、Cloud Run の負荷(インスタンス起動)とアウトバウンド通信が抑制され、コスト削減と表示速度の向上が両立できることが分かりました。
費用最適化された Cloud Run サービスのベスト プラクティス

→ 2回目以降はキャッシュ(エッジ)で止まり、Cloud Run に届いていない
感想・気づき
min-instancesの設定: コールドスタートを嫌う本番サービスでは有効ですが、開発・ステージング環境ではコストの無駄になりがちです。環境ごとに0か1以上かを明確に使い分けるべきだと感じました。- 静的ファイル配信は Cloud Run の仕事ではない: JS ファイルのような静的コンテンツの配信元が Cloud Run になっているケースは、そもそもアーキテクチャの見直しを検討すべきです。Cloud Storage + Cloud CDN の組み合わせが、コストとパフォーマンスの観点で最適解です。
- CPU 割り当て設定: 「CPU を常に割り当てる」設定は、バックグラウンド処理など特殊な要件がない限り使うべきではありません。インスタンス数だけでなく、この設定もコストに直結することを再認識しました。
- コストアラートの重要性: 今回のような予期せぬコスト増は、設定ミスによって誰にでも起こりえます。一定の予算を超えたら通知が飛ぶように、Cloud Billing の予算とアラートを設定しておくことが、被害を最小限に抑えるための最後の砦となります。
まとめ
Cloud Run のコスト最適化には、2つの大きな視点があります。一つは、min-instances や CPU 割り当てといったスケーリング設定をサービスの特性に合わせて正しく構成し、不要なインスタンスの起動を抑えることです。もう一つは、静的コンテンツの配信のような不得意なタスクを Cloud CDN など他の適切なサービスにオフロードすることです。
手軽に利用開始できる Cloud Run ですが、その挙動と課金モデルを正しく理解し、定期的に設定を見直すことが、安定したサービス運用とコスト管理を実現するために不可欠です。