使用 Eventarc 從 Cloud Storage 觸發函式

本教學課程說明如何使用 Google Cloud CLI,在 Cloud Run 中部署事件驅動函式,並使用 Eventarc 觸發函式來回應 Cloud Storage 事件。

為 Eventarc 觸發條件指定篩選器,即可設定事件的轉送方式,包括事件來源和事件目標。以本教學課程的範例來說,Cloud Storage bucket 的更新會觸發事件,並以 HTTP 要求的形式將要求傳送至函式。

設定必要角色

您或管理員必須授予部署者帳戶、觸發程序身分,以及視需要授予 Pub/Sub 服務代理程式和 Cloud Storage 服務代理程式下列 IAM 角色。

部署者帳戶的必要角色

  1. 如果您是專案建立者,系統會授予基本「擁有者」角色 (roles/owner)。根據預設,這個身分與存取權管理 (IAM) 角色包含完全存取大多數 Google Cloud資源所需的權限,因此您可以略過這個步驟。

    如果您不是專案建立者,必須在專案中將必要權限授予適當的主體。舉例來說,主體可以是 Google 帳戶 (適用於使用者) 或服務帳戶 (適用於應用程式和運算工作負載)。詳情請參閱活動目的地的「角色和權限」頁面。

    如要取得完成本教學課程所需的權限,請要求管理員為您授予專案的下列 IAM 角色:

    如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和機構的存取權」。

    您或許還可透過自訂角色或其他預先定義的角色取得必要權限。

    請注意,根據預設,Cloud Build 權限包含上傳及下載 Artifact Registry 構件的權限

觸發身分所需的角色

  1. 記下 Compute Engine 預設服務帳戶,因為您會將其附加至 Eventarc 觸發程序,代表觸發程序的身分以進行測試。啟用或使用採用 Compute Engine 的服務後,系統會自動建立這個服務帳戶,電子郵件地址格式如下: Google Cloud

    PROJECT_NUMBER-compute@developer.gserviceaccount.com

    PROJECT_NUMBER 替換為專案編號。 Google Cloud您可以在 Google Cloud 控制台的「歡迎」頁面中找到專案編號,也可以執行下列指令:

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

    在正式環境中,我們強烈建議建立新的服務帳戶,並授予一或多個包含最低必要權限的 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 Invoker 角色,系統仍會成功建立並啟用觸發條件。不過,觸發條件不會正常運作,記錄中會顯示類似下列內容的訊息:

    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 直接事件的觸發條件前,請將 Pub/Sub 發布者角色 (roles/pubsub.publisher) 授予 Cloud Storage 服務代理:

    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 日當天或之前啟用 Cloud Pub/Sub 服務代理,請將服務帳戶權杖建立者角色 (roles/iam.serviceAccountTokenCreator) 授予服務代理,以支援已驗證的 Pub/Sub 推送要求。否則,系統會預設授予這個角色:
    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 bucket:

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. helloGCS 目錄中建立 index.js 檔案,並加入下列 Node.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. helloGCS 目錄中建立 requirements.txt 檔案,指定 Python 依附元件:

    functions-framework==3.9.2
    cloudevents==1.11.0

    這會新增範例所需的套件。

  3. helloGCS 目錄中建立 main.py 檔案,並加入下列 Python 範例:

    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。如要進一步瞭解基礎映像檔和各映像檔中包含的套件,請參閱「支援的語言執行階段和基礎映像檔」。

部署完成後,Google Cloud CLI 會顯示服務的執行網址。

建立 Eventarc 觸發條件

Eventarc 觸發條件會將 Cloud Storage bucket 中的事件傳送至 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. 確認觸發條件是否已成功建立。請注意,雖然觸發條件會立即建立,但最多可能需要兩分鐘才能正常運作。

    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 bucket,產生會傳送至函式的事件。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",
           .....
        }
      ]
      

      記錄需要一些時間才會出現。如果沒有立即看到記錄,請稍候片刻再查看一次。

看到記錄檔項目後,表示您已成功部署事件驅動函式,且該函式會在文字檔上傳至 Cloud Storage 時觸發。