Eventarc と Cloud Run 関数を使用して Cloud Storage からイベント処理をトリガーする

1. 概要

このラボでは、Cloud Storage バケット イベントと Eventarc を使用してイベント処理をトリガーする方法について学習します。Cloud Run 関数を使用して、データを分析し、画像を処理します。この関数は Google の Vision API を使用して、結果の画像を Cloud Storage バケットに保存します。

424779013ac38648.png

学習内容

画像処理パイプラインを構築する方法。

  • ストレージ バケットを構成する
  • Cloud Storage でオブジェクトの読み取りと書き込みを行う Cloud Run functions の関数を作成する
  • Eventarc トリガーをデプロイする
  • Vision API を統合して食品画像を検出する
  • エンドツーエンドのソリューションをテストして検証する

前提条件

  • このラボは、Cloud コンソールとシェル環境に精通していることを前提としています。
  • Cloud Storage、Cloud Run 関数、Vision API の使用経験があると役立ちますが、必須ではありません。

2. 設定と要件

Cloud プロジェクトの設定

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

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

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

Cloud Shell をアクティブにする

検索バーの右側にあるアイコンをクリックして Cloud Shell を有効にします。

b02c63d9c7632ef8.png

環境設定

  1. Cloud Shell ターミナルで次のコマンドを実行して、プロジェクトとリソースに関連する環境変数を作成します。
export PROJECT_ID=$(gcloud config get-value project)
export PROJECT_NAME=$(gcloud config get-value project)
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
export REGION=us-east1 
export UPLOAD_BUCKET_NAME=menu-item-uploads-$PROJECT_ID
export UPLOAD_BUCKET=gs://menu-item-uploads-$PROJECT_ID
export BUCKET_THUMBNAILS=gs://menu-item-thumbnails-$PROJECT_ID
export MENU_SERVICE_NAME=menu-service
export USER_EMAIL=$(gcloud config list account --format "value(core.account)")
  1. ラボに必要な API を有効にする
gcloud services enable \
    vision.googleapis.com \
    cloudfunctions.googleapis.com \
    pubsub.googleapis.com \
    cloudbuild.googleapis.com \
    logging.googleapis.com \
    eventarc.googleapis.com \
    artifactregistry.googleapis.com \
    run.googleapis.com \
    --quiet
  1. リポジトリのクローンを作成する
git clone https://github.com/GoogleCloudPlatform/cymbal-eats.git && cd cymbal-eats/cloud-functions

3. Cloud Storage バケットを構成する

ストレージ バケットを作成する

画像処理パイプラインのアップロードとサムネイルの Cloud Storage バケットを作成します。

gsutil mb コマンドと一意の名前を使用して、2 つのバケットを作成します。

  1. 画像が最初にアップロードされるアップロード バケット
  2. 生成されたサムネイル画像を保存するサムネイル バケット

新しい画像をアップロードするバケットを作成します。

gsutil mb -p $PROJECT_ID -l $REGION $UPLOAD_BUCKET

出力例:

Creating gs://menu-item-uploads-cymbal-eats-8399-3119/...

生成されたサムネイルを保存するバケットを作成します。

gsutil mb -p $PROJECT_ID -l $REGION $BUCKET_THUMBNAILS

出力例:

Creating gs://menu-item-thumbnails-cymbal-eats-8399-3119/...

バケットの権限を更新する

ストレージ バケットの権限を更新して、ユーザーに読み取り権限を付与します。

gsutil iam ch コマンドを使用して、バケット内のオブジェクトの読み取りと書き込みの権限を付与します。

gsutil iam ch allUsers:objectViewer $UPLOAD_BUCKET
gsutil iam ch allUsers:objectViewer $BUCKET_THUMBNAILS

出力例

Updated IAM policy for project [cymbal-eats-8399-3119].
[...]

4. サービス アカウントを構成する

Cloud Functions がサムネイルを処理するためのカスタム サービス アカウントを作成します。

export CF_SERVICE_ACCOUNT=thumbnail-service-sa
gcloud iam service-accounts create ${CF_SERVICE_ACCOUNT}

