🐶

Cloud Run Jobs を使うときの覚書

に公開

はじめに

Cloud Run Jobs(以下、Cloud Run ジョブ)を使ってバッチ処理や一回限りの処理を実行する際の個人的な覚書です。忘れやすいポイントをまとめます。

これは何?

HTTP サーバー不要。一度(またはスケジュール)で実行して終了するバッチ向けコンテナ。 FaaS とは違い、Web サーバを意識しないため、シンプルな実装が可能です。

想定ユースケース

  • ETL/データ集計、レポート生成
  • API バックフィル、バッチ送信(Slack/メール等)
  • 定期メンテナンス(不要データ削除、サマリー作成など)

前提・準備

  • イメージは Artifact Registry に集約します。
  • job.yaml を単一の真実源(SSOT)として宣言的に管理します。
  • CI/CD は Cloud Build で、ビルド・プッシュ後に gcloud run jobs replace を実行します。
  • 定期実行は Cloud Scheduler、イベント駆動は Pub/Sub、手動実行はオペレーションから行います。

ビルドとデプロイ(概要)

  • アプリのビルド→イメージを Artifact Registry へプッシュ。
  • job.yaml のイメージタグを更新し、gcloud run jobs replace で適用。
  • 実行はトリガー(スケジューラ/イベント/手動)で行い、CD では自動実行しない運用を推奨。

設計の要点(ジョブ)

  • 並列実行: taskCountparallelism を設計に合わせて設定。
  • 再試行: maxRetries はタスク単位。冪等性で重複実行に耐える。
  • タイムアウト: timeoutSeconds を処理時間に見合う値へ。

実行と観測(概要)

  • 実行トリガー: Cloud Scheduler、Pub/Sub、手動。
  • 観測: Cloud Logging に標準出力/標準エラー。Error Reporting と Alerting を連携。

運用・ライフサイクル

  • 更新は job.yaml を更新して jobs replace を実施(宣言的)。
  • 削除は jobs delete。ラベル・アノテーションは管理タグを活用。

スケジューリング・イベント連携(概要)

  • Cloud Scheduler: CRON で jobs.run を呼ぶ。最小権限でサービスアカウントを付与。
  • Pub/Sub: メッセージ受信をトリガーに実行(ワーク分割・冪等性設計)。
  • 手動実行: オペレーション手順として実行・監視を行う。

並列実行と再試行の設計メモ

  • 並列実行: --tasks=N で N 個のタスクを並列に起動。タスク間でワークを分割する設計にする(例: シャーディングやページング)。
  • 再試行: --max-retries はタスク単位。冪等設計にして重複実行に耐える。
  • タイムアウト: 長時間ジョブは --task-timeout を十分大きく。中断されるときは SIGTERM を受ける想定で安全に終了させる。
  • データ授受: ステップごとのデータの授受は、Cloud Storage 利用が推奨。

YAMLでのリソース定義

CLI オプションでも管理できますが、再現性・コードレビュー性の観点から YAML で定義して replace する運用をおすすめします。以下は VPC 設定を含む最小例です。

job.yaml
apiVersion: run.googleapis.com/v1
kind: Job
metadata:
  name: job-sample
  labels:
    cloud.googleapis.com/location: asia-northeast1
spec:
  template:
    template:
      metadata:
        annotations:
          # 直結 VPC(Direct VPC egress)。JSON 文字列で指定
          run.googleapis.com/network-interfaces: '[{"network":"projects/PROJECT_ID/global/networks/NETWORK","subnetwork":"projects/PROJECT_ID/regions/asia-northeast1/subnetworks/SUBNET"}]'
          # すべてのアウトバウンドを VPC 経由にする場合
          run.googleapis.com/vpc-access-egress: all-traffic
      spec:
        serviceAccountName: job-sa@PROJECT_ID.iam.gserviceaccount.com
        containers:
        - image: asia-northeast1-docker.pkg.dev/PROJECT_ID/app-repo/job-sample:latest
          env:
          - name: NODE_ENV
            value: production
        timeoutSeconds: 600
        maxRetries: 1
    taskCount: 1
    parallelism: 1

適用は gcloud run jobs replace job.yaml を用います(CIとRelease参照)。

補足:

  • VPC: run.googleapis.com/network-interfaces はネットワーク/サブネットを JSON 文字列で指定します。run.googleapis.com/vpc-access-egressall-traffic(全量)/private-ranges-only(プライベート範囲のみ)を選択。
  • 帯域制限: Cloud Run の各インスタンス(ジョブの各タスク相当)のアウトバウンド帯域は 1 Gbps が上限です。大量転送がある処理は並列数・分割・再試行を設計してください。

アーキテクチャ

構成の考え方:

  • CI/CD: Cloud Build がイメージをビルド/プッシュし、gcloud run jobs replacejob.yaml を宣言的に適用。
  • イベント: Cloud Scheduler/ Pub/Sub/手動実行で Cloud Run ジョブを起動。
  • 観測: Cloud Loggingを連携し、失敗検知と通知を自動化。
  • ネットワーク: VPC egress を要件に合わせて選択。大容量転送は 1 Gbps/インスタンスの上限を考慮し並列度設計。

