[GCP]Cloud Run jobsまとめ

Cloud Run jobsの概要を思い出したいときの自分用メモ

# Cloud Run jobs の概要
**デプロイ済みのコンテナイメージのプログラムを、任意のタイミング(手動だったりスケジュール実行だったり)で分割実行できる**

というもので、主にバッチ処理に使うもの。
1Job(後述)あたり、以下の設定(★)が必要。

- 実行させたいプログラムのコンテナイメージのURL (イメージはArtifact Registryへアップロードしておく必要あり)
- 実行に際しての各種設定
    - コンテナインスタンスのCPU, メモリ
    - Task(プログラムの分割実行単位)数
    - Taskの並列処理数 
    - 各Task失敗時の再試行回数
    - 各Taskのタイムアウト時間
    - コンテナインスタンス内の環境変数

## Cloud Run jobs の仕組み
以下のようなイメージで動いているらしい。
```
- Job
  - Execution
    - Task_1 --- コンテナ1で実行
    ...
    - Task_N --- コンテナNで実行
```

**Job**
先述の★の設定を保持するもの。
Jobに対して実行を要求すると、Executionが作成、さらにTaskが作成される。

**Task**
コンテナイメージのプログラムの分割実行単位。
1Taskあたり1コンテナインスタンスが割り当てられる。

**Execution**
Task群の進捗管理をする監督者のようなもの。
1Taskでも失敗すると、これを束ねるExecutionとしても失敗扱いになる。

※ExecutionとTaskの関係は、負荷試験ツールJMeterのMasterとSlaveの関係に近いものだと思っている(全然用途も違うし古いけど)

参考

https://blog.g-gen.co.jp/entry/cloud-run-jobs-explained#Cloud-Run-jobs-%E3%81%AE%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E3%83%A2%E3%83%87%E3%83%AB

### 並列処理させるには

>ジョブは、単一のタスクとしても、複数の独立したタスク（最大 10,000 個）としても構成でき、並列で処理できます。各タスクは 1 つのコンテナ インスタンスを実行し、障害発生時に再試行するように構成できます。各タスクはインデックスを認識します。インデックスは CLOUD_RUN_TASK_INDEX 環境変数に格納されます。タスクの総数は CLOUD_RUN_TASK_COUNT 環境変数に格納されます。データを並行して処理する場合は、どのタスクがデータのどのサブセットを処理するのかはコードによって判断されます。

引用元: https://cloud.google.com/run/docs/create-jobs?hl=ja

ということで、
「デプロイするコンテナイメージのソースコード内で以下の環境変数を参照し、どの処理をさせるかを割り振るようにコーディングする」
模様。

- CLOUD_RUN_TASK_COUNT: Jobに設定したタスク総数
- CLOUD_RUN_TASK_INDEX: 現在、プログラムを実行しているTaskのインデックス

## GCPの類似サービスとの比較
### Cloud Run jobs vs Batch
双方とも似たようなサービス。
参考記事によると、

- 1ジョブが1時間で処理終わらない、GPUを利用したいならばBatch一択
- 既存のバッチスクリプトをGCPへさっと移行させたいならばBatchの方がよさそう

という感じで、その他もろもろの要件についてはどちらでも対応可能らしい。
参考記事の感じだと、料金未考慮の場合Batch一択でいいのでは説が・・・

ちなみにCloud Run jobsのほうが後発。
- Batch 2022/10/11 GA 
- Cloud Run jobs 2023/4/26 GA

**参考**

https://cloud.google.com/blog/ja/products/serverless/cloud-run-vs-cloud-functions-for-serverless

https://zenn.dev/google_cloud_jp/articles/c99697707e3b2c

### Cloud Run jobs vs Cloud Function
Cloud Function は自らコンテナイメージを作成してアップロードする必要はなく、ソースコードをアップロードすればデプロイできる模様(内部的にはアップロード後にコンテナイメージがビルドされるのだが)。

ただ、以下の制限があることを考えると、コンテナイメージのビルドが苦でないならば、新規にジョブを実行するシステムを整える上では候補から除外してよさそう。
- 利用できる言語は限定されている(といっても主要なWeb系言語は抑えられている)
- GCPサービスのイベントをトリガーとした実行の場合は10分でタイムアウト

**参考**

https://blog.g-gen.co.jp/entry/cloud-run-explained#Cloud-Run-%E3%81%A8-Cloud-Functions-%E3%81%AE%E9%81%95%E3%81%84

# 実際に利用する際のTips
## job実行時に外部から引数を追加で与える
Cloud Run jobs のWebコンソールから直接実行する際に、「オーバーライドを使用して実行」から以下の「コンテナ設定」で与えて実行できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59542/543a67d7-1c8c-54f8-4004-8578836945b1.png)

`-<引数名>=<引数>`で与えられる

## job実行時の環境変数を設定
(gcloud run jobsコマンド利用の場合)

```
# 直接値を注入する場合
## job新規作成時
gcloud run jobs create <job名> --image <コンテナイメージのURL> --set-env-vars=<環境変数名1>=<環境変数値1>,...,<環境変数名N>=<環境変数値N>

## job更新時
gcloud run jobs update <job名> --set-env-vars=<環境変数名1>=<環境変数値1>,...,<環境変数名N>=<環境変数値N>

# Secret Managerに登録してあるシークレットの値を注入する場合
## job新規作成時
gcloud run jobs create <job名> --image <コンテナイメージのURL> --set-secrets=<環境変数名1>=<シークレット1名>:<シークレット1のバージョン>,...,<環境変数名N>=<シークレットN名>:<シークレットNのバージョン>

## job更新時
gcloud run jobs update <job名> --set-secrets=<環境変数名1>=<シークレット1名>:<シークレット1のバージョン>,...,<環境変数名N>=<シークレットN名>:<シークレットNのバージョン>
```

`--set-env-vars`フラグ及び利用可能な類似のフラグ
```
--set-env-vars=: 対象jobに過去に登録した全ての環境変数を抹消してから登録
--update-env-vars=: set-env-varsの過去分抹消しない版
--env-vars-file=<FILE_PATH>: set-env-varsのYAMLファイルで読み込ませる版
```

`--set-secrets`フラグ及び利用可能な類似のフラグ
```
--set-secrets=: 対象jobに過去に登録した全てのシークレット用環境変数を抹消してから登録
--update-secrets=: set-sectetsの過去分抹消しない版
--env-vars-file=<FILE_PATH>: set-env-varsのYAMLファイルで読み込ませる版
```


- 直接値を注入するフラグ、シークレットの値を注入するフラグともに併用可能である(動確済み)。
- `--set-secrets`フラグでSecret Manager側のシークレットが削除されるわけではないこと動確済み(当たり前ではあるが)。
- 既存および過去に実行されたjobに設定した環境変数は、Cloud Run jobsのWebコンソール上で直接確認可能。


参考: 

https://cloud.google.com/run/docs/configuring/environment-variables?hl=ja#setting-jobs

https://cloud.google.com/run/docs/configuring/secrets?hl=ja#mounting-secrets-job