使用 Eventarc 和工作流构建事件驱动型编排

1. 简介

cb762f29e9183a3f.png 1c05e3d0c2bd2b45.png a03f943ca09ac4c.png

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

工作流是一个全代管式编排平台,按照您指定的顺序执行服务:工作流。这些工作流可以结合使用 Cloud Run 或 Cloud Functions 托管的服务、Cloud Vision AI 和 BigQuery 等 Google Cloud 服务以及任何基于 HTTP 的 API。

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

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

e372ceed8c26c5fb.png

学习内容

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

2. 设置和要求

兑换积分

cae48e4b2e19921d.png

在后续对话框中,点击“接受并继续”按钮以接受服务条款:

27d87930a0daf2f8.png

接受服务条款后,您将被重定向到一个结算摘要页,其右下角会出现一个面板,如下所示:

2076ea7aa9bf3f65.png

最后,当您创建第一个项目时,系统会显示一个对话框,您可以在其中为项目分配结算帐号。选择与免费赠金相关联的结算帐号,然后点击“创建”按钮:

dd3b0e795843296

总而言之,您现在拥有结算帐号和项目,这两个实体相关联,因此您今天的 Codelab 中所做的任何工作都将获得您的免费赠金**。**

自定进度的环境设置

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

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 项目名称是此项目参与者的显示名。它是 Google API 不使用的字符串,并且您可以随时对其进行更新。
  • 项目 ID 在所有 Google Cloud 项目中必须是唯一的,并且不可变(一经设置便无法更改)。Cloud Console 会自动生成一个唯一字符串;通常您并不在意它是什么。在大多数 Codelab 中,您都需要引用项目 ID(它通常标识为 PROJECT_ID),因此,如果您不喜欢它,请再生成一个随机 ID,或者您也可以尝试自己创建一个,看看可用。然后,项目创建后会处于“冻结”状态。
  • 第三个值是一些项目所用的项目编号。如需详细了解所有这三个值,请参阅文档
  1. 接下来,您需要在 Cloud Console 中启用结算功能,才能使用 Cloud 资源/API。此 Codelab 的运行费用应该不会太多。要关闭资源以免产生超出本教程范围的费用,请按照 Codelab 末尾提供的任何“清理”说明操作。Google Cloud 的新用户有资格参与 $300 USD 免费试用计划。

启动 Cloud Shell

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

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

55efc1aaa7a4d3ad.png

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

7ffe5cbb04455448.png

这个虚拟机已加载了您需要的所有开发工具。它提供了一个持久的 5GB 主目录,并在 Google Cloud 上运行,大大增强了网络性能和身份验证。只需一个浏览器,即可完成本实验中的所有工作。

设置 gcloud

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

PROJECT_ID=[YOUR-PROJECT-ID]
REGION=[YOUR-REGION]
gcloud config set core/project $PROJECT_ID
gcloud config set functions/region $REGION

启用服务

启用所有必要的服务:

gcloud services enable \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  cloudfunctions.googleapis.com \
  eventarc.googleapis.com \
  vision.googleapis.com \
  workflows.googleapis.com \
  workflowexecutions.googleapis.com

获取源代码

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

克隆代码库:

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

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

cd eventarc-samples/processing-pipelines

3.架构概览

该应用的架构如下:

6aa6fbc7721dd6b6.png

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

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

4.创建存储分区

为用户创建一个上传存储分区,将图片上传到其中;为图片处理流水线创建一个输出存储分区,以保存处理后的图片。

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

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 安全返回结果。

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

SERVICE_NAME=filter
gcloud functions deploy $SERVICE_NAME \
  --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 --format 'value(httpsTrigger.url)')

6.部署标签添加者服务

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

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

SERVICE_NAME=labeler
gcloud functions deploy $SERVICE_NAME \
  --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 --format 'value(httpsTrigger.url)')

7. 部署大小调整器服务

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

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

SERVICE_NAME=resizer
gcloud functions deploy $SERVICE_NAME \
  --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

部署函数后,在变量中设置服务网址,稍后我们将需要使用该网址:

RESIZER_URL=$(gcloud functions describe $SERVICE_NAME --format 'value(httpsTrigger.url)')

8. 部署水印功能

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

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

SERVICE_NAME=watermarker
gcloud functions deploy $SERVICE_NAME \
  --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 --format 'value(httpsTrigger.url)')

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

5d7d4061e04c91bb.png

9. 定义和部署工作流

使用 Workflows 将过滤器、标签添加者、调整大小器和水印功能整合到一个工作流中。工作流会按照我们定义的参数顺序调用这些服务。

定义

工作流接收 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.png

10. 创建触发器

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

一次性设置

触发器将使用默认的计算服务帐号。确保它具有 eventarc.eventReceiver 角色:

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

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

pubsub.publisher 角色授予 Cloud Storage 服务帐号。以下是 Eventarc 的 Cloud Storage 触发器所需的属性:

SERVICE_ACCOUNT="$(gsutil kms serviceaccount -p $PROJECT_NUMBER)"

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

创建

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

TRIGGER_NAME=trigger-$WORKFLOW_NAME
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=$PROJECT_NUMBER-compute@developer.gserviceaccount.com

您可以在 Cloud Console 的 Eventarc 部分看到触发器已创建并准备就绪:

14330c4fa2451bc0.png

11. 测试流水线

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

gsutil cp beach.jpg gs://$BUCKET1

上传照片后,您应该可以看到处于活跃状态的工作流执行:

36d07cb63c39e7d9.png

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

229200c79d989c25.png

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

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 和工作流概览
  • 如何部署 Cloud Functions 服务
  • 如何使用 Workflows 编排服务
  • 如何让 Workflows 使用 Eventarc 响应 Cloud Storage 事件