Google Cloudでサーバーを運用する際、避けて通れないのが「どのコンピューティングリソースを選ぶか」という問題です。
Cloud Runは、Kubernetesをバックエンドに持ちながら、さまざまなワークロードに応じてアプリケーションを簡単にセットアップできる非常に便利なサービスです。2026年1月現在、主に以下の4つの製品群が展開されています。
- Cloud Run Service
- Cloud Run Function (第2世代)
- Cloud Run Job
- Cloud Run Worker Pool(プレビュー版)
どのサービスにも適切な用途があり、事前のプランニングなしに選定してしまうと、インフラ面だけでなくアプリケーションのハンドラー改修が必要になるなど、後々「地味な痛手」を負うことになります。今回は私の実体験を元に、失敗から学んだ「適切なリソース選択」について解説します。
実例から見る失敗談:画像変換処理の実装
開発していたサービスに、「ユーザーがアップロードしたpdf、psdやrawデータなどのメディアファイルを、プレビュー用のpngやjpeg形式に変換する」という機能がありました。
当初の構成は以下の通りです。
- フロントエンド/バックエンド: Cloud Run Serviceで稼働。
- アップロード: Cloud StorageのSigned URLを利用。
- 変換処理: Cloud Run Jobを利用。
変換ジョブは、ImageMagickをインストールしたGoのイメージで、Cloud Storage FUSE※1を使用してバケットをマウントし、ストリーミング読み込みを行うことでメモリ消費を抑える設計でした。
安易な「ジョブ呼び出し」の追加
この既存の変換ジョブを、「One DriveやGoogle Driveなどの外部クラウドストレージから大量のファイルを一括インポートする新機能」でも再利用することにしました。
実装自体はシンプルです。インポート処理(これもCloud Run Job)の中でループを回し、メディアファイルを見つけるたびにCloud SDK経由で「画像変換ジョブ」を起動するという構成です。 テスト環境では少ないファイル数で問題なく動いていたため、そのまま運用を開始しました。
直面した「429 Too Many Requests」エラー
ところが、ストレージから大量のファイルをインポートした際、事件が起きました。 画像変換ジョブの呼び出しが次々と429 Too Many Requestsエラーで失敗し、多くのファイルでプレビューが作成されなかったのです。
なぜエラーになったのか?
後から理解したことですが、Cloud Run Jobはその名の通り「バッチ処理」や「長時間実行されるタスク」に特化した製品です 。
- オンデマンドの大量リクエストには向かない: 短時間に大量のジョブを起動しようとすると、実行数のクオータ(割当制限)に即座に抵触します。
- 呼び出しの前提: 基本的にCloud SDKやCloud Schedulerからの実行が想定されており、APIサーバーのように数千、数万のリクエストを即座に捌くようには設計されていません。
軌道修正:メッセージキューの導入と新たな壁
この特性を理解し、チームとしてアプローチを大幅に変更することにしました。 短時間に多量のリクエストが発生する場合の定石通り、変換ジョブの前段にCloud Pub/Subを挟み、メッセージキューとして活用する方針です。
新しいフローは以下の通りです:
- インポートジョブがファイルを検知。
- メディアファイルがあればPub/Subへメッセージを投げる。
- 画像変換側がそのメッセージを受け取って処理する。
これにより、大量のリクエストもキューイングによって「いい塩梅」で処理できるはずでした。
さらなる(プチ)悲劇:Cloud Run JobはHTTPで呼べない?
いざTerraformを調整しようとした際、決定的な違和感に気づきます。 「Cloud Run Jobには、Pub/SubのPushサブスクリプションを受け取るためのHTTPエンドポイントがない」ということです。
Pub/Subからプッシュ通知を受け取るには、一般的なWEBサーバーのようにHTTP POSTリクエストを捌くハンドラーが必要ですが、Cloud Run Jobは基本的にSDKやスケジューラー経由の「起動」のみをサポートしています。エンドポイント自体は存在するものの、Bodyパラメータを渡してジョブの挙動を柔軟にコントロールする用途には適していませんでした。
最終的な解決策:Cloud Run Serviceへの移行
チームで議論を重ねた結果、解決策は非常にシンプルになりました。「画像変換ジョブを、Cloud Run JobからCloud Run Serviceに移行する」という選択です。
もともとDockerコンテナとして動かしていたため、Terraformの定義を少し書き換えるだけで移行はスムーズに完了しました。
- Cloud Run Serviceにしたメリット:
- HTTPハンドラーを実装することで、Pub/SubからのPush通知を直接受け取れる。
- リクエストベースで柔軟にスケールし、大量のメッセージも効率よく捌ける。
一件で学んだこと:Cloud Runファミリーの真価と使い分け
実務での一連の流れを通じて、Cloud Run Jobの限界と、各サービスが本来想定している「棲み分け」が見えてきたと思います。
今回の反省点は、「大量の処理=バッチ(Job)」という固定観念に縛られてしまったことです。アジャイル開発ではPRDやDesign Docのような機能や設計に関するドキュメントを最初から完璧に用意するのは難しいものですが、ワークロードの性質(トリガーは何か? 同時実行数は? 引数はどう渡すか?)を初期段階で整理できていれば、今回のような手戻りは防げたはずです。
また、モノレポ構成でコードを共通化していると、既存の構成に引きずられて「なんとなくJobで動かす」という盲目的な判断に陥りがちです。インフラ構成は、個々のユースケースに対して単体で最適解を検討すべきであると痛感しました。
4つのCloud Run:サービス特性の徹底比較
ここで、ワークロードに応じて最適なリソースを判別できるよう、それぞれの特性を整理しました。
特徴 | Cloud Run Service | Cloud Run Functions | Cloud Run Job | Cloud Run Worker Pool |
主な用途 | APIサーバー、Webアプリ | イベント駆動の軽量処理 | バッチ処理、一過性のタスク | 長時間のバックグラウンド処理 |
実行モデル | リクエスト待機型 | イベント駆動型 | タスクベース(完了後終了) | キューベースの継続処理 |
主なトリガー | HTTP, Pub/Sub Push, Eventarc | Cloud Storage, Firestore, Pub/Sub | 手動, Scheduler, APIコール | 内部キューのメッセージ |
ジョブ(Job)を使いこなすコツ:冪等性の確保
Cloud Run Jobは、処理の「並列実行」を非常に簡単に実現できる強力なツールです。 同じことをServiceで実現しようとすると、リクエストの同時実行数やインスタンスのオートスケーリングを細かく制御する必要がありますが、Jobであれば「タスク数」を指定するだけで済みます。
ただし、Jobを活用する上で不可欠なのが「冪等性(べきとうせい)※2」です。
- なぜ必要か: ネットワークエラーやタイムアウトでジョブが再試行された際、二重処理によるデータ破損を防ぐため。
- ポイント: 「処理済みフラグ」の確認や、上書き保存の許容など、何回実行されても同じ結果になる設計にすることで、Jobの並列性能を最大限に活かせます。
どっちを使う?判別フローチャート
「大量のファイルを処理したい」といったユースケースに直面したとき、以下のフローで考えると最適なリソースに辿り着けます。
- トリガーは何か?
- HTTPリクエスト/Webhook: → Service または Functions
- ファイルの作成/DBの更新イベント: → Functions
- スケジュール実行/アドホックな実行: → Job
- 実行時間はどれくらいか?
- 数分以内: どれでもOK(コストと起動速度で判断)
- 数十分〜24時間: → Job または Service(タイムアウト設定に注意)
- スケーリングの特性は?
- スパイク(瞬間的)な大量リクエスト: → Service + Pub/Sub
- 定時バッチ/並列計算: → Job
ユースケース別のおすすめ
- ファイル変換処理: ファイルサイズが数kB〜数GBと幅広く、メモリ調整が難しい場合 。
- 基本は Service + Pub/Sub。リクエストごとにリソースを割り当て、キューで流量制御を行うのが最も安定します 。
- 軽量な通知処理: Webhookを受けてSlackに飛ばすなど。
- Functions が最適。設定がシンプルで、イベント駆動に特化しています
まとめ:クオータを確認し、ワークロードに寄り添う
「大量に処理するからCloud Run Jobでいいだろう」という安易な選択は禁物です。 短時間のAPIコール制限や、同時実行数のクオータを事前に確認しましょう。Cloud Runは非常に柔軟なサービスですが、その真価は「ワークロードの性質とサービスの特性を合致させたとき」に発揮されます。
今回の失敗が、皆さんのより良いアーキテクチャ設計の助けになれば幸いです。
注釈
※1 Cloud Storage FUSE
Google Cloud Storage のバケットを、Linux のファイルシステムとしてマウントできる仕組み。
アプリケーションからは通常のファイル I/O と同様に扱えるため、大きなファイルをストリーミング読み込みしながら処理できる。一方で、実体はリモートストレージであり、ローカルディスクと同じ I/O 特性やスループットは保証されない。
※2 冪等性(Idempotency)
同じ処理を1回実行しても、複数回実行しても、最終的な結果が変わらない性質。
Cloud Run Jobでは、タスクの再試行や並列実行が自動で行われるため、途中で失敗した処理が再度実行されることがある。そのため、ファイル変換やデータ更新処理は「二重に実行されても問題が起きない」設計にしておくことが不可欠となる。