使用 Eventarc 和 Workflows 构建事件驱动型编排

1. 简介

f2f35f5c40b91a3c.png c637dcc97f298e7e.png c4a9d5b95f111710.png

借助 Eventarc,您可以轻松地将 Cloud Run 服务与来自各种来源的事件相关联。它可让您构建微服务松散耦合且分布式的事件驱动型架构。它会为您处理事件提取、传送、安全、授权和错误处理。

Workflows 是一个全托管式编排平台,该平台会按照您定义的顺序执行服务:工作流。这些工作流可以组合 Cloud Run 或 Cloud Functions 上托管的服务、Google Cloud 服务(如 Cloud Vision AI 和 BigQuery)以及任何基于 HTTP 的 API。

在此 Codelab 中,您将构建一个由事件驱动的微服务编排,用于处理图片。您将使用 Workflows 来编排 4 个图片处理 Cloud Functions 的顺序、输入和输出。然后,您将启用编排功能,以便通过 Eventarc 以松散耦合的方式响应 Cloud Storage 事件。

最后,您将获得一个灵活而结构化的无服务器架构来处理图片。

b75a14a4268cbe73.png

学习内容

  • Eventarc 和 Workflows 概览
  • 如何部署 Cloud Functions 服务
  • 如何使用 Workflows 编排服务
  • 如何使工作流通过 Eventarc 响应 Cloud Storage 事件

2. 设置和要求

自定进度的环境设置

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

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.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

虽然可以通过笔记本电脑对 Google Cloud 进行远程操作,但在此 Codelab 中,您将使用 Google Cloud Shell,这是一个在云端运行的命令行环境。

Google Cloud 控制台 中,点击右上角工具栏中的 Cloud Shell 图标:

激活 Cloud Shell

预配和连接到环境应该只需要片刻时间。完成后,您应该会看到如下内容:

Google Cloud Shell 终端的屏幕截图,显示环境已连接

这个虚拟机已加载了您需要的所有开发工具。它提供了一个持久的 5 GB 主目录,并且在 Google Cloud 中运行,大大增强了网络性能和身份验证功能。您在此 Codelab 中的所有工作都可以在浏览器中完成。您无需安装任何程序。

设置 gcloud

在 Cloud Shell 中,设置项目 ID 以及要将应用部署到的区域。将它们保存为 PROJECT_IDREGION 变量。如需查看可用区域,请参阅 Cloud Functions 位置

PROJECT_ID=your-project-id
gcloud config set project $PROJECT_ID

获取源代码

应用的源代码位于 eventarc-samples 代码库的 processing-pipelines 文件夹中。

克隆代码库:

git clone https://github.com/GoogleCloudPlatform/eventarc-samples.git

转到 eventarc-samples/processing-pipelines 文件夹:

cd eventarc-samples/processing-pipelines

3. 架构概览

应用的架构如下:

7b810e1505054c0c.png

  1. 将图片保存到输入存储分区,这会生成 Cloud Storage 创建事件。
  2. Eventarc 通过 Cloud Storage 触发器读取 Cloud Storage 创建事件,并将其作为 CloudEvent 传递给 Workflows
  3. 在工作流的第一步过滤中,Cloud Functions 服务使用 Vision API 确定图片是否安全。如果图片安全,工作流会继续执行后续步骤。
  4. 在工作流的第二步中,Labeler(一种 Cloud Functions 服务)会使用 Vision API 提取图片的标签,并将这些标签保存到输出存储分区。
  5. 在第三步中,另一个 Cloud Functions 服务 Resizer 使用 ImageSharp 调整图片大小,并将调整后的图片保存到输出存储分区。
  6. 在最后一步中,另一个 Cloud Functions 服务 Watermarker 使用 ImageSharp 将 Labeler 中的标签水印添加到调整大小后的图片,并将该图片保存到输出存储分区。

应用由 Cloud Storage 事件触发,因此是事件驱动型应用。图片处理是在工作流中进行的,因此属于编排。最终,它将成为一种事件驱动型编排,用于灵活而结构化的无服务器架构,以处理图片。

4. 创建分桶

创建一个输入存储分区,供用户上传图片;并创建一个输出存储分区,供图片处理流水线保存处理后的图片。

在 Cloud Shell 中运行下面的命令:

REGION=us-central1
BUCKET1=$PROJECT_ID-images-input-$RANDOM
BUCKET2=$PROJECT_ID-images-output-$RANDOM

gsutil mb -l $REGION gs://$BUCKET1
gsutil mb -l $REGION gs://$BUCKET2

5. 部署过滤服务

我们先来部署第一个服务。此 Cloud Functions 服务会接收存储分区和文件信息,使用 Vision API 确定图片是否安全,并返回结果。

首先,为 Cloud Functions 第 2 代和 Vision API 启用所需的服务:

gcloud services enable \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  cloudfunctions.googleapis.com \
  run.googleapis.com \
  vision.googleapis.com

在顶级 processing-pipelines 文件夹中,部署服务:

SERVICE_NAME=filter

