每日图片:实验 6 - 使用 Workflows 进行编排

1. 概览

在之前的实验中,您构建了 Pic-a-daily 应用的事件驱动型版本,该版本使用 Google Cloud Storage 触发的 Cloud Functions 函数以用于图片分析服务,一个 GCS 通过 Pub/Sub 触发 Cloud Run 容器的缩略图服务触发 Cloud Run 容器,并使用 Eventarc 触发 Cloud Run 上的图片垃圾回收器服务。还有一项 Cloud Scheduler 触发的拼贴服务:

d93345bfc235f81e.png

在本实验中,您将创建一个应用的编排版本。您无需使用不同类型的事件流经系统,而是使用 Workflows 来编排和调用服务,如下所示:

b763efcbf5589747.png

学习内容

  • App Engine
  • Cloud Firestore
  • Cloud Functions
  • Cloud Run
  • Workflows

2. 设置和要求

自定进度的环境设置

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

96a9c957bc475304

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

请记住项目 ID,它在所有 Google Cloud 项目中都是唯一的名称(上述名称已被占用,您无法使用,抱歉!)。它稍后将在此 Codelab 中被称为 PROJECT_ID

  1. 接下来,您需要在 Cloud 控制台中启用结算功能,才能使用 Google Cloud 资源。

运行此 Codelab 应该不会产生太多的费用(如果有费用的话)。请务必按照“清理”部分部分,其中会指导您如何关停资源,以免产生超出本教程范围的结算费用。Google Cloud 的新用户符合参与 300 美元的免费试用计划的条件。

启动 Cloud Shell

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

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

bce75f34b2c53987.png

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

f6ef2b5f13479f3a.png

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

3. Workflows 简介

90fcd42d556e310e.jpeg

您可以使用 Workflows 创建无服务器工作流,以便按照您定义的顺序将一系列无服务器任务关联在一起。您可以结合使用 Google Cloud 的 API、Cloud Functions 和 Cloud Run 等无服务器产品以及对外部 API 的调用,以创建灵活的无服务器应用。

正如您对编排器所期望的那样,Workflows 允许您使用基于 YAML/JSON 的工作流定义语言来定义业务逻辑的流,并提供 Workflows Execution API 和 Workflows 界面来触发这些流。

它不仅仅是一个具有下列可配置内置功能的编排系统:

  • 在步骤之间灵活地进行重试和错误处理,确保步骤的执行可靠。
  • 在步骤之间进行 JSON 解析和变量传递,以避免粘合代码。
  • 用于决策的表达式公式支持按条件执行步骤。
  • 适用于模块化且可重复使用的工作流的子工作流。
  • 通过支持外部服务,您可以编排 Google Cloud 以外的服务。
  • 为 Google Cloud 和外部服务提供身份验证支持,以确保安全执行步骤。
  • 连接到 Google Cloud 服务(例如 Pub/Sub、Firestore、Tasks、Secret Manager),可简化集成。

更不用说,Workflows 是一款全代管式无服务器产品。您无需配置或扩缩服务器,并且只需为实际用量付费。

4. 启用 API

在本实验中,您将使用 Workflows 连接 Cloud Functions 和 Cloud Run 服务。您还将使用 App Engine、Cloud Build、Vision API 和其他服务。

在 Cloud Shell 中,确保启用了所有必要的服务:

gcloud services enable \
  appengine.googleapis.com \
  cloudbuild.googleapis.com \
  cloudfunctions.googleapis.com \
  compute.googleapis.com \
  firestore.googleapis.com \
  run.googleapis.com \
  vision.googleapis.com \
  workflows.googleapis.com \

一段时间后,您应该会看到操作成功完成:

Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.

5. 获取代码

如果之前的 Codelab 中没有获得过该代码,请执行以下操作:

git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop

您将获得以下与此实验相关的文件夹结构:

frontend
 |
workflows
 |
 ├── functions
 ├── |── trigger-workflow
 ├── |── vision-data-transform
 ├── services
 ├── |── collage
 ├── |── thumbnails
 ├── workflows.yaml

