Eventarc と Workflows でイベント駆動型オーケストレーションを構築する

1. はじめに

cb762f29e9183a3f.png 1c05e3d0c2bd2b45.png a03f943ca09ac4c.png

Eventarc を使用すると、さまざまなソースのイベントと Cloud Run サービスを簡単に接続できます。マイクロサービスが疎結合かつ分散されたイベント ドリブン アーキテクチャを構築できます。イベントの取り込み、配信、セキュリティ、認可、エラー処理を自動的に行います。

Workflows はフルマネージドのオーケストレーション プラットフォームで、定義した順序(ワークフロー)でサービスを実行します。これらのワークフローでは、Cloud Run や Cloud Functions でホストされているサービス、Cloud Vision AI や BigQuery などの Google Cloud サービス、任意の HTTP ベースの API を組み合わせることができます。

この Codelab では、画像を処理するマイクロサービスのイベント ドリブン オーケストレーションを構築します。Workflows を使用して、4 つの画像処理 Cloud Functions の順序、入力、出力をオーケストレートします。その後、オーケストレーションと、Eventarc との疎結合で Cloud Storage イベントに応答できるようにします。

最終的には、画像を処理するための柔軟かつ構造化されたサーバーレス アーキテクチャが完成します。

e372ceed8c26c5fb.png

学習内容

  • Eventarc と Workflows の概要
  • Cloud Functions サービスをデプロイする方法
  • Workflows を使用してサービスをオーケストレートする方法
  • Eventarc を使用して Workflows が Cloud Storage イベントに応答する方法

2. 設定と要件

セルフペース型の環境設定

  1. Google Cloud Console にログインして、プロジェクトを新規作成するか、既存のプロジェクトを再利用します。Gmail アカウントも Google Workspace アカウントもまだお持ちでない場合は、アカウントを作成してください。

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • プロジェクト名は、このプロジェクトの参加者に表示される名称です。Google API では使用されない文字列です。この値はいつでも更新できます。
  • プロジェクト ID は、すべての Google Cloud プロジェクトにおいて一意でなければならず、不変です(設定後は変更できません)。Cloud コンソールでは一意の文字列が自動生成されます。通常、それが何であるかは関係ありません。ほとんどの Codelab では、プロジェクト ID を参照する必要があります(通常は PROJECT_ID として識別されます)。生成された ID が気に入らない場合は、別のランダムな ID を生成できます。または、ご自身でお試しになることもできます。このステップを終えた後は変更できず、プロジェクト期間中は維持されます。
  • なお、3 つ目の値は、一部の API で使用される [プロジェクト番号] です。これら 3 つの値について詳しくは、こちらのドキュメントをご覧ください。
  1. 次に、Cloud のリソースや API を使用するために、Cloud コンソールで課金を有効にする必要があります。この Codelab の操作をすべて行って、費用が生じたとしても、少額です。このチュートリアルの終了後に課金が発生しないようにリソースをシャットダウンするには、作成したリソースを削除するか、プロジェクト全体を削除します。Google Cloud の新規ユーザーは、300 米ドル分の無料トライアル プログラムをご利用いただけます。

Cloud Shell の起動

Google Cloud はノートパソコンからリモートで操作できますが、この Codelab では、Google Cloud Shell(Cloud 上で動作するコマンドライン環境)を使用します。

Google Cloud Console で、右上のツールバーにある Cloud Shell アイコンをクリックします。

55efc1aaa7a4d3ad.png

プロビジョニングと環境への接続にはそれほど時間はかかりません。完了すると、次のように表示されます。

7ffe5cbb04455448.png

この仮想マシンには、必要な開発ツールがすべて用意されています。永続的なホーム ディレクトリが 5 GB 用意されており、Google Cloud で稼働します。そのため、ネットワークのパフォーマンスと認証機能が大幅に向上しています。この Codelab での作業はすべて、ブラウザ内から実行できます。インストールは不要です。

gcloud を設定する

Cloud Shell で、プロジェクト ID とアプリケーションのデプロイ先のリージョンを設定します。これらの情報は、PROJECT_ID 変数と REGION 変数として保存します。使用可能なリージョンについては、Cloud Functions のロケーションをご覧ください。

PROJECT_ID=your-project-id
gcloud config set project $PROJECT_ID

ソースコードを取得する

アプリケーションのソースコードは、eventarc-samples リポジトリの processing-pipelines フォルダにあります。

リポジトリのクローンを作成します。

git clone https://github.com/GoogleCloudPlatform/eventarc-samples.git

