Eventarc を使用して Cloud Storage から関数をトリガーする

このチュートリアルでは、Cloud Run にイベント ドリブン関数をデプロイし、Eventarc を使用して Google Cloud CLI で Cloud Storage イベントに応答して関数をトリガーする方法について説明します。

Eventarc トリガーのフィルタを指定すると、イベントソースやイベント ターゲットなど、イベントの転送を構成できます。このチュートリアルの例では、Cloud Storage バケットが更新されるとイベントがトリガーされ、リクエストが HTTP リクエストの形式で関数に送信されます。

必要なロールを設定する

ご自身または管理者が、デプロイ担当者アカウント、トリガー ID、さらに必要に応じて Pub/Sub サービス エージェントと Cloud Storage サービス エージェントに次の IAM ロールを付与する必要があります。

デプロイ担当者のアカウントに必要なロール

  1. プロジェクト作成者には、基本オーナーロールroles/owner)が付与されます。デフォルトでは、この Identity and Access Management(IAM)ロールには、ほとんどの Google Cloudリソースへのフルアクセスに必要な権限が含まれており、この手順は省略できます。

    プロジェクト作成者でない場合は、プロジェクトで適切なプリンシパルに必要な権限を付与する必要があります。プリンシパルは Google アカウント(エンドユーザーの場合)やサービス アカウント(アプリケーションとコンピューティング ワークロードの場合)になることもあります。詳細については、イベントの宛先のロールと権限のページをご覧ください。

    このチュートリアルを完了するために必要な権限を取得するには、プロジェクトに対する次の IAM ロールを付与するよう管理者に依頼してください。

    ロールの付与については、プロジェクト、フォルダ、組織へのアクセス権の管理をご覧ください。

    必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

    デフォルトでは、Cloud Build の権限には、Artifact Registry アーティファクトをアップロードおよびダウンロードするための権限が含まれています

トリガー ID に必要なロール

  1. Compute Engine のデフォルトのサービス アカウントをメモしておいてください。テスト目的で、Eventarc トリガーにこのサービス アカウントを関連付け、トリガーの ID として使用します。このサービス アカウントは、Compute Engine を使用する Google Cloud サービスを有効にするか使用すると自動的に作成されます。メールアドレスの形式は次のとおりです。

    PROJECT_NUMBER-compute@developer.gserviceaccount.com

    PROJECT_NUMBER は、使用する Google Cloudプロジェクト番号に置き換えます。プロジェクト番号は、 Google Cloud コンソールの [ようこそ] ページで確認できます。また、次のコマンドでも確認できます。

    gcloud projects describe PROJECT_ID --format='value(projectNumber)'

    本番環境では、新しいサービス アカウントを作成して、必要最小限の権限を含む、最小権限の原則に従った 1 つ以上の IAM ロールを付与することを強くおすすめします。

  2. デフォルトでは、Cloud Run サービスを呼び出すことができるのは、プロジェクト オーナー、プロジェクト編集者、Cloud Run 管理者、起動元のみです。サービスごとにアクセスを制御できます。ただし、テスト目的の場合は、 Google Cloud プロジェクトの Cloud Run 起動元ロールrun.invoker)を Compute Engine サービス アカウントに付与してください。これにより、プロジェクト内のすべての Cloud Run サービスとジョブにロールが付与されます。
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member=serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com \
        --role=roles/run.invoker

    Cloud Run 起動元ロールを付与せずに認証済みの Cloud Run サービスのトリガーを作成すると、トリガーは正常に作成され、アクティブになります。ただし、トリガーが期待どおりに機能せず、次のようなメッセージがログに記録されます。

    The request was not authenticated. Either allow unauthenticated invocations or set the proper Authorization header.
  3. プロジェクトの Eventarc イベント レシーバーのロールroles/eventarc.eventReceiver)を Compute Engine のデフォルト サービス アカウントに付与して、Eventarc トリガーがイベント プロバイダからイベントを受信できるようにします。
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member=serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com \
        --role=roles/eventarc.eventReceiver