以下是相关文件夹:

  • frontend 包含我们将在实验 4 中重复使用的 App Engine 前端。
  • functions 包含为工作流创建的 Cloud Functions 函数。
  • services 包含为工作流修改的 Cloud Run 服务。
  • workflows.yaml 是工作流定义文件。

6. 探索 Workflows YAML

workflows.yaml 通过一系列步骤定义了工作流。我们来仔细了解一下它。

在工作流开始时,系统会传入一些参数。它们将由两个触发 Workflows 的 Cloud Functions 函数传入。我们稍后会介绍这些函数,但 Workflows 的启动方式如下:

d44a5e18aa9d4660.png

在 YAML 中,您可以看到这些参数在 init 步骤中分配给了变量,例如触发事件的文件和存储分区名称,以及 Workflows 将调用的某些 Cloud Functions 和 Cloud Run 服务的网址:

main:
  params: [args]
  steps:
    - init:
        assign:
          - file: ${args.file}
          - bucket: ${args.bucket}
          - gsUri: ${"gs://" + bucket + "/" + file}
          - projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
          - urls: ${args.urls}

接下来,Workflows 检查事件类型。支持两种事件类型:object.finalize(文件保存在 Cloud Storage 存储分区中时发出)和 object.delete(文件被删除时发出)。执行任何其他操作都会引发不受支持的事件异常。

dd1f450983655619.png

以下是 YAML 工作流定义中的步骤,我们将检查文件存储事件类型:

    - eventTypeSwitch:
        switch:
            - condition: ${args.eventType == "google.storage.object.finalize"}
              next: imageAnalysisCall
            - condition: ${args.eventType == "google.storage.object.delete"}
              next: pictureGarbageCollectionGCS
    - eventTypeNotSupported:
        raise: ${"eventType " + args.eventType + " is not supported"}
        next: end

请注意 Workflows 如何通过 switch 指令及其各种条件支持 switch 语句和异常处理,以及如何在无法识别事件时引发错误。

接下来,我们来看看 imageAnalysisCall。这是来自 Workflows 的一系列调用,用于调用 Vision API 来分析图片,转换 Vision API 响应数据以对图片中识别出的内容的标签进行排序,选择主色,检查图片是否可以安全显示,然后将元数据保存到 Cloud Firestore。

请注意,除 Vision Transform Cloud Functions 函数(稍后将部署)之外的所有其他操作都在 Workflows 中完成:

ca2ad16b9cbb436.png

YAML 格式的步骤如下:

    - imageAnalysisCall:
        call: http.post
        args:
          url: https://vision.googleapis.com/v1/images:annotate
          headers:
            Content-Type: application/json
          auth:
            type: OAuth2
          body:
            requests:
            - image:
                source:
                  gcsImageUri: ${gsUri}
              features:
              - type: LABEL_DETECTION
              - type: SAFE_SEARCH_DETECTION
              - type: IMAGE_PROPERTIES
        result: imageAnalysisResponse
    - transformImageAnalysisData:
        call: http.post
        args:
          url: ${urls.VISION_DATA_TRANSFORM_URL}
          auth:
            type: OIDC
          body: ${imageAnalysisResponse.body}
        result: imageMetadata
    - checkSafety:
        switch:
          - condition: ${imageMetadata.body.safe == true}
            next: storeMetadata
        next: end
    - storeMetadata:
        call: http.request
        args:
          url: ${"https://firestore.googleapis.com/v1/projects/" + projectId + "/databases/(default)/documents/pictures/" + file + "?updateMask.fieldPaths=color&updateMask.fieldPaths=labels&updateMask.fieldPaths=created"}
          auth:
            type: OAuth2
          method: PATCH
          body:
            name: ${"projects/" + projectId + "/databases/(default)/documents/pictures/" + file}
            fields:
              color:
                stringValue: ${imageMetadata.body.color}
              created:
                timestampValue: ${imageMetadata.body.created}
              labels:
                arrayValue:
                  values: ${imageMetadata.body.labels}
        result: storeMetadataResponse

