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

1. 简介

cb762f29e9183a3f.png 1c05e3d0c2bd2b45 a03f943ca09ac4c.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 事件。

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

e372ceed8c26c5fb.png

学习内容

  • Eventarc 和 Workflows 概览
  • 如何部署 Cloud Functions 服务
  • 如何使用 Workflows 编排服务
  • 如何使用 Eventarc 让 Workflows 响应 Cloud Storage 事件

2. 设置和要求

自定进度的环境设置

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

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.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 USD 免费试用计划的条件。

启动 Cloud Shell

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

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

55efc1aaa7a4d3ad.png

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

7ffe5cbb04455448.png

这个虚拟机已加载了您需要的所有开发工具。它提供了一个持久的 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. 架构概览

该应用的架构如下所示:

6aa6fbc7721dd6b6

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

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

4. 创建存储分区

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

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

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

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

5. 部署过滤器服务

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

首先,为 Cloud Functions gen2 和 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 函数:

76a218568982c90c.png

9. 定义和部署工作流

使用 Workflows 将过滤器、标签添加者、调整大小器和水位标记服务整合到一个工作流中。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 步骤中,Workflows 调用我们之前部署的过滤器服务。然后,它会记录并检查文件安全性:

  - 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 步骤中,Workflows 调用标签添加者服务并捕获响应(前 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 步骤中,Workflows 使用调整后的图片和标签调用水印服务,并捕获结果(调整大小后带水印的图片):

  - 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 步骤中,Workflows 从标签添加者、调整器和水印服务返回 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

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

92cf4e758bdc3dde

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 控制台的 Eventarc 部分看到触发器已创建并准备就绪:

14330c4fa2451bc0

11. 测试流水线

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

gsutil cp beach.jpg gs://$BUCKET1

上传图片后,您应该会看到 Workflows 执行处于活跃状态:

36d07cb63c39e7d9

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

229200c79d989c25

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

gsutil ls gs://$BUCKET2

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

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

75f3c0019ca842ce.jpeg

12. 恭喜

恭喜,您已完成此 Codelab!

所学内容

  • Eventarc 和 Workflows 概览
  • 如何部署 Cloud Functions 服务
  • 如何使用 Workflows 编排服务
  • 如何使用 Eventarc 让 Workflows 响应 Cloud Storage 事件