eventarc-samples/processing-pipelines フォルダに移動します。

cd eventarc-samples/processing-pipelines

3. アーキテクチャの概要

アプリケーションのアーキテクチャは次のとおりです。

6aa6fbc7721dd6b6.png

  1. 画像が入力バケットに保存され、Cloud Storage create イベントが生成されます。
  2. Cloud Storage の作成イベントは、Cloud Storage トリガーを介して Eventarc によって読み取られ、CloudEvent として Workflows に渡されます。
  3. ワークフローの最初のステップでは、Cloud Functions の関数サービスの Filter が Vision API を使用して画像が安全かどうかを判断します。イメージが安全な場合、Workflows は次のステップに進みます。
  4. ワークフローの 2 番目のステップでは、Labeler(Cloud Functions の関数サービス)が Vision API で画像のラベルを抽出し、出力バケットに保存します。
  5. 3 番目のステップである Resizer(別の Cloud Functions 関数サービス)が ImageSharp を使用して画像のサイズを変更し、サイズ変更した画像を出力バケットに保存します。
  6. 最後のステップでは、別の Cloud Function サービスである Watermarker が、ImageSharp を使用してサイズ変更した画像にラベラーからのラベルの透かしを追加し、画像を出力バケットに保存します。

このアプリケーションは Cloud Storage イベントによってトリガーされるため、イベント ドリブンです。画像の処理はワークフロー内で行われるため、これはオーケストレーションです。結局のところ、柔軟で構造化されたサーバーレス アーキテクチャによる画像処理のためのイベント ドリブンなオーケストレーションです。

4. バケットを作成する

ユーザーが画像をアップロードする入力バケットと、画像処理パイプラインで処理された画像を保存する出力バケットを作成します。

Cloud Shell で次のコマンドを実行します。

REGION=us-central1
BUCKET1=$PROJECT_ID-images-input
BUCKET2=$PROJECT_ID-images-output

gsutil mb -l $REGION gs://$BUCKET1
gsutil mb -l $REGION gs://$BUCKET2

5. フィルタ サービスをデプロイする

まず、1 つ目のサービスをデプロイします。この Cloud Functions サービスはバケットとファイルの情報を受け取り、画像が Vision API で安全かどうかを判断して結果を返します。

まず、Cloud Functions gen2 と Vision API に必要なサービスを有効にします。

gcloud services enable \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  cloudfunctions.googleapis.com \
  run.googleapis.com \
  vision.googleapis.com

最上位の processing-pipelines フォルダ内で、サービスをデプロイします。

SERVICE_NAME=filter

gcloud functions deploy $SERVICE_NAME \
  --gen2 \
  --allow-unauthenticated \
  --runtime dotnet3 \
  --trigger-http \
  --region=$REGION \
  --entry-point Filter.Function \
  --set-build-env-vars GOOGLE_BUILDABLE=image-v3/filter/csharp

関数をデプロイしたら、サービス URL を変数に設定します。これは後で必要になります。

FILTER_URL=$(gcloud functions describe $SERVICE_NAME --region=$REGION --gen2 --format 'value(serviceConfig.uri)')

6. ラベラー サービスをデプロイする

2 つ目の Cloud Functions サービスはバケットとファイルの情報を受け取り、Vision API で画像のラベルを抽出して出力バケットに保存します。

最上位の processing-pipelines フォルダ内で、サービスをデプロイします。

SERVICE_NAME=labeler

gcloud functions deploy $SERVICE_NAME \
  --gen2 \
  --allow-unauthenticated \
  --runtime dotnet3 \
  --trigger-http \
  --region=$REGION \
  --set-env-vars BUCKET=$BUCKET2 \
  --entry-point Labeler.Function \
  --set-build-env-vars GOOGLE_BUILDABLE=image-v2/labeler/csharp

関数をデプロイしたら、サービス URL を変数に設定します。これは後で必要になります。

LABELER_URL=$(gcloud functions describe $SERVICE_NAME --region=$REGION --gen2 --format 'value(serviceConfig.uri)')

7. サイズ変更サービスをデプロイする

この Cloud Functions サービスは、バケットとファイルの情報を受け取り、ImageSharp を使用して画像のサイズを変更し、出力バケットに画像を保存します。

最上位の processing-pipelines フォルダ内で、サービスをデプロイします。

SERVICE_NAME=resizer

gcloud functions deploy $SERVICE_NAME \
  --gen2 \
  --allow-unauthenticated \
  --runtime dotnet3 \
  --trigger-http \
  --region=$REGION \
  --set-env-vars BUCKET=$BUCKET2 \
  --entry-point Resizer.Function \
  --set-build-env-vars GOOGLE_BUILDABLE=image-v2/resizer/csharp \
  --timeout=120s