Cloud Storage サービス エージェントのオプションのロール

  • Cloud Storage からの直接イベントのトリガーを作成する前に、Cloud Storage サービス エージェントに Pub/Sub パブリッシャーのロールroles/pubsub.publisher)を付与します。

    SERVICE_ACCOUNT="$(gcloud storage service-agent --project=PROJECT_ID)"
    
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member="serviceAccount:${SERVICE_ACCOUNT}" \
        --role='roles/pubsub.publisher'

Pub/Sub サービス エージェントのオプションのロール

  • 2021 年 4 月 8 日以前に、認証済みの Pub/Sub push リクエストをサポートするために Cloud Pub/Sub サービス エージェントを有効にした場合は、サービス アカウント トークン作成者のロールroles/iam.serviceAccountTokenCreator)をサービス エージェントに付与します。それ以外の場合、このロールはデフォルトで付与されます。
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member=serviceAccount:service-PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \
        --role=roles/iam.serviceAccountTokenCreator

Cloud Storage バケットを作成する

イベントソースとして使用する Cloud Storage バケットを作成します。

gcloud storage buckets create -l us-central1 gs://PROJECT_ID-bucket/

イベント ドリブン関数を作成する

イベント ドリブン関数の作成手順は次のとおりです。

Node.js

  1. helloGCS という名前の新しいディレクトリを作成し、そのディレクトリに移動します。

       mkdir helloGCS
       cd helloGCS
    

  2. helloGCS ディレクトリに package.json ファイルを作成して、Node.js の依存関係を指定します。

    {
      "name": "nodejs-docs-samples-functions-v2-storage",
      "version": "0.0.1",
      "private": true,
      "license": "Apache-2.0",
      "author": "Google LLC",
      "repository": {
        "type": "git",
        "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git"
      },
      "engines": {
        "node": ">=16.0.0"
      },
      "scripts": {
        "test": "c8 mocha -p -j 2 test/*.test.js --timeout=60000"
      },
      "dependencies": {
        "@google-cloud/functions-framework": "^3.0.0"
      },
      "devDependencies": {
        "c8": "^10.0.0",
        "mocha": "^10.0.0",
        "sinon": "^18.0.0",
        "supertest": "^7.0.0"
      }
    }
    
  3. 次の Node.js サンプルを使用して、helloGCS ディレクトリに index.js ファイルを作成します。

    const functions = require('@google-cloud/functions-framework');
    
    // Register a CloudEvent callback with the Functions Framework that will
    // be triggered by Cloud Storage.
    functions.cloudEvent('helloGCS', cloudEvent => {
      console.log(`Event ID: ${cloudEvent.id}`);
      console.log(`Event Type: ${cloudEvent.type}`);
    
      const file = cloudEvent.data;
      console.log(`Bucket: ${file.bucket}`);
      console.log(`File: ${file.name}`);
      console.log(`Metageneration: ${file.metageneration}`);
      console.log(`Created: ${file.timeCreated}`);
      console.log(`Updated: ${file.updated}`);
    });

Python

  1. helloGCS という名前の新しいディレクトリを作成し、そのディレクトリに移動します。

       mkdir helloGCS
       cd helloGCS
    

  2. Python の依存関係を指定するために、helloGCS ディレクトリに requirements.txt ファイルを作成します。

    functions-framework==3.9.2
    cloudevents==1.11.0

    これにより、サンプルで必要なパッケージが追加されます。

  3. helloGCS ディレクトリに、次の Python サンプルを含む main.py ファイルを作成します。

    from cloudevents.http import CloudEvent
    
    import functions_framework
    
    
    # Triggered by a change in a storage bucket
    @functions_framework.cloud_event
    def hello_gcs(cloud_event: CloudEvent) -> tuple:
        """This function is triggered by a change in a storage bucket.
    
        Args:
            cloud_event: The CloudEvent that triggered this function.
        Returns:
            The event ID, event type, bucket, name, metageneration, and timeCreated.
        """
        data = cloud_event.data
    
        event_id = cloud_event["id"]
        event_type = cloud_event["type"]
    
        bucket = data["bucket"]
        name = data["name"]
        metageneration = data["metageneration"]
        timeCreated = data["timeCreated"]
        updated = data["updated"]
    
        print(f"Event ID: {event_id}")
        print(f"Event type: {event_type}")
        print(f"Bucket: {bucket}")
        print(f"File: {name}")
        print(f"Metageneration: {metageneration}")
        print(f"Created: {timeCreated}")
        print(f"Updated: {updated}")
    
        return event_id, event_type, bucket, name, metageneration, timeCreated, updated
    
    