Cloud Run サービスとの違い

  • HTTP サーバー不要(プロセスが終われば終了)。
  • 課金単位は実行中の vCPU/メモリ時間。アイドル課金はなし。
  • スケールはタスク数ベース。リクエスト駆動ではない。
  • ヘルスチェックは不要。終了コードで成否を判定。

トラブルシュートのメモ

  • コンテナが即終了する: エントリポイント(CMD/ENTRYPOINT)が正しいか確認。
  • 失敗が続く: 退出コードの確認、--max-retries と冪等性、外部依存のタイムアウト設定を見直す。
  • ログが出ない: 標準出力/標準エラーに出力しているか、Cloud Logging のフィルタで resource.type=cloud_run_job を確認。

おわりに

Cloud Run ジョブは「HTTP がいらない一回きりの処理」を手早く安全に動かすのに便利です。ここにある雛形とコマンドを土台に、プロジェクトのガードレール(IAM/ネットワーク/監視)を整えて使っていきます。


付録: Cloud Build サンプル(CI と Release)

宣言的デプロイ(gcloud run jobs replace)を前提に、CI 用と Release 用の YAML 例を示します。テンプレート置換は簡易に sed を利用しています。

CI: プルリク/ブランチ向け(ビルドと一時タグ)

cloudbuild.ci.yaml
substitutions:
  _REGION: asia-northeast1
  _REPO: app-repo
  _JOB_NAME: job-sample

steps:
  - name: gcr.io/cloud-builders/docker
    args: ['build', '-t', '${_REGION}-docker.pkg.dev/$PROJECT_ID/${_REPO}/${_JOB_NAME}:${SHORT_SHA}', '.']

  - name: gcr.io/cloud-builders/docker
    args: ['push', '${_REGION}-docker.pkg.dev/$PROJECT_ID/${_REPO}/${_JOB_NAME}:${SHORT_SHA}']

# 任意: SBOM生成/脆弱性スキャン等

images:
  - '${_REGION}-docker.pkg.dev/$PROJECT_ID/${_REPO}/${_JOB_NAME}:${SHORT_SHA}'

Release

cloudbuild.release.yaml
substitutions:
  _REGION: asia-northeast1
  _REPO: app-repo
  _JOB_NAME: job-sample

steps:
  # CI で作ったイメージを release タグへ付け替え
  - name: gcr.io/cloud-builders/docker
    entrypoint: bash
    args:
      - -c
      - |
        SRC=${_REGION}-docker.pkg.dev/$PROJECT_ID/${_REPO}/${_JOB_NAME}:${SHORT_SHA}
        DST=${_REGION}-docker.pkg.dev/$PROJECT_ID/${_REPO}/${_JOB_NAME}:release
        docker pull ${SRC}
        docker tag ${SRC} ${DST}
        docker push ${DST}

  # job.yaml をテンプレートからレンダリングし、宣言的に置換
  - name: gcr.io/cloud-builders/gcloud
    entrypoint: bash
    args:
      - -c
      - |
        IMAGE=${_REGION}-docker.pkg.dev/$PROJECT_ID/${_REPO}/${_JOB_NAME}:release
        sed "s#IMAGE_PLACEHOLDER#${IMAGE}#g; s#PROJECT_ID#${PROJECT_ID}#g; s#REGION#${_REGION}#g; s#JOB_NAME#${_JOB_NAME}#g" job.tmpl.yaml > job.yaml
        gcloud run jobs replace job.yaml --region=${_REGION}

artifacts:
  objects:
    location: gs://$PROJECT_ID-build-artifacts/jobs/
    paths: ['job.yaml']

job.tmpl.yaml(例)

job.tmpl.yaml
apiVersion: run.googleapis.com/v1
kind: Job
metadata:
  name: JOB_NAME
  labels:
    cloud.googleapis.com/location: REGION
spec:
  template:
    template:
      metadata:
        annotations:
          # 例: すべてのアウトバウンドをVPC経由
          run.googleapis.com/vpc-access-egress: all-traffic
      spec:
        serviceAccountName: job-sa@PROJECT_ID.iam.gserviceaccount.com
        containers:
        - image: IMAGE_PLACEHOLDER
          env:
          - name: NODE_ENV
            value: production
        timeoutSeconds: 600
        maxRetries: 1
    taskCount: 1
    parallelism: 1

運用メモ:

  • CI はビルドと検証用タグの発行まで。Release で安定タグ付与と jobs replace を実施。
  • 実行は Scheduler/手動/イベントに分離。CD 直後の自動実行は避けると安全。
  • 大容量転送は 1 Gbps/インスタンスの上限を考慮し、並列度・分割を調整。

参考

リバナレテックブログ

Discussion