timeout の値が 2 分になっているため、リサイザ関数の処理時間が長くなります。

関数をデプロイしたら、サービス URL を変数に設定します。これは後で必要になります。

RESIZER_URL=$(gcloud functions describe $SERVICE_NAME --region=$REGION --gen2 --format 'value(serviceConfig.uri)')

8. 透かしサービスをデプロイする

この Cloud Functions サービスは、バケット、ファイル、ラベルの情報を受け取り、ファイルを読み取り、ImageSharp を使用してラベルを透かしとして画像に追加し、画像を出力バケットに保存します。

最上位の processing-pipelines フォルダ内で、サービスをデプロイします。

SERVICE_NAME=watermarker

gcloud functions deploy $SERVICE_NAME \
  --gen2 \
  --allow-unauthenticated \
  --runtime dotnet3 \
  --trigger-http \
  --region=$REGION \
  --set-env-vars BUCKET=$BUCKET2 \
  --entry-point Watermarker.Function \
  --set-build-env-vars GOOGLE_BUILDABLE=image-v2/watermarker/csharp

関数をデプロイしたら、サービス URL を変数に設定します。これは後で必要になります。

WATERMARKER_URL=$(gcloud functions describe $SERVICE_NAME --region=$REGION --gen2 --format 'value(serviceConfig.uri)')

この時点で、4 つの Cloud Functions の関数がすべてデプロイされ、実行されているはずです。

76a218568982c90c.png

9. ワークフローの定義とデプロイ

Workflows を使用すると、フィルタ、ラベル付け、サイズ変更、透かしのサービスを 1 つのワークフローにまとめることができます。Workflows は、定義したパラメータを使用して、これらのサービスの呼び出しをオーケストレートします。

まず、Workflows に必要なサービスを有効にします。

gcloud services enable \
  workflows.googleapis.com \
  workflowexecutions.googleapis.com

定義

Workflows は、パラメータとして CloudEvent を受け取ります。トリガーを作成すると、Eventarc から取得されます。最初の 2 つのステップでは、Workflows がイベントをログに記録し、そのイベントからバケットとファイルの情報を抽出します。

main:
  params: [event]
  steps:
  - log_event:
      call: sys.log
      args:
          text: ${event}
          severity: INFO
  - extract_bucket_and_file:
      assign:
      - bucket: ${event.data.bucket}
      - file: ${event.data.name}

filter ステップで、Workflows は前にデプロイしたフィルタ サービスを呼び出します。次に、ファイルの安全性をログに記録してチェックします。

  - filter:
      call: http.post
      args:
        url: FILTER_URL # TODO: Replace
        auth:
          type: OIDC
        body:
            bucket: ${bucket}
            file: ${file}
      result: filterResponse
  - log_safety:
      call: sys.log
      args:
          text: ${filterResponse.body.safe}
          severity: INFO
  - check_safety:
      switch:
        - condition: ${filterResponse.body.safe == true}
          next: label
      next: end

label ステップで、Workflows はラベラー サービスを呼び出し、レスポンスをキャプチャします(上位 3 つのラベル)。

  - label:
      call: http.post
      args:
        url: LABELER_URL # TODO: Replace
        auth:
          type: OIDC
        body:
            bucket: ${bucket}
            file: ${file}
      result: labelResponse

resize ステップで、Workflows はサイズ変更サービス サービスを呼び出し、レスポンス(サイズ変更された画像のバケットとファイル)をキャプチャします。

  - resize:
      call: http.post
      args:
        url: RESIZER_URL # TODO: Replace
        auth:
          type: OIDC
        body:
            bucket: ${bucket}
            file: ${file}
      result: resizeResponse

watermark ステップで、Workflows はサイズ変更された画像とラベルを使用して透かしサービスを呼び出し、結果(サイズ変更され透かしを入れた画像)をキャプチャします。

  - watermark:
      call: http.post
      args:
        url: WATERMARKER_URL # TODO: Replace
        auth:
          type: OIDC
        body:
            bucket: ${resizeResponse.body.bucket}
            file: ${resizeResponse.body.file}
            labels: ${labelResponse.body.labels}
      result: watermarkResponse

final ステップで、Workflows はラベラー、サイズ変更ツール、ウォーターマーク サービスから HTTP ステータス コードを返します。

  - final:
      return:
        label: ${labelResponse.code}
        resize: ${resizeResponse.code}
        watermark: ${watermarkResponse.code}

