2024/08/02
Cloud Run jobs を利用したバッチ処理
はじめに
Google Cloud 上でバッチ処理を行う際に、Cloud Run jobsを使用したので紹介します。 本記事では、他サービスとの比較とCloud Run jobsの使い方について説明します。
Google Cloud でバッチ処理できるサービス
Cloud Run jobs を使用するにあたって、他のサービスについても調べたのでそれぞれの特徴をまとめました。
Cloud Functions
様々なイベントをトリガーにできるので、特定のイベントが発生したときに動かしたいバッチ処理の場合は Cloud Functions を使うと良さそうです。 例えば Cloud Storage に画像がアップロードされた際に、自動的にサムネイルを作成したり、画像にフィルターをかけたりする処理が簡単に作れます。 しかし、最大実行時間に制限(60 分)があるため長時間の処理には適さない場合があります。
Batch
大規模なバッチ処理ワークロードを効率的に実行するためのフルマネージドなサービスです。 高性能コンピューティング(HPC)、機械学習、データ処理など、さまざまな種類のバッチジョブをスケーラブルかつ柔軟に実行できます。 また、最大実行時間に制限が無いので長時間の処理に適しています。 しかし、Cloud Functions や Cloud Run jobs よりも設定が複雑になってしまうので採用しませんでした。
Cloud Run jobs
Cloud Run の一機能で、バッチ処理や非同期タスクの実行に特化したサービスです。 最大実行時間に制限がありますが、24 時間実行できるのでほとんどのバッチ処理は問題ないでしょう。
Cloud Run jobs の基本要素
Cloud Run jobs のリソース構造
Cloud Run jobs は以下のようなリソースで構成されています。
ジョブ (Job)
実行したいタスクの全体像を定義するルートリソースです。
ジョブでは以下の項目を設定できます。
- コンテナイメージ
- タスク数
- 並列実行数
- リソース(各タスクに割り当てる CPU やメモリなどのリソース量)
- 環境変数
- サービスアカウント
タスク (Task)
ジョブによって定義されたタスクのインスタンスです。 タスクはジョブに設定された数だけ実行されます。コンテナインスタンスを 1:1 で用意し、コンテナインスタンスごとの進捗を管理します。タスクがエラーで終了した場合は、タスク単位で再実行もできます。
実行 (Execution)
タスクの実行履歴です。 ジョブの設定に応じてタスクを実行し、全てのタスクが完了するまでの状態を管理します。1 度作成した実行は、何度でも再実行が可能です。
Cloud Run jobs の作成・実行方法
サンプルアプリケーションの用意
以下のコードを適当なフォルダに作成します
環境変数にSLEEP_MS
を設定すると、設定した時間だけスリープするようになり、時間のかかる処理を再現できます。
FAIL_RATE
を設定すると、指定した確率でジョブがエラーになり、エラー時の挙動を確認できます。
main.js
1// Retrieve Job-defined env vars 2const { CLOUD_RUN_TASK_INDEX = 0, CLOUD_RUN_TASK_ATTEMPT = 0 } = process.env; 3// Retrieve User-defined env vars 4const { SLEEP_MS, FAIL_RATE } = process.env; 5 6// Define main script 7const main = async () => { 8 console.log( 9 `Starting Task #${CLOUD_RUN_TASK_INDEX}, Attempt #${CLOUD_RUN_TASK_ATTEMPT}...` 10 ); 11 // Simulate work 12 if (SLEEP_MS) { 13 await sleep(SLEEP_MS); 14 } 15 // Simulate errors 16 if (FAIL_RATE) { 17 try { 18 randomFailure(FAIL_RATE); 19 } catch (err) { 20 err.message = `Task #${CLOUD_RUN_TASK_INDEX}, Attempt #${CLOUD_RUN_TASK_ATTEMPT} failed.\n\n${err.message}`; 21 throw err; 22 } 23 } 24 console.log(`Completed Task #${CLOUD_RUN_TASK_INDEX}.`); 25}; 26 27// Wait for a specific amount of time 28const sleep = (ms) => { 29 return new Promise((resolve) => setTimeout(resolve, ms)); 30}; 31 32// Throw an error based on fail rate 33const randomFailure = (rate) => { 34 rate = parseFloat(rate); 35 if (!rate || rate < 0 || rate > 1) { 36 console.warn( 37 `Invalid FAIL_RATE env var value: ${rate}. Must be a float between 0 and 1 inclusive.` 38 ); 39 return; 40 } 41 42 const randomFailure = Math.random(); 43 if (randomFailure < rate) { 44 throw new Error("Task failed."); 45 } 46}; 47 48// Start script 49main().catch((err) => { 50 console.error(err); 51 process.exit(1); // Retry Job Task by exiting the process 52});
package.json
1{ 2 "main": "main.js", 3 "scripts": { 4 "start": "node main.js" 5 }, 6 "engines": { 7 "node": ">=20.0.0" 8 } 9}
Dockerfile
1FROM node:20 2WORKDIR /app 3COPY . . 4RUN npm install 5CMD [ "npm", "start" ]
コンテナをプッシュ
次のコマンドで Artifact Registry にコンテナをプッシュします。${REGION}
と${PROJECT_ID}
は各自で置き換えてください。
1gcloud builds submit --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/gcr.io/job-sample
ジョブを作成
今回は、以下の Cloud Run のコンソールから作成します。
https://console.cloud.google.com/run/jobs
「ジョブの作成」をクリックします。
「コンテナ イメージの URL」に先ほど作成したコンテナを選択します。
イメージ名が自動的に設定されます。
リージョンやタスク数はお好みで設定して下さい。
ジョブの実行
「実行」をクリックし、ジョブを開始します。
しばらく経つと、全てのタスクが完了し、実行が完了します。実行の詳細を開くとタスクが完了していることが確認でき、各タスクのログ等が確認できます。
作成した Job を定期実行する方法
「トリガー」タブを選択し、「スケジューラ トリガーを追加」をクリックします。
頻度を unix-cron 形式で選択します。
今回は 5 分ごと(*/5****
)に実行してみます。
指定した通り、5 分ごとにジョブが実行されました。
まとめ
今回は Cloud Run jobs について説明しましたが、各サービスのメリット・デメリットを比較し、要件に合った最適なサービスを選択することが重要です。 今後、他サービスにも触れる機会がありましたら紹介したいです。
参考
Author Profile
AIROU
プログラマーです 猫とラーメンが好きです
SHARE