gcloud functions deploy $SERVICE_NAME \
  --gen2 \
  --allow-unauthenticated \
  --runtime dotnet3 \
  --trigger-http \
  --region=$REGION \
  --entry-point Filter.Function \
  --set-build-env-vars GOOGLE_BUILDABLE=image-v3/filter/csharp

部署函数后,将服务网址设置在一个变量中,我们稍后会用到它:

FILTER_URL=$(gcloud functions describe $SERVICE_NAME --region=$REGION --gen2 --format 'value(serviceConfig.uri)')

6. 部署标签添加者服务

第二个 Cloud Functions 服务接收存储分区和文件信息,使用 Vision API 提取图片的标签,并将标签保存到输出存储分区。

在顶级 processing-pipelines 文件夹中,部署服务:

SERVICE_NAME=labeler

gcloud functions deploy $SERVICE_NAME \
  --gen2 \
  --allow-unauthenticated \
  --runtime dotnet3 \
  --trigger-http \
  --region=$REGION \
  --set-env-vars BUCKET=$BUCKET2 \
  --entry-point Labeler.Function \
  --set-build-env-vars GOOGLE_BUILDABLE=image-v2/labeler/csharp

部署函数后,将服务网址设置在一个变量中,我们稍后会用到它:

LABELER_URL=$(gcloud functions describe $SERVICE_NAME --region=$REGION --gen2 --format 'value(serviceConfig.uri)')

7. 部署调整大小服务

此 Cloud Functions 服务会接收存储分区和文件信息,使用 ImageSharp 调整图片大小,并将图片保存到输出存储分区。

在顶级 processing-pipelines 文件夹中,部署服务:

SERVICE_NAME=resizer

gcloud functions deploy $SERVICE_NAME \
  --gen2 \
  --allow-unauthenticated \
  --runtime dotnet3 \
  --trigger-http \
  --region=$REGION \
  --set-env-vars BUCKET=$BUCKET2 \
  --entry-point Resizer.Function \
  --set-build-env-vars GOOGLE_BUILDABLE=image-v2/resizer/csharp \
  --timeout=120s

请注意,我们将 timeout 值设置为 2 分钟,以便调整大小函数有更多时间进行处理。

部署函数后,将服务网址设置在一个变量中,我们稍后会用到它:

RESIZER_URL=$(gcloud functions describe $SERVICE_NAME --region=$REGION --gen2 --format 'value(serviceConfig.uri)')

8. 部署水印添加器服务

此 Cloud Functions 服务会接收存储分区、文件和标签信息,读取文件,使用 ImageSharp 将标签作为水印添加到图片,并将图片保存到输出存储分区。

在顶级 processing-pipelines 文件夹中,部署服务:

SERVICE_NAME=watermarker

gcloud functions deploy $SERVICE_NAME \
  --gen2 \
  --allow-unauthenticated \
  --runtime dotnet3 \
  --trigger-http \
  --region=$REGION \
  --set-env-vars BUCKET=$BUCKET2 \
  --entry-point Watermarker.Function \
  --set-build-env-vars GOOGLE_BUILDABLE=image-v2/watermarker/csharp

部署函数后,将服务网址设置在一个变量中,我们稍后会用到它:

WATERMARKER_URL=$(gcloud functions describe $SERVICE_NAME --region=$REGION --gen2 --format 'value(serviceConfig.uri)')

此时,所有四个 Cloud Functions 函数都应已部署并正在运行:

fe662925cb0121e9.png

9. 定义和部署工作流

使用 Workflows 将过滤、标记、调整大小和添加水印服务整合到一个工作流中。Workflows 将按我们定义的顺序和参数编排对这些服务的调用。

首先,为工作流启用所需的服务:

gcloud services enable \
  workflows.googleapis.com \
  workflowexecutions.googleapis.com

定义

工作流会接收 CloudEvent 作为参数。创建触发器后,此值将来自 Eventarc。在前两步中,Workflows 会记录事件并从事件中提取存储分区和文件信息:

main:
  params: [event]
  steps:
  - log_event:
      call: sys.log
      args:
          text: ${event}
          severity: INFO
  - extract_bucket_and_file:
      assign:
      - bucket: ${event.data.bucket}
      - file: ${event.data.name}

filter 步骤中,工作流会调用我们之前部署的过滤服务。然后,它会记录并检查文件安全性:

  - filter:
      call: http.post
      args:
        url: FILTER_URL # TODO: Replace
        auth:
          type: OIDC
        body:
            bucket: ${bucket}
            file: ${file}
      result: filterResponse
  - log_safety:
      call: sys.log
      args:
          text: ${filterResponse.body.safe}
          severity: INFO
  - check_safety:
      switch:
        - condition: ${filterResponse.body.safe == true}
          next: label
      next: end

label 步骤中,工作流会调用标签服务并捕获响应(前 3 个标签):

  - label:
      call: http.post
      args:
        url: LABELER_URL # TODO: Replace
        auth:
          type: OIDC
        body:
            bucket: ${bucket}
            file: ${file}
      result: labelResponse

