Cloud Run jobsを用いてバッチ処理を実現する
はじめに
こんにちは、クラウドエース バックエンド ディビジョン所属の許です。
今回は、Cloud Run の機能の一つである Cloud Run jobs について、使用例を交えながら解説していきます。
Cloud Run jobs とは
Cloud Run には service(以下、サービス)と jobs(以下、ジョブ)の2つの機能が存在しています。どちらも既存のコンテナ イメージを用いて処理を実行できるという点においては同じです。
Cloud Run を使用するときは大抵がサービスであり、リクエストを受信して処理するというような使い方が可能です。
しかし、ジョブはタスクを実行するだけであり、処理が完了すると終了してしまいます。実行時はパラメータの入力も受け付けず、事前に実装した処理が実行されるだけとなっております。
Cloud Run jobs の特徴
- 複数タスクの同時実行による並列処理
- ジョブ実行失敗時の再試行
- タスクの最大実行時間(タイムアウト)が設定できる
- デフォルトの実行時間は 10 分
- 実行時間を設定で長くしたり、短くしたりできる
- 最長は 24 時間まで
- 実行環境は第 2 世代のCloud Run
実装について
私は社内ツールのバッチ処理実装に Cloud Run jobs を利用しました。
今回は実際に社内ツールでの実装例を基に、Cloud Run jobs の使い方を解説していきます。
特にコード面での実装は抽象的な解説になってしまいますが、ご容赦ください。
また、社内ツールにはすでにサービス部分の実装が完了していたため、この先の解説ではサービスが存在しているという前提での解説になります。
開発言語
Go(v1.20)
時間がない人向けの実装ダイジェスト
[実装]→[Google Cloud コンソールでの操作]の大きく2段階に分けて作業する必要があります。
実装では、コードを実装後に Dockerfile と cloudbuild.yaml ファイルを作成します。
Google Cloud では、Cloud Build トリガーを作成し、ジョブを作成します。
最後に Cloud Build トリガーを実行することで、ジョブが正常に作成出来ます。
実装
社内ツールでは2つのバッチ処理を実装しました。
- データベース(以下、DB) のマイグレーション処理
- OR Mapper での定義によって、定期的に DB をマイグレーションする処理
- 社内情報同期処理
- 新入社員の情報や所属情報などの社内に存在する各システムの DB から情報を引っ張ってきて、社内ツールの情報を最新にするための処理
今回は社内情報同期処理を例に解説していきます。
コードでのタスク実装
前述の通り API 用のサービスは存在しており、そのコードの一部としてコードを書いていきます。
具体的なコードは省略しますが、API 用に作成していた社内情報更新処理をそのまま用いて実装することができました。
処理の流れとしては以下の通り
- 現在の DB に登録されている社内情報を取得(古い情報)
- 最新の従業員情報をさまざまな社内 DB から取得(最新の情報)
- 現在と最新の情報の差分を比較し、変更があった場合は DB を最新の情報に同期する
ここで忘れていけないのが、バッチ起動用の main.go
を作成すること
ここで依存関係を定義してあげることによって、バッチ処理の範囲を定義することができます。(筆者はWireを使いました)
Dockerfile の作成
ここでバッチ処理環境のコンテナを作成するための Dockerfile を作成します。
先ほど作成した main.go
を基準にコンテナが作成されるような記述をしてあげる必要があります。
FROM golang:1.20
WORKDIR /go/src/app
COPY go.mod go.sum ./
RUN go mod download
COPY . ./
# Build
RUN CGO_ENABLED=0 GOOS=linux go build -o /syncEmployees ./{作成したmain.goが存在するフォルダ}
CMD ["/syncEmployees"]
Cloudbuild.yaml の作成
Cloudbuild で自動的にデプロイが実現できるよう Cloudbuild.yaml
を作成します。
前述の Dockerfile を基準にコンテナが作成されるように記述してあげる必要があります。
steps:
- name: gcr.io/cloud-builders/docker
args:
- build
- '-t'
- '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
- '-f'
- 'Dockerfile/{対象のDockerfile}'
- '.'
id: Build
- name: 'gcr.io/cloud-builders/docker'
args:
- 'push'
- '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
id: 'Push'
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:slim'
args:
- 'run'
- 'jobs'
- 'update'
- '$_SERVICE_NAME'
- '--image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
- >-
--labels=managed-by=gcp-cloud-build-deploy-cloud-run,commit-sha=$COMMIT_SHA,gcb-build-id=$BUILD_ID,gcb-trigger-id=$_TRIGGER_ID,$_LABELS
- '--region=$_DEPLOY_REGION'
- '--quiet'
id: Deploy
entrypoint: gcloud
images:
- '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
options:
substitutionOption: ALLOW_LOOSE
substitutions:
_PLATFORM: managed
_SERVICE_NAME: (省略)
_LABELS: (省略)
_TRIGGER_ID: (省略)
_DEPLOY_REGION: asia-northeast1
_GCR_HOSTNAME: asia.gcr.io
tags:
- gcp-cloud-build-deploy-cloud-run
- gcp-cloud-build-deploy-cloud-run-managed
Cloud Run での操作
次に実装を Google Cloud 環境に反映させるために、以下の操作を行います。
Cloud Build トリガーの設定
先ほど作成した社内情報同期処理のトリガーを作成します。
環境変数など入力多い場合は入力が面倒なため、サービスで作成していたトリガーをコピーして編集します。
主に編集する箇所は以下の通りです。
- トリガー名
-
cloudbuild.yaml
の参照場所 - 代入変数(必要に応じて)
ジョブを作成
トリガーを起動するだけではジョブは作成できないので、Cloud Run の画面でジョブを作成する。
サービスと同様に設定した方が良いところは、サービス同様の値を設定する。
- コンテナ イメージを選択する。(最初はコンテナ イメージが存在していないはずなので、適当に選んでも可。後から変更する)
- ジョブ名を制定
- リージョンを選択
- タスク数を決定(今回は1を設定)
- 全般タブでタイムアウトの時間と再試行回数を設定
- 変数とシークレットタブで環境変数やシークレット変数を追加
- 接続タブで接続したい Cloud SQL インスタンスを指定
- セキュリティタブで権限があるサービス アカウントを選択する(必要な権限に関してはこちら)
- 作成を押す
ここまでの手順を踏むことでジョブを作成することができます。
コードの実装の手間などを考えると、少々骨の折れる作業ですが、API と同じコード内でバッチを管理できるメリットが大きいなと使用していて感じました。
必要最低限の設定はここで終わりですが、スケジューラ トリガーを設定することで、定期実行が可能になります。
オプション:スケジューラ トリガーの設定
なんと、Cloud Run jobs の画面にはスケジューラ トリガーを設定してくださいと言わんばかりに、トリガー
のタブが存在しているんです!
ここからスケジューラ トリガーを簡単に設定することができます。
- スケジューラを設定したいジョブを開く
- 詳細画面が出てくると、トリガータブを開く
- スケジューラ トリガーを追加する(設定方法などは Cloud Schduler と大体同じなので省略)
このような手順で簡単にスケジューラ トリガーを作成することが可能です。
おわりに
今回の記事では Cloud Run jobs を利用してバッチ処理を実装する方法について、実際の実装例を交えながら紹介しました。
少々抽象度の高い記事かもしれませんが、実装の参考にしていただけると幸いです。
Discussion