こんにちは。 CTO 室の yuina です。
引き続き某 CTO からの無茶振りを捌いております。
今回 GCP の Workflows を使って、複数の Cloud Run の job に対し、依存関係を作りながら実装をしたので、備忘録として残しておきます。
GCPのWorkflowsとは
GCP の Workflows は、GCP 上でのワークフローを定義するためのサービスです。 AWSにも同様のサービスとしてAWS Step FunctionsやAmazon SWFがあります。
GCPのWorkflowsは、GCPのサービス以外にも、Googleの各種サービスをシームレスに組み合わせたりもできるので、G Suite等のサービスとも連携ができるため、エンジニアの方以外でも使う機会はあるかもしれません。
個人的にもGmail、Googleカレンダー等と組み合わせてオートメーション的なものを作っていたりしています。
どんなことをしたのか
今回はWorkflowsにてCloud Run Jobsを並列実行したり、依存を持たせることをしながら対応しました。
前提として、Cloud Run Jobsは既に作成済みで、Cloud Run Jobsを呼び出すだけの実装です。
以下はサンプルコードです。
main: params: [input_params] steps: - step_1: assign: - var_a: ${default(map.get(input_params, "param_a"), "")} - var_b: ${default(map.get(input_params, "param_b"), "")} - var_c: ${default(map.get(input_params, "param_c"), "")} - project_id: project-xyz - job_location: asia-northeast1 - step_2: parallel: branches: - branch_a: steps: - task_a: call: googleapis.run.v1.namespaces.jobs.run args: name: ${"namespaces/" + project_id + "/jobs/job-abc-1"} location: ${job_location} body: overrides: containerOverrides: - args: ${["script.py", "--param-a", var_a, "--param-c", var_c, "--param-b", var_b]} result: result_a - branch_b: steps: - task_b: call: googleapis.run.v1.namespaces.jobs.run args: name: ${"namespaces/" + project_id + "/jobs/job-abc-2"} location: ${job_location} body: overrides: containerOverrides: - args: ${["script.py", "--param-a", var_a, "--param-b", var_b]} result: result_b - step_3: call: googleapis.run.v1.namespaces.jobs.run args: name: ${"namespaces/" + project_id + "/jobs/job-abc-5"} location: ${job_location} body: overrides: containerOverrides: - args: ${["script.py", "--param-a", var_a]} result: final_result - end_step: return: ${final_result}
このyamlを図にすると以下のようになります。
GCPの画面上でyamlを書いていくと、上記のような図を自動でプレビューしながら作成できるので、流れをイメージしやすいです。
また、構文に関してはドキュメントがあるため、yamlの構文を理解していれば、すぐに実装できると思います。
yamlのポイントとなりそうな部分を解説します。
1. 並列実行
- step_2: parallel: branches: - branch_a: steps: - task_a: call: googleapis.run.v1.namespaces.jobs.run args: name: ${"namespaces/" + project_id + "/jobs/job-abc-1"} location: ${job_location} body: overrides: containerOverrides: - args: ${["script.py", "--param-a", var_a, "--param-c", var_c, "--param-b", var_b]} result: result_a - branch_b: steps: - task_b: call: googleapis.run.v1.namespaces.jobs.run args: name: ${"namespaces/" + project_id + "/jobs/job-abc-2"} location: ${job_location} body: overrides: containerOverrides: - args: ${["script.py", "--param-a", var_a, "--param-b", var_b]} result: result_b
上記のように、parallel
を使うことで、複数のjobを並列実行することができます。
並列実行がすべて完了した後に、次のステップに進むような形になります。
2. Cloud Run Jobsを呼び出す
call: googleapis.run.v1.namespaces.jobs.run args: name: ${"namespaces/" + project_id + "/jobs/job-abc-1"} location: ${job_location} body: overrides: containerOverrides: - args: ${["script.py", "--param-a", var_a, "--param-c", var_c, "--param-b", var_b]}
上記のように、Cloud Run Jobsを呼び出すことができます。
call
の部分でCloud Run Jobsの呼び出しを行い、args
の部分でjobの名前や引数を指定します。
containerOverridesの部分で、Cloud Run Jobsに渡す引数を指定する形をとります。
事前にinitで引数となる定義しておくことで、Workflows実行時にjson形式で引数の元となる値を渡すことができるようになり、同じ引数を使いまわしたり、yamlの可読性を上げることができます。
3. Cloud Run job が失敗したときの挙動
Cloud Run jobがexit code 0 以外で終了した場合、Workflowsは途中で失敗として扱うようになっています。 そのため、Cloud Run Jobsのどれかが失敗した場合は、Workflows全体が失敗として扱われます。
IaCでのデプロイ
WorkflowsはTerraformでのデプロイも可能です。 Terraformで書く場合、書き方によってはGCPの画面上で書く場合と同じ構文が使えず、手直しする必要があります。
また、実際に困った部分としては、terraform planでは特にエラーが出ないのに、applyするとエラーになることがありましたので、注意が必要です。
まとめ
Workflowsを使うことで、GCPの各種サービスを組み合わせて、シンプルに依存や並列実行を実装することができました。 GCPのサービスのみに囚われずに利用もできるため、一度触ってみると面白いと思います。