图片分析完毕后,接下来的两个步骤是创建图片的缩略图和最新图片的拼贴图。具体方法是部署 2 项 Cloud Run 服务,并通过 thumbnailCallcollageCall 步骤调用这些服务:

76f9179323c3144

YAML 中的步骤:

   - thumbnailCall:
        call: http.post
        args:
          url: ${urls.THUMBNAILS_URL}
          auth:
            type: OIDC
          body:
              gcsImageUri: ${gsUri}
        result: thumbnailResponse
    - collageCall:
        call: http.get
        args:
          url: ${urls.COLLAGE_URL}
          auth:
            type: OIDC
        result: collageResponse

此执行分支以 finalizeCompleted 步骤中每项服务返回状态代码结束:

    - finalizeCompleted:
        return:
          imageAnalysis: ${imageAnalysisResponse.code}
          storeMetadata: ${storeMetadataResponse.code}
          thumbnail: ${thumbnailResponse.code}
          collage: ${collageResponse.code}

执行的另一个分支是从主存储分区中删除某个文件,该文件包含图片的高分辨率版本。在该分支中,我们需要从包含缩略图的存储分区中删除图片缩略图,并从 Firestore 中删除该图片的元数据。这两个操作都通过 Workflows 中的 HTTP 调用完成:

f172379274dcb3c2.png

YAML 中的步骤:

    - pictureGarbageCollectionGCS:
        try:
          call: http.request
          args:
            url: ${"https://storage.googleapis.com/storage/v1/b/thumbnails-" + projectId + "/o/" + file}
            auth:
              type: OAuth2
            method: DELETE
          result: gcsDeletionResult
        except:
          as: e
          steps:
              - dummyResultInOutVar:
                  assign:
                      - gcsDeletionResult:
                          code: 200
                          body: "Workaround for empty body response"
    - pictureGarbageCollectionFirestore:
        call: http.request
        args:
          url: ${"https://firestore.googleapis.com/v1/projects/" + projectId + "/databases/(default)/documents/pictures/" + file}
          auth:
            type: OAuth2
          method: DELETE
        result: firestoreDeletionResult

delete 分支最后会返回每个步骤的结果 / 代码:

    - deleteCompleted:
        return:
          gcsDeletion: ${gcsDeletionResult}
          firestoreDeletion: ${firestoreDeletionResult.code}

在以下步骤中,我们将创建 Workflows 的所有外部依赖项:存储分区、Cloud Functions、Cloud Run 服务和 Firestore 数据库。

7. 创建存储分区

您需要为图片设置 2 个存储分区:一个用于保存原始高分辨率图片,另一个用于保存图片的缩略图。

使用 gsutil 工具创建一个具有统一访问权限的公共区域级(本例中为欧洲)存储分区,以便用户上传照片:

export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
gsutil mb -l EU gs://${BUCKET_PICTURES}
gsutil uniformbucketlevelaccess set on gs://${BUCKET_PICTURES}
gsutil iam ch allUsers:objectViewer gs://${BUCKET_PICTURES}

为缩略图再创建一个公开区域存储分区:

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
gsutil mb -l EU gs://${BUCKET_THUMBNAILS}
gsutil uniformbucketlevelaccess set on gs://${BUCKET_THUMBNAILS}
gsutil iam ch allUsers:objectViewer gs://${BUCKET_THUMBNAILS}

您可以访问 Cloud 控制台的 Cloud Storage 部分,仔细检查存储分区是否已创建并公开:

15063936edd72f06

8. Vision 数据转换 (Cloud Functions)

Workflows.yamliniteventTypeSwitcheventTypeNotSupported 步开头。这可确保将来自存储分区的事件路由到正确的步骤。

对于 object.finalize 事件,imageAnalysisCall 步骤会调用 Vision API 以提取所创建图片的元数据。所有这些步骤都在 Workflows 中完成:

