1. 简介
您可以使用 Workflows 创建无服务器工作流,以便按照您定义的顺序将一系列无服务器任务关联在一起。您可以结合使用 Google Cloud 的 API、Cloud Functions 和 Cloud Run 等无服务器产品以及对外部 API 的调用,以创建灵活的无服务器应用。
Workflows 不需要管理基础架构,可以随需求无缝扩缩,包括缩减至零。由于采用的是按用量付费价格模式,您只需为执行时间付费。
在此 Codelab 中,您将学习如何使用 Workflows 连接各种 Google Cloud 服务和外部 HTTP API。更具体地说,您需要将两项公共 Cloud Functions 服务(一项专用 Cloud Run 服务和外部公共 HTTP API)连接到一个工作流中。
学习内容
- Workflows 基础知识。
- 如何将公共 Cloud Functions 与 Workflows 连接。
- 如何将专用 Cloud Run 服务与 Workflows 连接。
- 如何将外部 HTTP API 与 Workflows 连接。
2. 设置和要求
自定进度的环境设置
请记住项目 ID,它在所有 Google Cloud 项目中都是唯一的名称(上述名称已被占用,您无法使用,抱歉!)。它稍后将在此 Codelab 中被称为 PROJECT_ID
。
- 接下来,您需要在 Cloud 控制台中启用结算功能,才能使用 Google Cloud 资源。
运行此 Codelab 应该不会产生太多的费用(如果有费用的话)。请务必按照“清理”部分部分,其中会指导您如何关停资源,以免产生超出本教程范围的结算费用。Google Cloud 的新用户符合参与 $300 USD 免费试用计划的条件。
启动 Cloud Shell
虽然可以通过笔记本电脑对 Google Cloud 进行远程操作,但在此 Codelab 中,您将使用 Google Cloud Shell,这是一个在云端运行的命令行环境。
在 GCP 控制台中,点击右上角工具栏上的 Cloud Shell 图标:
预配和连接到环境应该只需要片刻时间。完成后,您应该会看到如下内容:
这个虚拟机已加载了您需要的所有开发工具。它提供了一个持久的 5GB 主目录,并且在 Google Cloud 中运行,大大增强了网络性能和身份验证功能。只需一个浏览器,即可完成本实验中的所有工作。
3. Workflows 概览
基础知识
工作流由使用基于 Workflows YAML 的语法描述的一系列步骤组成。这是工作流的定义。如需详细了解 Workflows YAML 语法,请参阅语法参考页面。
创建工作流后,系统会对其进行部署,这使得工作流为执行做好准备。执行是指工作流定义中包含的逻辑的单次运行。所有工作流执行都是独立的,并且该产品支持大量并发执行。
启用服务
在此 Codelab 中,您将通过 Workflows 连接 Cloud Functions(Cloud Run 服务)。您还将在服务构建期间使用 Cloud Build 和 Cloud Storage。
启用所有必要的服务:
gcloud services enable \ cloudfunctions.googleapis.com \ run.googleapis.com \ workflows.googleapis.com \ cloudbuild.googleapis.com \ storage.googleapis.com
在下一步中,您将在一个工作流中连接两个 Cloud Functions 函数。
4. 部署第一个 Cloud Functions 函数
第一个函数是 Python 中的随机数生成器。
创建并导航到函数代码的目录:
mkdir ~/randomgen cd ~/randomgen
在目录中创建一个包含以下内容的 main.py
文件:
import random, json from flask import jsonify def randomgen(request): randomNum = random.randint(1,100) output = {"random":randomNum} return jsonify(output)
收到 HTTP 请求时,此函数会生成一个介于 1 到 100 之间的随机数字,并以 JSON 格式将该值返回给调用方。
该函数依赖 Flask 进行 HTTP 处理,我们需要将其添加为依赖项。Python 中的依赖项可通过 pip 进行管理,并在名为 requirements.txt
的元数据文件中表示。
在同一目录中创建一个 requirements.txt
文件,其中包含以下内容:
flask>=1.0.2
使用 HTTP 触发器部署该函数,并使用以下命令允许未经身份验证的请求:
gcloud functions deploy randomgen \ --runtime python37 \ --trigger-http \ --allow-unauthenticated
部署函数后,您可以在控制台或 gcloud functions describe
命令的 httpsTrigger.url
属性下看到函数的网址。
您还可以使用以下 curl
命令访问该函数的网址:
curl $(gcloud functions describe randomgen --format='value(httpsTrigger.url)')
该函数已准备就绪,可以用于工作流。
5. 部署第二个 Cloud Functions 函数
第二个函数是乘数。它将收到的输入乘以 2。
创建并导航到函数代码的目录:
mkdir ~/multiply cd ~/multiply
在目录中创建一个包含以下内容的 main.py
文件:
import random, json from flask import jsonify def multiply(request): request_json = request.get_json() output = {"multiplied":2*request_json['input']} return jsonify(output)
收到 HTTP 请求时,此函数会从 JSON 正文中提取 input
,将其乘以 2,并以 JSON 格式返回给调用方。
在同一目录中创建相同的 requirements.txt
文件,其中包含以下内容:
flask>=1.0.2
使用 HTTP 触发器部署该函数,并使用以下命令允许未经身份验证的请求:
gcloud functions deploy multiply \ --runtime python37 \ --trigger-http \ --allow-unauthenticated
部署函数后,您还可以使用以下 curl
命令访问该函数的该网址:
curl $(gcloud functions describe multiply --format='value(httpsTrigger.url)') \ -X POST \ -H "content-type: application/json" \ -d '{"input": 5}'
该函数已准备就绪,可以用于工作流。
6. 连接两个 Cloud Functions 函数
在第一个工作流中,将这两个函数关联在一起。
创建一个包含以下内容的 workflow.yaml
文件。
- randomgenFunction: call: http.get args: url: https://<region>-<project-id>.cloudfunctions.net/randomgen result: randomgenResult - multiplyFunction: call: http.post args: url: https://<region>-<project-id>.cloudfunctions.net/multiply body: input: ${randomgenResult.body.random} result: multiplyResult - returnResult: return: ${multiplyResult}
在此工作流中,您将从第一个函数获取一个随机数字,并将其传递给第二个函数。结果就是相乘的随机数。
部署第一个工作流:
gcloud workflows deploy workflow --source=workflow.yaml
执行第一个工作流:
gcloud workflows execute workflow
执行工作流后,您可以通过传入上一步中提供的执行 ID 来查看结果:
gcloud workflows executions describe <your-execution-id> --workflow workflow
输出将包含 result
和 state
:
result: '{"body":{"multiplied":108},"code":200 ... } ... state: SUCCEEDED
7. 连接外部 HTTP API
接下来,您将连接 math.js 作为工作流中的外部服务。
在 math.js 中,您可以按如下所示对数学表达式求值:
curl https://api.mathjs.org/v4/?'expr=log(56)'
这次,您将使用 Cloud 控制台来更新我们的工作流。在 Google Cloud 控制台中找到 Workflows
:
找到您的工作流,然后点击 Definition
标签页:
修改工作流定义并添加对 math.js
的调用。
- randomgenFunction: call: http.get args: url: https://<region>-<project-id>.cloudfunctions.net/randomgen result: randomgenResult - multiplyFunction: call: http.post args: url: https://<region>-<project-id>.cloudfunctions.net/multiply body: input: ${randomgenResult.body.random} result: multiplyResult - logFunction: call: http.get args: url: https://api.mathjs.org/v4/ query: expr: ${"log(" + string(multiplyResult.body.multiplied) + ")"} result: logResult - returnResult: return: ${logResult}
工作流现在将乘法函数的输出馈送到 math.js
中的日志函数调用。
界面将引导您修改和部署工作流。部署后,点击 Execute
以执行工作流。您将看到执行详情:
请注意状态代码 200
和包含日志函数输出的 body
。
您刚刚将一项外部服务集成到了我们的工作流中,太棒了!
8. 部署 Cloud Run 服务
最后,通过调用专用 Cloud Run 服务完成工作流。这意味着工作流需要进行身份验证才能调用 Cloud Run 服务。
Cloud Run 服务返回传入的数值的 math.floor
。
创建并导航到服务代码的目录:
mkdir ~/floor cd ~/floor
在目录中创建一个包含以下内容的 app.py
文件:
import json import logging import os import math from flask import Flask, request app = Flask(__name__) @app.route('/', methods=['POST']) def handle_post(): content = json.loads(request.data) input = float(content['input']) return f"{math.floor(input)}", 200 if __name__ != '__main__': # Redirect Flask logs to Gunicorn logs gunicorn_logger = logging.getLogger('gunicorn.error') app.logger.handlers = gunicorn_logger.handlers app.logger.setLevel(gunicorn_logger.level) app.logger.info('Service started...') else: app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))
Cloud Run 会部署容器,因此您需要 Dockerfile
,并且容器需要绑定到 0.0.0.0
和 PORT
环境变量,因此需要编写上述代码。
收到 HTTP 请求时,此函数会从 JSON 正文中提取 input
,调用 math.floor 并将结果返回给调用方。
在同一目录中,创建以下 Dockerfile
:
# Use an official lightweight Python image. # https://hub.docker.com/_/python FROM python:3.7-slim # Install production dependencies. RUN pip install Flask gunicorn # Copy local code to the container image. WORKDIR /app COPY . . # Run the web service on container startup. Here we use the gunicorn # webserver, with one worker process and 8 threads. # For environments with multiple CPU cores, increase the number of workers # to be equal to the cores available. CMD exec gunicorn --bind 0.0.0.0:8080 --workers 1 --threads 8 app:app
构建容器。
export SERVICE_NAME=floor gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}
构建容器后,将其部署到 Cloud Run。请注意 no-allow-unauthenticated
标志。这可确保服务仅接受经过身份验证的调用:
gcloud run deploy ${SERVICE_NAME} \ --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \ --platform managed \ --no-allow-unauthenticated
部署后,该服务便可供工作流使用。
9. 连接 Cloud Run 服务
您需要先创建一个服务账号以供 Workflows 使用,然后才能配置 Workflows 以调用专用 Cloud Run 服务:
export SERVICE_ACCOUNT=workflows-sa gcloud iam service-accounts create ${SERVICE_ACCOUNT}
将 run.invoker
角色授予服务账号。这将允许服务账号调用经过身份验证的 Cloud Run 服务:
gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ --member "serviceAccount:${SERVICE_ACCOUNT}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \ --role "roles/run.invoker"
更新 workflow.yaml
中的工作流定义,以包含 Cloud Run 服务。请注意,您还添加了 auth
字段,以确保 Workflows 在其对 Cloud Run 服务的调用中传入身份验证令牌:
- randomgenFunction: call: http.get args: url: https://<region>-<project-id>.cloudfunctions.net/randomgen result: randomgenResult - multiplyFunction: call: http.post args: url: https://<region>-<project-id>.cloudfunctions.net/multiply body: input: ${randomgenResult.body.random} result: multiplyResult - logFunction: call: http.get args: url: https://api.mathjs.org/v4/ query: expr: ${"log(" + string(multiplyResult.body.multiplied) + ")"} result: logResult - floorFunction: call: http.post args: url: https://floor-<random-hash>.run.app auth: type: OIDC body: input: ${logResult.body} result: floorResult - returnResult: return: ${floorResult}
更新工作流。这次传入服务账号:
gcloud workflows deploy workflow \ --source=workflow.yaml \ --service-account=${SERVICE_ACCOUNT}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com
执行工作流:
gcloud workflows execute workflow
几秒钟后,您可以查看工作流执行情况以了解结果:
gcloud workflows executions describe <your-execution-id> --workflow workflow
输出将包括整数 result
和 state
:
result: '{"body":"5","code":200 ... } ... state: SUCCEEDED
10. 恭喜!
恭喜您完成此 Codelab。
所学内容
- Workflows 基础知识。
- 如何将公共 Cloud Functions 与 Workflows 连接。
- 如何将专用 Cloud Run 服务与 Workflows 连接。
- 如何将外部 HTTP API 与 Workflows 连接。