Artifact Registry からの読み取りオペレーションを許可する artifactregistry.reader ロールを付与します。

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member "serviceAccount:${CF_SERVICE_ACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role "roles/artifactregistry.reader"

生成された画像をサムネイル バケットに保存できるように、storage.objectCreator ロールを付与します。

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member "serviceAccount:${CF_SERVICE_ACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role "roles/storage.objectCreator"

Cloud Run サービスの呼び出しを許可する run.invoker ロールを付与します。

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member "serviceAccount:${CF_SERVICE_ACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com" \
  --role "roles/run.invoker"

プロバイダからのイベントの受信を許可する eventarc.eventReceiver ロールを付与します。

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

Cloud Storage サービス アカウントに pubsub.publisher ロールを付与します。これにより、サービス アカウントは、画像がバケットにアップロードされたときにイベントを公開できるようになります。

GCS_SERVICE_ACCOUNT=$(gsutil kms serviceaccount -p $PROJECT_NUMBER)

gcloud projects add-iam-policy-binding $PROJECT_NUMBER \
    --member "serviceAccount:$GCS_SERVICE_ACCOUNT" \
    --role "roles/pubsub.publisher"

5. 画像処理関数の概要

Cloud Storage から画像をダウンロードし、画像のサイズを変更して Cloud Storage にアップロードする関数を作成します。この関数は、Vision API を呼び出して画像に説明ラベルを割り当てます。この関数は、説明ラベルを確認します。ラベルで画像が「食べ物」と識別されると、メニュー アイテムの画像とサムネイルを更新するためにメニュー サービスにイベントが送信されます。

4c3c3b758dba6a9f.png

関数のトリガー

Cloud Storage の関数は Cloud Storage からの Pub/Sub 通知に基づいており、以下に挙げる類似のイベントタイプに対応しています。

このラボでは、Cloud Storage でオブジェクトがファイナライズされたときに関数をデプロイしてトリガーします。

オブジェクトのファイナライズ

オブジェクト ファイナライズ イベントは、Cloud Storage オブジェクトの「書き込み」が正常にファイナライズされた時点でトリガーされます。つまり、新しいオブジェクトの作成または既存のオブジェクトの上書きによって、このイベントがトリガーされます。このトリガーにより、アーカイブとメタデータの更新オペレーションは無視されます。

6. Cloud Storage を統合する

Cloud Storage は、Google Cloud でオブジェクトを保存するためのサービスです。 オブジェクトとは、任意の形式のファイルで構成される不変のデータのことです。オブジェクトをバケットと呼ばれるコンテナに保存します。バケットはすべていずれかのプロジェクトに関連付けられており、複数のプロジェクトを 1 つの組織の下にグループ化できます。クライアント ライブラリAPI を使用すると、Cloud Storage との統合が容易になります。

このラボでは、クライアント ライブラリを使用して、Cloud Storage へのオブジェクトの読み取りと書き込みを行います。

クライアント ライブラリのインストール

Cloud クライアント ライブラリは、多くの一般的なプログラミング言語で利用できます。ライブラリの使用を開始するには、クライアント ライブラリをインストールする必要があります。

クライアント ライブラリの使用

実装の詳細は、プログラミング言語によって大きく異なります。アプリケーションでクライアント ライブラリを使用するには、まず Cloud Storage の依存関係をインポートします。たとえば、Node.js プロジェクトでは、インポートは package.json ファイルに追加されます。以下のスニペットは、このラボの package.json ファイルの通知を示しています。

package.json

{
    "name": "thumbnail-service",
    "version": "0.1.0",
    "dependencies": {
      "@google-cloud/functions-framework": "^3.0.0",
      "@google-cloud/storage": "^5.18.2",
      "@google-cloud/vision": "^2.4.2",
        ...
    }
  }

CloudEvent コールバックを登録する

新しい画像がバケットにアップロードされたときに Cloud Storage によってトリガーされる Functions フレームワークCloudEvent コールバックを登録します。

index.js