daaed43a22d2b0d3.png

接下来,我们需要转换从 Vision API 返回的数据,然后才能将其保存到 Firestore。更具体地说,我们需要:

  • 列出为图片返回的标签。
  • 检索图片的主色。
  • 确定照片是否安全。

这是在 Cloud Functions 函数的代码中完成的,Workflows 会直接调用此函数:

5e120e70c67779cd.png

探索代码

Cloud Functions 函数称为 vision-data-transform。您可以在 index.js 中查看其完整代码。如您所见,此函数的唯一目的是执行从 JSON 到 JSON 的转换,以便方便地在 Firestore 中存储图片元数据。

部署到 Cloud Functions

导航到该文件夹:

cd workflows/functions/vision-data-transform/nodejs

设置您选择的区域:

export REGION=europe-west1
gcloud config set functions/region ${REGION}

使用以下命令部署该函数:

export SERVICE_NAME=vision-data-transform
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=vision_data_transform \
  --trigger-http \
  --allow-unauthenticated

部署函数后,Workflows transformImageAnalysisData 步骤将能够调用此函数以执行 Vision API 数据转换。

9. 准备数据库

工作流程中的下一步是通过图片数据检查图片的安全性,然后将 Vision API 返回的图片相关信息存储到 Cloud Firestore 数据库(一种快速、全代管式、无服务器、云原生的 NoSQL 文档数据库)中:

6624c616bc7cd97f

这两项操作都在 Workflows 中完成,但您需要创建 Firestore 数据库才能存储元数据。

首先,在您想要 Firestore 数据库的区域中创建 App Engine 应用(Firestore 的一项要求):

export REGION_FIRESTORE=europe-west2
gcloud app create --region=${REGION_FIRESTORE}

接下来,在同一区域中创建 Firestore 数据库:

gcloud firestore databases create --region=${REGION_FIRESTORE}

这些文档将在我们的集合中以编程方式创建,并包含 4 个字段:

  • name(字符串):已上传图片的文件名,也是文档的键
  • labels(字符串数组):Vision API 识别出的项目的标签
  • color(字符串):主色的十六进制颜色代码(即#ab12ef)
  • created(日期):存储此图片的元数据时的时间戳
  • thumbnail(布尔值):选填字段,如果为此照片生成了缩略图,此字段将是 true

我们将在 Firestore 中搜索包含缩略图的图片,并按创建日期排序,因此需要创建一个搜索索引。您可以使用以下命令创建索引:

gcloud firestore indexes composite create --collection-group=pictures \
  --field-config field-path=thumbnail,order=descending \
  --field-config field-path=created,order=descending

请注意,索引创建过程最多可能需要 10 分钟左右。

创建索引后,您可以在 Cloud 控制台中查看该索引:

43af1f5103bf423

Workflows storeMetadata 步骤现在能够将图片元数据存储到 Firestore。

10. 缩略图服务 (Cloud Run)

链中的下一个步骤是创建图片的缩略图。这是在 Cloud Run 服务的代码中完成的,Workflows 会在 thumbnailCall 步骤中调用此服务:

84d987647f082b53.png

探索代码

Cloud Run 服务称为 thumbnails。您可以在 index.js 中查看其完整代码。

构建和发布容器映像

Cloud Run 可以运行容器,但您首先需要构建容器映像(在 Dockerfile 中定义)。Google Cloud Build 可用于构建容器映像,然后托管到 Google Container Registry。

导航到该文件夹:

cd workflows/services/thumbnails/nodejs

构建:

export SERVICE_SRC=thumbnails
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
  . \
  --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}

一两分钟后,构建应该会成功,容器将部署到 Google Container Registry。

部署到 Cloud Run

设置一些所需的变量和配置:

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed

使用以下命令进行部署:

gcloud run deploy ${SERVICE_NAME} \
    --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
    --no-allow-unauthenticated \
    --memory=1Gi \
    --update-env-vars BUCKET_THUMBNAILS=${BUCKET_THUMBNAILS}

