Cloud Functions (gen2) のウォームインスタンスを営業時間帯だけに制限してコスト削減してみた
はじめに
Cloud Functions(第2世代)で運用しているチャットボットに min-instances=1 を設定し、コールドスタートを回避していました。しかし、夜間や休日はほぼ利用がないのに常時ウォームインスタンスを維持するのはもったいない。
「営業時間帯だけウォームにできないか?」と調べてみたところ、Cloud Schedulerで実現できました。ただし、いくつかハマりどころがあったので共有します。
やりたいこと
| 時間帯 | min-instances | 状態 |
|---|---|---|
| 平日 9:00〜18:00 | 1 | ウォーム(即時応答) |
| 上記以外(夜間・土日) | 0 | コールド(初回リクエスト時に起動) |
Cloud Schedulerで2つのジョブを作成し、営業開始時に minInstanceCount=1、営業終了時に minInstanceCount=0 に切り替えます。

前提環境
- Cloud Functions 第2世代(Cloud Run ベース)
- リージョン:
asia-northeast1 - ランタイム: Python 3.14
- デフォルトコンピューティングサービスアカウントに
roles/editorが付与済み
ハマりどころ1: Cloud SchedulerはPATCHメソッドを直接サポートしていない
Cloud Run / Cloud Functions の Admin API でリソースを部分更新するには PATCH メソッドが必要です。しかし、Cloud Schedulerの --http-method で指定できるのは DELETE, GET, HEAD, POST, PUT のみ。PATCH はありません。
ERROR: argument --http-method: Invalid choice: 'patch'.
Valid choices are [delete, get, head, post, put].
回避策: PUT + X-HTTP-Method-Override: PATCH ヘッダーを使います。Google Cloud の公式ドキュメントでもこの方法が紹介されています。
--http-method=PUT \
--headers="Content-Type=application/json,X-HTTP-Method-Override=PATCH"
ハマりどころ2: Cloud Run APIでは409エラーになる
最初は Cloud Run Admin API(run.googleapis.com)を使ってみました。
https://run.googleapis.com/v2/projects/YOUR_PROJECT/locations/REGION/services/YOUR_SERVICE?update_mask=scaling.min_instance_count
しかし、リクエストは常に HTTP 409 (Conflict) で失敗しました。
{
"debugInfo": "URL_ERROR-ERROR_OTHER. Original HTTP response code number = 409",
"status": "ABORTED"
}
原因: Cloud Functions(第2世代)は Cloud Run 上で動作しますが、Cloud Functions が管理するサービスに対して Cloud Run API で直接更新をかけると、管理レイヤーの競合が発生します。
解決策: Cloud Run API ではなく Cloud Functions v2 API(cloudfunctions.googleapis.com)を使います。
https://cloudfunctions.googleapis.com/v2/projects/YOUR_PROJECT/locations/REGION/functions/YOUR_FUNCTION?updateMask=serviceConfig.minInstanceCount
リクエストボディも Cloud Functions API の形式に合わせます:
{"serviceConfig": {"minInstanceCount": 1}}
Cloud Schedulerジョブの作成
上記2つのハマりどころを踏まえた最終的なコマンドです。
ウォーム開始ジョブ(営業時間開始)
gcloud scheduler jobs create http warm-bot-start \
--location=asia-northeast1 \
--schedule="0 9 * * 1-5" \
--time-zone="Asia/Tokyo" \
--uri="https://cloudfunctions.googleapis.com/v2/projects/YOUR_PROJECT/locations/REGION/functions/YOUR_FUNCTION?updateMask=serviceConfig.minInstanceCount" \
--http-method=PUT \
--headers="Content-Type=application/json,X-HTTP-Method-Override=PATCH" \
--message-body='{"serviceConfig":{"minInstanceCount":1}}' \
--oauth-service-account-email=YOUR_SA@developer.gserviceaccount.com
ウォーム停止ジョブ(営業時間終了)
gcloud scheduler jobs create http warm-bot-stop \
--location=asia-northeast1 \
--schedule="0 18 * * 1-5" \
--time-zone="Asia/Tokyo" \
--uri="https://cloudfunctions.googleapis.com/v2/projects/YOUR_PROJECT/locations/REGION/functions/YOUR_FUNCTION?updateMask=serviceConfig.minInstanceCount" \
--http-method=PUT \
--headers="Content-Type=application/json,X-HTTP-Method-Override=PATCH" \
--message-body='{"serviceConfig":{"minInstanceCount":0}}' \
--oauth-service-account-email=YOUR_SA@developer.gserviceaccount.com
ポイント:
--schedule="0 9 * * 1-5"は月〜金の9:00、"0 18 * * 1-5"は月〜金の18:00--time-zone="Asia/Tokyo"でJSTを指定--oauth-service-account-emailにはCloud Functions の更新権限(cloudfunctions.functions.update)を持つサービスアカウントを指定。roles/editorがあれば十分
動作確認
手動でジョブを実行して動作を確認します。
# ウォーム開始を手動トリガー
gcloud scheduler jobs run warm-bot-start --location=asia-northeast1
# ジョブのステータス確認(status: {} = 成功)
gcloud scheduler jobs describe warm-bot-start --location=asia-northeast1 \
--format="yaml(status,lastAttemptTime)"
実際に min-instances が変わったことを確認:
# Cloud Functions API で確認
gcloud functions describe YOUR_FUNCTION --region=asia-northeast1 --gen2 \
--format="value(serviceConfig.minInstanceCount)"
# Cloud Run のアノテーションでも確認可能
gcloud run services describe YOUR_FUNCTION --region=asia-northeast1 \
--format="value(spec.template.metadata.annotations.'autoscaling.knative.dev/minScale')"
status: {} が返れば成功です。status.code: 10 が返る場合は HTTP 409 エラーなので、APIエンドポイントが正しいか確認してください。
コスト比較
| 構成 | ウォーム時間/月 | 概算月額 |
|---|---|---|
| 常時 min-instances=1 | 約730時間 | 約¥8,500〜10,000 |
| スケジュール制(月〜金 9-18時) | 約195時間 | 約¥2,300〜2,700 |
約73%のコスト削減になります。
コールドスタートのトレードオフ
営業時間外(夜間・土日)に min-instances=0 になるため、その時間帯の最初のリクエストではコールドスタートが発生します。
具体的には:
- コンテナの起動、Pythonランタイムの初期化、依存パッケージの読み込みが走る
- 依存パッケージが重い場合(例:
google-cloud-aiplatformなど)、起動に30秒以上かかることがある - Google Chat のようにHTTPレスポンスにタイムアウトがあるサービスでは、タイムアウトエラーが表示される場合がある(処理自体は継続し、遅延して応答が返る)
startup-cpu-boost を有効にしておくと起動が速くなりますが、完全には解消できません。
# startup-cpu-boost の有効化(初回のみ)
gcloud run services update YOUR_FUNCTION --region=asia-northeast1 --startup-cpu-boost
営業時間外の利用頻度が低い場合は、このトレードオフは許容範囲でしょう。
まとめ
- Cloud Scheduler + Cloud Functions v2 API で、営業時間帯だけ
min-instances=1を維持する仕組みを構築できた - Cloud Functions(gen2)管理下のサービスには Cloud Run API ではなく Cloud Functions v2 API を使う必要がある(409回避)
- Cloud Scheduler は PATCH 非対応のため、
PUT+X-HTTP-Method-Override: PATCHで回避する - コスト約73%削減(常時ウォーム比)。営業時間外はコールドスタートが発生するトレードオフあり

