使用 Eventarc 和 Cloud Run 函数从 Cloud Storage 触发事件处理

1. 概览

在本实验中,您将学习如何使用 Cloud Storage 存储分区事件和 Eventarc 触发事件处理。您将使用 Cloud Run 函数来分析数据和处理图片。该函数将使用 Google 的 Vision API,并将生成的图片保存回 Cloud Storage 存储分区。

424779013ac38648.png

学习内容

如何构建图片处理流水线。

  • 配置存储分区
  • 创建 Cloud Run 函数以读取和写入 Cloud Storage 中的对象
  • 部署 Eventarc 触发器
  • 集成 Vision API 以检测食物图片
  • 测试和验证端到端解决方案

前提条件

  • 本实验假设您熟悉 Cloud 控制台和 shell 环境。
  • 有 Cloud Storage、Cloud Run 函数或 Vision API 方面的使用经验会很有帮助,但不是必需的。

2. 设置和要求

Cloud 项目设置

  1. 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串。您可以随时对其进行更新。
  • 项目 ID 在所有 Google Cloud 项目中是唯一的,并且是不可变的(一经设置便无法更改)。Cloud 控制台会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(通常用 PROJECT_ID 标识)。如果您不喜欢生成的 ID,可以再随机生成一个 ID。或者,您也可以尝试自己的项目 ID,看看是否可用。完成此步骤后便无法更改该 ID,并且此 ID 在项目期间会一直保留。
  • 此外,还有第三个值,即部分 API 使用的项目编号,供您参考。如需详细了解所有这三个值,请参阅文档
  1. 接下来,您需要在 Cloud 控制台中启用结算功能,以便使用 Cloud 资源/API。运行此 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 命令和唯一的名称创建两个存储分区:

  1. 图片将首先上传到的上传存储分区
  2. 用于存储生成的缩略图图片的 Thumbnails 存储分区

创建一个存储分区以上传新图片:

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"

pubsub.publisher 角色授予 Cloud Storage 服务账号。这样,服务账号便可以在图片上传到存储分区时发布事件。

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 中的服务。对象是由任意格式的文件组成的不可变的数据段。对象存储在称为存储桶的容器中。所有存储分区都与项目相关联,您可以在组织下对项目进行分组。客户端库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 回调

Functions 框架注册 CloudEvent 回调,当有新图片上传到存储分区时,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 分块上传。对于较大的上传内容或流式上传内容,请使用可续传上传。使用 XML API 时,文件会分块上传并组合为单个对象。对于较小的对象,请使用单个请求上传。

以下代码使用单次请求上传功能将图片上传到 Cloud Storage。

index.js

const thumbnailImage = await thumbBucket.upload(thumbFile);

7. 集成 Vision API

借助 Cloud Vision API,开发者可轻松将视觉检测功能集成到应用中,这些功能包括图片标记、面孔和地标检测、光学字符识别 (OCR) 以及露骨内容的标记等。

安装客户端库

Cloud 客户端库提供多种常用编程语言版本。如需开始使用这些库,您必须安装客户端库

创建 Image Annotator 客户端

如需使用官方客户端 SDK 访问 Google API,请根据相应 API 的发现文档(用于向 SDK 描述 API)来创建服务对象。您需要使用自己的凭据从 Vision API 的发现服务中获取该文档。

index.js

const client = new vision.ImageAnnotatorClient();

构建 Vision API 请求

Vision API 可以将图片文件的内容作为 base64 编码的字符串在请求正文中发送,从而对此图片文件执行特征检测。

使用 images 资源构建请求以注释图片。对此 API 的请求采用具有请求列表的对象形式。此列表中的每项均包含两种信息:

  • 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 functions 函数

此图片大小调整服务是更大的 Cymbal Eats 系统的一部分。在本部分中,您将仅部署与图片处理功能相关的组件。完整安装包含用于上传图片的界面和用于存储生成的元数据的下游请求。本实验不会安装这些功能。

函数部署期间将创建以下组件:

  • Cloud Run functions
  • Eventarc 触发器
  • Pub/Sub 主题和订阅

在 Cloud Shell 终端中,运行以下命令,在 menu-item-uploads-$PROJECT_ID 上部署带有触发器存储分区的 Cloud Run functions:

如需将 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 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

删除项目

若要避免产生费用,最简单的方法是删除您为本教程创建的项目。