部署该服务后,Workflows thumbnailCall 步骤将能够调用此服务。

11. 拼图服务 (Cloud Run)

链中的下一个步骤是根据最新的图片创建拼贴。这是在 Cloud Run 服务的代码中完成的,Workflows 会在 collageCall 步骤中调用此服务:

591e36149066e1ba

探索代码

Cloud Run 服务称为 collage。您可以在 index.js 中查看其完整代码。

构建和发布容器映像

Cloud Run 可以运行容器,但您首先需要构建容器映像(在 Dockerfile 中定义)。Google Cloud Build 可用于构建容器映像,然后托管到 Google Container Registry。

导航到该文件夹:

cd services/collage/nodejs

构建:

export SERVICE_SRC=collage
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
  . \
  --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}

一两分钟后,构建应该会成功,容器将部署到 Google Container Registry。

部署到 Cloud Run

设置一些所需的变量和配置:

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed

部署:

gcloud run deploy ${SERVICE_NAME} \
    --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
    --no-allow-unauthenticated \
    --memory=1Gi \
    --update-env-vars BUCKET_THUMBNAILS=${BUCKET_THUMBNAILS}

部署服务后,您可以在 Cloud 控制台的“Cloud Run”部分下检查两项服务是否正在运行,并且工作流 collageCall 步骤将能够调用此服务:

3ae9873f4cbbf423

12. Workflows 部署

我们部署了 Workflows 的所有外部依赖项。其余所有步骤(finalizeCompletedpictureGarbageCollectionGCSpictureGarbageCollectionFirestoredeleteCompleted)都可以由 Workflows 自行完成。

现在可以部署 Workflows 了!

前往包含 workflows.yaml 文件的文件夹,并使用以下命令部署该文件:

export WORKFLOW_REGION=europe-west4
export WORKFLOW_NAME=picadaily-workflows
gcloud workflows deploy ${WORKFLOW_NAME} \
  --source=workflows.yaml \
  --location=${WORKFLOW_REGION}

工作流应该会在几秒钟后部署完毕,然后您可以在 Cloud 控制台的“Workflows”部分看到它:

94a720149e5df9c5

如果需要,您可以点击工作流并进行修改。在修改过程中,您会获得非常直观的工作流程:

55441b158f6027f3

您也可以在 Cloud 控制台中使用正确的参数手动执行工作流。相反,我们会在下一步中自动执行该操作,以响应 Cloud Storage 事件。

13. Workflows 触发器 (Cloud Functions)

工作流已部署并准备就绪。现在,当 Cloud Storage 存储分区中创建或删除文件时,我们需要触发 Workflows。分别为 storage.object.finalizestorage.object.delete 事件。

Workflows 提供了用于创建、管理和执行您可以使用的 Workflows 的 API 和客户端库。在这种情况下,您将使用 Workflows Execution API,具体来说就是使用其 Node.js 客户端库来触发工作流。

您将通过 Cloud Functions 函数触发 Workflows,以监听 Cloud Storage 事件。由于一个 Cloud Functions 函数只能监听一种事件类型,因此您需要部署两个 Cloud Functions 函数来同时监听 create 事件和 delete 事件:

c4d79646de729e4.png

探索代码

Cloud Functions 函数称为 trigger-workflow。您可以在 index.js 中查看其完整代码。

部署到 Cloud Functions

导航到该文件夹:

cd workflows/functions/trigger-workflow/nodejs

设置一些所需的变量和配置:

export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
export WORKFLOW_NAME=picadaily-workflows
export WORKFLOW_REGION=europe-west4
export COLLAGE_URL=$(gcloud run services describe collage-service --format 'value(status.url)')
export THUMBNAILS_URL=$(gcloud run services describe thumbnails-service --format 'value(status.url)')
export VISION_DATA_TRANSFORM_URL=$(gcloud functions describe vision-data-transform --format 'value(httpsTrigger.url)')
gcloud config set functions/region ${REGION}