functions.cloudEvent('process-thumbnails', async (cloudEvent) => {
    console.log(`Event ID: ${cloudEvent.id}`);
    console.log(`Event Type: ${cloudEvent.type}`);
    ...

ストレージ参照オブジェクトを作成する

クライアント ライブラリをインポートしたら、アプリケーションが操作する新しいストレージ クライアントとバケットを作成する必要があります。

index.js

const storage = new Storage();
const bucket = storage.bucket(file.bucket);
const thumbBucket = storage.bucket(process.env.BUCKET_THUMBNAILS);

Cloud Storage オブジェクトをダウンロードする

index.js

await bucket.file(file.name).download({
            destination: originalFile
        });

Cloud Storage にオブジェクトをアップロードする

Cloud Storage にアップロード リクエストを送信するには、単一リクエスト、再開可能なアップロード、XML API マルチパート アップロードの 3 つの方法があります。大規模なアップロードやストリーミング アップロードの場合は、再開可能なアップロードを使用します。XML API では、ファイルは分割してアップロードされ、単一のオブジェクトとして組み立てられます。サイズの小さいオブジェクトの場合は、単一リクエストのアップロードを使用します。

次のコードは、単一リクエストのアップロードを使用して画像を Cloud Storage にアップロードします。

index.js

const thumbnailImage = await thumbBucket.upload(thumbFile);

7. Vision API を統合する

Cloud Vision を使用すると、開発するアプリケーションの中で簡単に画像検出機能を統合できます。この機能の例としては、画像ラベリング、顔やランドマークの検出、光学式文字認識(OCR)、不適切なコンテンツへのタグ付けがあります。

クライアント ライブラリのインストール

Cloud クライアント ライブラリは、多くの一般的なプログラミング言語で利用できます。ライブラリの使用を開始するには、クライアント ライブラリをインストールする必要があります。

Image Annotator クライアントを作成する

Google の API に公式クライアント SDK を使用してアクセスするには、その API のディスカバリ ドキュメントに基づいてサービス オブジェクトを作成します。このドキュメントは、SDK に対する API を記述するものです。デベロッパーは、自分の認証情報を使用してこのドキュメントを Vision API のディスカバリ サービスから取得する必要があります。

index.js

const client = new vision.ImageAnnotatorClient();

Vision API リクエストを作成する

Vision API は、リクエストの本文で画像ファイルのコンテンツを Base64 エンコードの文字列として送信し、画像ファイルの特徴検出を行います。

images リソースを使用してリクエストを作成し、画像にアノテーションを付けます。この API へのリクエストは、リクエスト リストを含むオブジェクト形式になります。このリスト内のアイテムのそれぞれに、次の 2 つの情報が格納されます。

  • base64 エンコード済みの画像データ
  • その画像についてアノテーションを付けたい機能のリスト

index.js

        const client = new vision.ImageAnnotatorClient();
        const visionRequest = {
            image: { source: { imageUri: `gs://${file.bucket}/${file.name}` } },
            features: [
                { type: 'LABEL_DETECTION' },
            ]
        };
        const visionPromise = client.annotateImage(visionRequest);

8. Cloud Run 関数をデプロイする

この画像サイズ変更サービスは、より大規模な Cymbal Eats システムの一部です。このセクションでは、画像処理機能に関連するコンポーネントのみをデプロイします。完全なインストールには、画像をアップロードするための UI と、生成されたメタデータを保存するためのダウンストリーム リクエストが組み込まれています。これらの機能は、このラボの一部としてインストールされません。

関数のデプロイ中に、次のコンポーネントが作成されます。

  • Cloud Run functions
  • Eventarc トリガー
  • Pub/Sub トピックとサブスクリプション

Cloudshell ターミナルで、次のコマンドを実行して、menu-item-uploads-$PROJECT_ID にトリガー バケットを持つ Cloud Run 関数をデプロイします。

Cloud Run functions を Cloud Run に直接デプロイするには、まず関数をデプロイしてから、その関数のトリガーを作成します。

Cloud Run 関数をデプロイします。

gcloud beta run deploy process-thumbnails \
      --source=thumbnail \
      --function process-thumbnails \
      --region $REGION \
      --base-image google-22-full/nodejs20 \
      --no-allow-unauthenticated \
      --project=$PROJECT_ID \
--service-account="${CF_SERVICE_ACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com" \
--set-env-vars=BUCKET_THUMBNAILS=$BUCKET_THUMBNAILS,MENU_SERVICE_URL=$MENU_SERVICE_URL \
  --max-instances=1 \
  --quiet

出力例:

Done.                                                                                                                                                                                    
Service [process-thumbnails] revision [process-thumbnails-00001-abc] has been deployed and is serving 100 percent of traffic.
Service URL: https://process-thumbnails-000000000.us-east1.run.app

トリガーを作成します。

gcloud eventarc triggers create process-thumbnails-trigger \
     --location=$REGION \
     --destination-run-service=process-thumbnails \
    --destination-run-region=$REGION \
     --event-filters="type=google.cloud.storage.object.v1.finalized" \
     --event-filters="bucket=$UPLOAD_BUCKET_NAME" \
     --service-account="${CF_SERVICE_ACCOUNT}@${PROJECT_ID}.iam.gserviceaccount.com"

出力例:

Creating trigger [process-thumbnails-trigger] in project [qwiklabs-gcp-02-53f8532696e1], location [us-east1]...done.                                                                     
WARNING: It may take up to 2 minutes for the new trigger to become active.

権限の問題が原因でトリガーのデプロイに失敗した場合は、前の手順で行った IAM の変更が反映されるまで待ってください。通常は 1 ~ 2 分ほどで、デプロイを再試行します。

エラー出力例:

...If you recently started to use Eventarc, it may take a few minutes before all necessary permissions are propagated to the Service Agent...
[...] 

Cloud コンソールで、関数用に作成された Cloud Run サービスを確認します。

546c5c951cf0f2f.png

Cloud コンソールで、関数用に作成された Eventarc トリガーを確認します。

dec11309016b09ac.png

Cloud コンソールで、Eventarc トリガー用に作成された Pub/Sub トピックサブスクリプションを確認します。

affe089c39ae1465.png

a4c41ede2af300db.png

9. エンドツーエンドのソリューションをテストして検証します。

新しい写真を Cloud Storage にアップロードし、画像が分析される間、パイプラインの進行状況をモニタリングします。Cloud Functions のログをモニタリングして、エンドツーエンドのソリューションをテストします。

画像のアップロード

ab7b43f876f9c3a9.jpeg

  1. この画像をローカルマシンに保存します。
  2. ファイルの名前を 1.jpg に変更します。
  3. Cloud Storage コンソールを開きます。
  4. menu-item-uploads-... バケットをクリックします。
  5. [ファイルをアップロード] をクリックします。
  6. 1.jpg をストレージ バケットにアップロードします。
  7. Cloud コンソールで、[Cloud Run] に移動します。
  8. [process-thumbails] をクリックします。
  9. [ログ] タブをクリックします。

fca8e4bafbdf135d.png

  1. menu-item-thumbnails-$PROJECT_ID Cloud Storage バケットに移動します。
  2. サムネイル バケットにサムネイル画像が作成されていることを確認する

1b6dee72a1fde681.png

食べ物以外の画像をアップロードする

機能が正しく動作することを確認するため、[食品] アイテムに分類されるオブジェクトが含まれていない画像をアップロードします。

c76dd525765f66a6.jpeg

  1. この画像をローカルマシンに保存します。
  2. ファイル名を 2.jpg に変更します。
  3. Cloud Storage コンソールを開きます。
  4. menu-item-uploads-... バケットをクリックします。
  5. [ファイルをアップロード] をクリックします。
  6. 2.jpg をストレージ バケットにアップロードします。
  7. Cloud コンソールで、[Cloud Run] に移動します。
  8. [process-thumbails] をクリックします。
  9. [ログ] タブをクリックします。

18b1e30ee78d3955.png

10. 完了

お疲れさまでした。ラボはこれで完了です。

次のステップ:

Cymbal Eats の他の Codelab を確認する:

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

プロジェクトの削除

課金を停止する最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。