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

1. 概览

在之前的实验中,您构建了 Pic-a-daily 应用的事件驱动版本,该版本使用 Google Cloud Storage 触发的 Cloud Function 作为图片分析服务、通过 Pub/Sub 使用 GCS 触发的 Cloud Run 容器作为缩略图服务,并使用 Eventarc 触发 Cloud Run 上的图片垃圾收集器服务。还有一个由 Cloud Scheduler 触发的 Collage 服务:

d93345bfc235f81e.png

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

b763efcbf5589747.png

学习内容

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

2. 设置和要求

自定进度的环境设置

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

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

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

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

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

启动 Cloud Shell

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

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

bce75f34b2c53987.png

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

f6ef2b5f13479f3a.png

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

3. 工作流简介

90fcd42d556e310e.jpeg

您可以使用 Workflows 创建无服务器工作流,以按照您定义的顺序将一系列无服务器任务关联起来。您可以搭配使用 Google Cloud API 和无服务器函数(如 Cloud Functions 和 Cloud Run)的强大功能,调用外部 API 以创建灵活的无服务器应用。

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

凭借以下内置和可配置的功能,它不仅仅是一个简单的编排器:

  • 在各个步骤之间实现灵活的重试和错误处理,以确保可靠地执行步骤。
  • JSON 解析和步骤之间的变量传递,以避免粘合代码。
  • 用于决策的表达式公式支持条件式步骤执行。
  • 用于模块化和可重复使用的工作流的子工作流。
  • 对外部服务的支持可实现对 Google Cloud 之外的服务的编排。
  • 支持对 Google Cloud 和外部服务进行身份验证,以实现安全的步骤执行。
  • 连接器可连接到 Pub/Sub、Firestore、Tasks、Secret Manager 等 Google Cloud 服务,以便更轻松地进行集成。

更不用说,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. 探索工作流 YAML

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

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

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}

接下来,工作流会检查事件类型。支持 2 种事件类型:object.finalize(在云存储分区中保存文件时发出)和 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

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

接下来,我们来看看 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.png

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

删除分支通过返回每个步骤的结果 / 代码来结束:

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

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

7. 创建存储分区

您需要 2 个存储分区来存储图片:1 个用于保存原始高分辨率图片,1 个用于保存图片缩略图。

使用 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 Console 的 Cloud Storage 部分,仔细检查存储分区是否已创建并设为公开:

15063936edd72f06.png

8. Vision Data Transform(Cloud Function)

Workflows.yamliniteventTypeSwitcheventTypeNotSupported 步骤开头。这些规则可确保来自分桶的事件路由到正确的步骤。

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

daaed43a22d2b0d3.png

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

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

此操作在 Cloud Functions 函数的代码中完成,而工作流只需调用此函数:

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

部署函数后,工作流的 transformImageAnalysisData 步骤将能够调用此函数来执行 Vision API 数据转换。

9. 准备数据库

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

6624c616bc7cd97f.png

这两项操作均在 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(字符串):上传的照片的文件名,也是相应文档的键
  • 标签(字符串数组):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.png

工作流 storeMetadata 步骤现在能够将图片元数据存储到 Firestore 中。

10. 缩略图服务 (Cloud Run)

链中的下一个步骤是创建图片的缩略图。这是在 Cloud Run 服务中的代码中完成的,而工作流会在 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}

服务部署完毕后,工作流 thumbnailCall 步骤将能够调用此服务。

11. 拼贴服务 (Cloud Run)

接下来,系统会根据最新图片制作拼贴。这是在 Cloud Run 服务中的代码中完成的,而工作流会在 collageCall 步骤中调用此服务:

591e36149066e1ba.png

探索代码

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.png

12. 工作流部署

我们部署了工作流的所有外部依赖项。其余所有步骤(finalizeCompletedpictureGarbageCollectionGCSpictureGarbageCollectionFirestoredeleteCompleted)都可以由 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 控制台的“工作流”部分中看到它:

94a720149e5df9c5.png

您可以点击工作流并根据需要进行修改。在编辑期间,您可以直观地了解工作流:

55441b158f6027f3.png

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

13. 工作流触发器 (Cloud Functions)

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

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

您将通过 Cloud Functions 触发工作流,而 Cloud Functions 会监听 Cloud Storage 事件。由于 Cloud Functions 函数只能监听一种事件类型,因此您需要部署两个 Cloud Functions 函数,分别监听创建和删除事件:

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}

部署响应最终确定事件的函数:

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.png

14. 前端 (App Engine)

在此步骤中,您将基于 Pic-a-daily:实验 4 - 创建 Web 前端在 Google App Engine 上创建一个 Web 前端,让用户能够从 Web 应用上传图片,并浏览上传的图片及其缩略图。

223fb2281614d053.png

您可以参阅 Pic-a-daily:实验 4 - 创建 Web 前端,详细了解 App Engine 并阅读代码说明。

探索代码

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.png

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

b5a2a3d7a2bc094.png

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

8959df5098c21548.png

再上传 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