部署用于响应 finalize 事件的函数:

export SERVICE_NAME=trigger-workflow-on-finalize
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=trigger_workflow \
  --trigger-resource=${BUCKET_PICTURES} \
  --trigger-event=google.storage.object.finalize \
  --allow-unauthenticated \
  --set-env-vars GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},WORKFLOW_REGION=${WORKFLOW_REGION},WORKFLOW_NAME=${WORKFLOW_NAME},THUMBNAILS_URL=${THUMBNAILS_URL},COLLAGE_URL=${COLLAGE_URL},VISION_DATA_TRANSFORM_URL=${VISION_DATA_TRANSFORM_URL}

部署用于响应删除事件的第二个函数:

export SERVICE_NAME=trigger-workflow-on-delete
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=trigger_workflow \
  --trigger-resource=${BUCKET_PICTURES} \
  --trigger-event=google.storage.object.delete \
  --allow-unauthenticated \
  --set-env-vars GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},WORKFLOW_REGION=${WORKFLOW_REGION},WORKFLOW_NAME=${WORKFLOW_NAME},THUMBNAILS_URL=${THUMBNAILS_URL},COLLAGE_URL=${COLLAGE_URL},VISION_DATA_TRANSFORM_URL=${VISION_DATA_TRANSFORM_URL}

部署完成后,您可以在 Cloud 控制台中看到这两项功能:

7d60c8b7851f39f5

14. 前端 (App Engine)

在此步骤中,您将通过 Pic-a-daily: Lab 4 - 创建网络前端 (Pic-a-daily: Lab 4-Create a web frontend) 在 Google App Engine 上创建一个网络前端,以便用户从网络应用上传图片,以及浏览上传的图片及其缩略图。

223fb2281614d053

如需详细了解 App Engine 并阅读代码说明,请参阅每日图片:实验 4 - 创建网络前端

探索代码

App Engine 应用名为 frontend。您可以在 index.js 中查看其完整代码。

部署到 App Engine

导航到该文件夹:

cd frontend

设置您选择的区域,并将 app.yaml 中的 GOOGLE_CLOUD_PROJECT 替换为您的实际项目 ID:

export REGION=europe-west1
gcloud config set compute/region ${REGION}
sed -i -e "s/GOOGLE_CLOUD_PROJECT/${GOOGLE_CLOUD_PROJECT}/" app.yaml

部署:

gcloud app deploy app.yaml -q

一两分钟后,系统会告知您应用正在处理流量:

Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 8 files to Google Cloud Storage                ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://GOOGLE_CLOUD_PROJECT.appspot.com]
You can stream logs from the command line by running:
  $ gcloud app logs tail -s default
To view your application in the web browser run:
  $ gcloud app browse

您还可以访问 Cloud 控制台的 App Engine 部分,查看应用是否已部署,并探索 App Engine 的功能,例如版本控制和流量分配:

f4bd5f4de028bd83.png

15. 测试工作流

如需进行测试,请转到应用的默认 App Engine 网址 (https://<YOUR_PROJECT_ID>.appspot.com/),您应该会看到前端界面已启动并运行!

1649ac060441099

上传图片。这应该会触发 Workflows,并且您可以在 Cloud 控制台中看到处于 Active 状态的工作流执行情况:

b5a2a3d7a2bc094.png

完成工作流后,您可以点击执行 ID 并查看不同服务的输出:

8959df5098c21548

再上传 3 张照片。您还应该看到 Cloud Storage 存储分区和 App Engine 前端中图片的缩略图和拼贴已更新:

d90c786ff664a5dc.png

16. 清理(可选)

如果您不打算保留该应用,可以通过删除整个项目来清理资源,从而节省成本并成为一个整体优秀的云公民:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT} 

17. 恭喜!

您使用 Workflows 创建了应用的编排版本,以编排和调用服务。

所学内容

  • App Engine
  • Cloud Firestore
  • Cloud Functions
  • Cloud Run
  • Workflows