Eventarc と Cloud Functions(第 2 世代)を使用して Cloud Storage からイベント処理をトリガーする

1. 概要

このラボでは、Cloud Storage バケット イベントと Eventarc を使用してイベント処理をトリガーする方法を学びます。Cloud Functions(第 2 世代)を使用して、データの分析と画像の処理を行います。この関数は Google の Vision API を使用し、生成された画像を Cloud Storage バケットに保存します。

4756e4c218d84e26.png

学習内容

画像処理パイプラインの構築方法。

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

前提条件

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

2. 設定と要件

Cloud プロジェクトの設定

  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 をアクティブにする

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

8613854df02635a3.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=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. ラボに必要な API を有効にします。(Qwiklabs 固有の手順)
gcloud services disable cloudfunctions.googleapis.com
gcloud services enable cloudfunctions.googleapis.com
  1. リポジトリのクローンを作成する
git clone https://github.com/GoogleCloudPlatform/cymbal-eats.git && cd cymbal-eats/cloud-functions

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

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

画像処理パイプライン用のアップロード 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}

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

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"

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

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 でオブジェクトがファイナライズされたときに関数をデプロイしてトリガーします。

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

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

6. Cloud Storage を統合する

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

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

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

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

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

実装の詳細は、プログラミング言語によって異なります。アプリケーションでクライアント ライブラリを使用するには、まず Cloud Storage の依存関係をインポートします。たとえば Node.js プロジェクトでは、import.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 コールバックを登録する

Functions FrameworkCloudEvent コールバックを登録します。このコールバックは、新しい画像がバケットにアップロードされたときに Cloud Storage によってトリガーされます。

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 では、ファイルは分割してアップロードされ、単一のオブジェクトとして組み立てられます。より小さいオブジェクトの場合は、単一リクエストのアップロードを使用します。

以下のコードは、1 回のリクエストによるアップロードを使用して、画像を Cloud Storage にアップロードします。

index.js

const thumbnailImage = await thumbBucket.upload(thumbFile);

7. Vision API を統合する

Cloud Vision を使用すると、デベロッパーはアプリケーション内に画像検出機能を簡単に統合できます。たとえば、画像のラベル付け、顔やランドマークの検出、光学式文字認識(OCR)、露骨な表現を含むコンテンツのタグ付けなどです。

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

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

画像アノテーター クライアントを作成する

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

index.js

const client = new vision.ImageAnnotatorClient();

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

Vision API は、リクエスト本文で画像ファイルの内容を base64 エンコード文字列として送信することで、画像ファイルに対して特徴検出を実行できます。

画像リソースを使用して画像にアノテーションを付けるリクエストを作成するには、この 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 Functions の関数をデプロイ

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

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

  • Cloud Functions の関数
  • Cloud Run サービス
  • Eventarc トリガー
  • Pub/Sub トピックとサブスクリプション

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

gcloud functions deploy process-thumbnails \
  --gen2 \
  --runtime=nodejs16 \
  --source=thumbnail \
  --region=$REGION \
  --project=$PROJECT_ID \
  --entry-point=process-thumbnails \
  --trigger-bucket=$UPLOAD_BUCKET \
  --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

アップロード用ストレージ バケットの権限の問題が原因でデプロイが失敗した場合は、前の手順の IAM の変更が反映されるまでお待ちください。通常 1 ~ 2 分後にデプロイを再試行します。

出力例

Deploying function (may take a while - up to 2 minutes)...done.
[...] 

Cloud コンソールで、作成された Cloud Functions の関数を確認します。

8148dd29e6757603.png

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

42e970cdd48cae76.png

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

9441995a5cc62e38.png

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

affe089c39ae1465.png

a4c41ede2af300db.png

9. エンドツーエンドのソリューションのテストと検証

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

適切な画像をアップロードする

2fdd13b63d6148f4.jpeg

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

7ab4e783e474c90d.png

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

84d8023782eb3e0c.png

食品以外の画像のアップロード

関数が正しく動作することを確認するために、「Food」に分類されるオブジェクトを含まない画像をアップロードします。表示されます。

3226a24251084b28.jpeg

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

421c36c342fceea8.png

10. 完了

これでラボは終了です。

次のステップ:

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

クリーンアップ

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

プロジェクトの削除

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