1. 简介

借助 Eventarc,您可以轻松地将 Cloud Run 服务与来自各种来源的事件相关联。它可让您构建微服务松散耦合且分布式的事件驱动型架构。它会为您处理事件提取、传送、安全、授权和错误处理。
Workflows 是一个全托管式编排平台,该平台会按照您定义的顺序执行服务:工作流。这些工作流可以组合 Cloud Run 或 Cloud Functions 上托管的服务、Google Cloud 服务(如 Cloud Vision AI 和 BigQuery)以及任何基于 HTTP 的 API。
在此 Codelab 中,您将构建一个由事件驱动的微服务编排,用于处理图片。您将使用 Workflows 来编排 4 个图片处理 Cloud Functions 的顺序、输入和输出。然后,您将启用编排功能,以便通过 Eventarc 以松散耦合的方式响应 Cloud Storage 事件。
最后,您将获得一个灵活而结构化的无服务器架构来处理图片。

学习内容
- Eventarc 和 Workflows 概览
- 如何部署 Cloud Functions 服务
- 如何使用 Workflows 编排服务
- 如何使工作流通过 Eventarc 响应 Cloud Storage 事件
2. 设置和要求
自定进度的环境设置
- 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个。



- 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串。您可以随时对其进行更新。
- 项目 ID 在所有 Google Cloud 项目中是唯一的,并且是不可变的(一经设置便无法更改)。Cloud 控制台会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(通常用
PROJECT_ID标识)。如果您不喜欢生成的 ID,可以再随机生成一个 ID。或者,您也可以尝试自己的项目 ID,看看是否可用。完成此步骤后便无法更改该 ID,并且此 ID 在项目期间会一直保留。 - 此外,还有第三个值,即部分 API 使用的项目编号,供您参考。如需详细了解所有这三个值,请参阅文档。
- 接下来,您需要在 Cloud 控制台中启用结算功能,以便使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有的话)。若要关闭资源以避免产生超出本教程范围的结算费用,您可以删除自己创建的资源或删除项目。Google Cloud 新用户符合参与 300 美元免费试用计划的条件。
启动 Cloud Shell
虽然可以通过笔记本电脑对 Google Cloud 进行远程操作,但在此 Codelab 中,您将使用 Google Cloud Shell,这是一个在云端运行的命令行环境。
在 Google Cloud 控制台 中,点击右上角工具栏中的 Cloud Shell 图标:

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

这个虚拟机已加载了您需要的所有开发工具。它提供了一个持久的 5 GB 主目录,并且在 Google Cloud 中运行,大大增强了网络性能和身份验证功能。您在此 Codelab 中的所有工作都可以在浏览器中完成。您无需安装任何程序。
设置 gcloud
在 Cloud Shell 中,设置项目 ID 以及要将应用部署到的区域。将它们保存为 PROJECT_ID 和 REGION 变量。如需查看可用区域,请参阅 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. 架构概览
应用的架构如下:

- 将图片保存到输入存储分区,这会生成 Cloud Storage 创建事件。
- Eventarc 通过 Cloud Storage 触发器读取 Cloud Storage 创建事件,并将其作为 CloudEvent 传递给 Workflows。
- 在工作流的第一步过滤中,Cloud Functions 服务使用 Vision API 确定图片是否安全。如果图片安全,工作流会继续执行后续步骤。
- 在工作流的第二步中,Labeler(一种 Cloud Functions 服务)会使用 Vision API 提取图片的标签,并将这些标签保存到输出存储分区。
- 在第三步中,另一个 Cloud Functions 服务 Resizer 使用 ImageSharp 调整图片大小,并将调整后的图片保存到输出存储分区。
- 在最后一步中,另一个 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 函数都应已部署并正在运行:

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
几秒钟后,您应该会在控制台中看到已部署的工作流:

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 部分中看到触发器已创建并处于就绪状态:

11. 测试流水线
图片处理流水线已准备好接收来自 Cloud Storage 的事件。如需测试流水线,请将图片上传到输入存储分区:
gsutil cp beach.jpg gs://$BUCKET1
上传图片后,您应该会立即看到处于有效状态的工作流执行:

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

如果您列出输出存储分区的内容,则应会看到调整大小后的图片、调整大小并添加水印后的图片以及图片的标签:
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
如需仔细检查,您可以打开调整大小并添加水印后的图片,查看结果:

12. 恭喜
恭喜,您已完成此 Codelab!
所学内容
- Eventarc 和 Workflows 概览
- 如何部署 Cloud Functions 服务
- 如何使用 Workflows 编排服务
- 如何使工作流通过 Eventarc 响应 Cloud Storage 事件