デプロイ

ワークフローをデプロイする前に、手動または sed を使用して、サービス URL がデプロイされた関数の URL に置き換えられていることを確認します。

最上位の processing-pipelines フォルダ内で、workflows.yaml ファイルが保存されている image-v3 フォルダに移動します。

cd image-v3/

sed を実行して、プレースホルダの URL を、デプロイされたサービスの実際の URL に置き換えます。

sed -i -e "s|FILTER_URL|${FILTER_URL}|" workflow.yaml
sed -i -e "s|LABELER_URL|${LABELER_URL}|" workflow.yaml
sed -i -e "s|RESIZER_URL|${RESIZER_URL}|" workflow.yaml
sed -i -e "s|WATERMARKER_URL|${WATERMARKER_URL}|" workflow.yaml

ワークフローをデプロイします。

WORKFLOW_NAME=image-processing

gcloud workflows deploy $WORKFLOW_NAME \
    --source=workflow.yaml \
    --location=$REGION

数秒後に、ワークフローがコンソールにデプロイされていることを確認します。

92cf4e758bdc3dde.png

10. トリガーを作成

ワークフローがデプロイされたので、最後のステップとして、Eventarc トリガーを使用してワークフローを Cloud Storage イベントに接続します。

1 回限りの設定

まず、Eventarc に必要なサービスを有効にします。

gcloud services enable \
 eventarc.googleapis.com

Eventarc トリガーで使用するサービス アカウントを作成します。

SERVICE_ACCOUNT=eventarc-trigger-imageproc-sa

gcloud iam service-accounts create $SERVICE_ACCOUNT \
  --display-name="Eventarc trigger image processing service account"

サービス アカウントを使用して Eventarc から Workflows を呼び出せるように、workflows.invoker ロールを付与します。

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --role roles/workflows.invoker \
  --member serviceAccount:$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com

eventarc.eventReceiver ロールを付与すると、サービス アカウントを

Cloud Storage トリガー:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --role roles/eventarc.eventReceiver \
  --member serviceAccount:$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com

Cloud Storage サービス アカウントに pubsub.publisher ロールを付与します。これは、Eventarc の Cloud Storage トリガーに必要です。

STORAGE_SERVICE_ACCOUNT="$(gsutil kms serviceaccount -p $PROJECT_ID)"

gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member serviceAccount:$STORAGE_SERVICE_ACCOUNT \
    --role roles/pubsub.publisher

作成

次のコマンドを実行してトリガーを作成します。このトリガーは、入力 Cloud Storage バケットからの新しいファイル作成イベントをフィルタし、前に定義したワークフローに渡します。

TRIGGER_NAME=trigger-image-processing

gcloud eventarc triggers create $TRIGGER_NAME \
  --location=$REGION \
  --destination-workflow=$WORKFLOW_NAME \
  --destination-workflow-location=$REGION \
  --event-filters="type=google.cloud.storage.object.v1.finalized" \
  --event-filters="bucket=$BUCKET1" \
  --service-account=$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com

トリガーが作成され、準備ができたことは、Cloud コンソールの [Eventarc] セクションで確認できます。

14330c4fa2451bc0.png

11. パイプラインをテストする

画像処理パイプラインで、Cloud Storage からイベントを受信する準備が整いました。パイプラインをテストするために、入力バケットに画像をアップロードします。

gsutil cp beach.jpg gs://$BUCKET1

写真をアップロードするとすぐに、Workflows の実行がアクティブな状態であることが表示されます。

36d07cb63c39e7d9.png

1 分ほど待つと、実行が成功したことがわかります。ワークフローの入力と出力も確認できます。

229200c79d989c25.png

出力バケットの内容を一覧表示すると、サイズ変更された画像、サイズ変更され透かしが入った画像、画像のラベルが表示されます。

gsutil ls gs://$BUCKET2

gs://$PROJECT_ID-images-output/beach-400x400-watermark.jpeg
gs://$PROJECT_ID-images-output/beach-400x400.png
gs://$PROJECT_ID-images-output/beach-labels.txt

再確認するには、サイズを変更した透かしを入れた画像を開いて結果を確認します。

75f3c0019ca842ce.jpeg

12. 完了

お疲れさまでした。これでこの Codelab は終了です。

学習した内容

  • Eventarc と Workflows の概要
  • Cloud Functions サービスをデプロイする方法
  • Workflows を使用してサービスをオーケストレートする方法
  • Eventarc を使用して Workflows が Cloud Storage イベントに応答する方法