イベント ドリブン関数をデプロイする

サンプルコードを含むディレクトリで次のコマンドを実行し、helloworld-events という名前の関数をデプロイします。

Node.js

gcloud run deploy helloworld-events \
      --source . \
      --function helloGCS \
      --base-image BASE_IMAGE \
      --region us-central1

BASE_IMAGE は、関数のベースイメージ環境に置き換えます(例: nodejs22)。ベースイメージと各イメージに含まれるパッケージの詳細については、サポートされている言語ランタイムとベースイメージをご覧ください。

Python

gcloud run deploy helloworld-events \
      --source . \
      --function hello_gcs \
      --base-image BASE_IMAGE \
      --region us-central1

BASE_IMAGE は、関数のベースイメージ環境に置き換えます(例: python313)。ベースイメージと各イメージに含まれるパッケージの詳細については、サポートされている言語ランタイムとベースイメージをご覧ください。

デプロイが完了すると、サービスが実行されている URL が Google Cloud CLI に表示されます。

Eventarc トリガーを作成する

Eventarc トリガーは、Cloud Storage バケットから helloworld-events Cloud Run サービスにイベントを送信します。

  1. Cloud Storage イベントをフィルタするトリガーを作成します。

    gcloud eventarc triggers create TRIGGER_NAME  \
        --location=${REGION} \
        --destination-run-service=helloworld-events  \
        --destination-run-region=${REGION} \
        --event-filters="type=google.cloud.storage.object.v1.finalized" \
        --event-filters="bucket=PROJECT_ID-bucket" \
        --service-account=PROJECT_NUMBER-compute@developer.gserviceaccount.com

    次のように置き換えます。

    • TRIGGER_NAME: トリガーの名前。
    • PROJECT_ID: 実際の Google Cloud プロジェクト ID。
    • PROJECT_NUMBER: Google Cloud プロジェクト番号。

    Google Cloud プロジェクトで初めて Eventarc トリガーを作成する場合は、Eventarc サービス エージェントのプロビジョニングに遅延が発生する可能性があります。この問題は通常、トリガーを再度作成することで解決できます。詳細については、権限拒否エラーをご覧ください。

  2. トリガーが正常に作成されたことを確認します。トリガーはすぐに作成されますが、トリガーが完全に機能するまでに 2 分ほどかかることがあります。

    gcloud eventarc triggers list --location=${REGION}

    出力例を以下に示します。

    NAME: helloworld-events
    TYPE: google.cloud.storage.object.v1.finalized
    DESTINATION: Cloud Run service: helloworld-events
    ACTIVE: Yes
    LOCATION: us-central1
    

イベントを生成して表示する

テキスト ファイルを Cloud Storage バケットにアップロードして、関数に転送されるイベントを生成します。このイベントは、Cloud Run 関数によってサービスログに記録されます。

  1. イベントを生成するには、Cloud Storage にテキスト ファイルをアップロードします。

     echo "Hello World" > random.txt
     gcloud storage cp random.txt gs://PROJECT_ID-bucket/random.txt
    

    アップロードによりイベントが生成され、Cloud Run 関数はイベントのメッセージをロギングします。

  2. ログエントリを表示するには:

    1. ログエントリをフィルタして、JSON 形式で出力を返します。

      gcloud logging read "resource.labels.service_name=helloworld-events AND textPayload:random.txt" --format=json
      
    2. 次のようなログエントリを探します。

      [
        {
         ....
          "resource": {
            "labels": {
              ....
              "location": "us-central1",
              .....
              "service_name": "helloworld-events"
            },
          },
          "textPayload": "File: random.txt",
           .....
        }
      ]
      

      ログが表示されるまで少し時間がかかることがあります。すぐに表示されない場合は、1 分後に再度確認してください。

ログエントリが表示されたら、テキスト ファイルが Cloud Storage にアップロードされたときにトリガーされたイベント ドリブン関数が正常にデプロイされています。