resize 步骤中,Workflows 会调用调整大小服务并捕获响应(调整大小后的图片的存储分区和文件):

  - resize:
      call: http.post
      args:
        url: RESIZER_URL # TODO: Replace
        auth:
          type: OIDC
        body:
            bucket: ${bucket}
            file: ${file}
      result: resizeResponse

watermark 步骤中,工作流使用调整大小后的图片和标签调用水印添加服务,并捕获结果(调整大小并添加水印后的图片):

  - watermark:
      call: http.post
      args:
        url: WATERMARKER_URL # TODO: Replace
        auth:
          type: OIDC
        body:
            bucket: ${resizeResponse.body.bucket}
            file: ${resizeResponse.body.file}
            labels: ${labelResponse.body.labels}
      result: watermarkResponse

final 步骤中,工作流会返回来自标签器、调整大小器和水印添加器服务的 HTTP 状态代码:

  - final:
      return:
        label: ${labelResponse.code}
        resize: ${resizeResponse.code}
        watermark: ${watermarkResponse.code}

部署

在部署工作流之前,请确保手动或使用 sed 将服务网址替换为已部署函数的网址:

在顶级 processing-pipelines 文件夹中,前往 workflows.yaml 文件所在的 image-v3 文件夹:

cd image-v3/

运行 sed 以将占位网址替换为已部署服务的实际网址:

sed -i -e "s|FILTER_URL|${FILTER_URL}|" workflow.yaml
sed -i -e "s|LABELER_URL|${LABELER_URL}|" workflow.yaml
sed -i -e "s|RESIZER_URL|${RESIZER_URL}|" workflow.yaml
sed -i -e "s|WATERMARKER_URL|${WATERMARKER_URL}|" workflow.yaml

部署工作流:

WORKFLOW_NAME=image-processing

gcloud workflows deploy $WORKFLOW_NAME \
    --source=workflow.yaml \
    --location=$REGION

几秒钟后,您应该会在控制台中看到已部署的工作流:

a5f537f2b3f3bd3.png

10. 创建触发器

工作流部署完毕后,最后一步是使用 Eventarc 触发器将其连接到 Cloud Storage 事件。

一次性设置

首先,为 Eventarc 启用所需的服务:

gcloud services enable \
 eventarc.googleapis.com

创建将在 Eventarc 触发器中使用的服务账号。

SERVICE_ACCOUNT=eventarc-trigger-imageproc-sa

gcloud iam service-accounts create $SERVICE_ACCOUNT \
  --display-name="Eventarc trigger image processing service account"

授予 workflows.invoker 角色,以便可以使用该服务账号从 Eventarc 调用 Workflows:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --role roles/workflows.invoker \
  --member serviceAccount:$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com

授予 eventarc.eventReceiver 角色,以便在

Cloud Storage 触发器:

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

pubsub.publisher 角色授予 Cloud Storage 服务账号。Eventarc 的 Cloud Storage 触发器需要以下权限:

STORAGE_SERVICE_ACCOUNT="$(gsutil kms serviceaccount -p $PROJECT_ID)"

gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member serviceAccount:$STORAGE_SERVICE_ACCOUNT \
    --role roles/pubsub.publisher

创建

运行以下命令以创建触发器。此触发器会过滤来自输入 Cloud Storage 存储分区的新文件创建事件,并将这些事件传递给之前定义的工作流:

TRIGGER_NAME=trigger-image-processing

gcloud eventarc triggers create $TRIGGER_NAME \
  --location=$REGION \
  --destination-workflow=$WORKFLOW_NAME \
  --destination-workflow-location=$REGION \
  --event-filters="type=google.cloud.storage.object.v1.finalized" \
  --event-filters="bucket=$BUCKET1" \
  --service-account=$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com

您可以在 Cloud Console 的 Eventarc 部分中看到触发器已创建并处于就绪状态:

a5f4301863d7d9e4.png

11. 测试流水线

图片处理流水线已准备好接收来自 Cloud Storage 的事件。如需测试流水线,请将图片上传到输入存储分区:

gsutil cp beach.jpg gs://$BUCKET1

上传图片后,您应该会立即看到处于有效状态的工作流执行:

2c914341950b5fde.png

大约一分钟后,您应该会看到执行成功。您还可以查看工作流的输入和输出:

9abba6c28c51a9b5.png

如果您列出输出存储分区的内容,则应会看到调整大小后的图片、调整大小并添加水印后的图片以及图片的标签:

gsutil ls gs://$BUCKET2

gs://$PROJECT_ID-images-output-$RANDOM/beach-400x400-watermark.jpeg
gs://$PROJECT_ID-images-output-$RANDOM/beach-400x400.png
gs://$PROJECT_ID-images-output-$RANDOM/beach-labels.txt

如需仔细检查,您可以打开调整大小并添加水印后的图片,查看结果:

46d375cb05a8aae4.jpeg

12. 恭喜

恭喜,您已完成此 Codelab!

所学内容

  • Eventarc 和 Workflows 概览
  • 如何部署 Cloud Functions 服务
  • 如何使用 Workflows 编排服务
  • 如何使工作流通过 Eventarc 响应 Cloud Storage 事件