使用 Workflows 连接服务

本教程介绍如何使用 Workflows 将一系列服务关联在一起。通过连接两项公共 HTTP 服务(使用 Cloud Functions)、外部 REST API 和专用 Cloud Run 服务,您可以创建柔性无服务器应用。

目标

在本教程中,您将创建一个单独工作流,一次连接一项服务:

  1. 部署两项 Cloud Functions 函数服务:第一个函数生成一个随机数字,然后将该数字传递给第二个函数(此函数会乘以该数字)。
  2. 使用 Workflows 将两个 HTTP 函数连接在一起。执行工作流并返回结果,然后将其传递给外部 API。
  3. 使用 Workflows 连接外部 HTTP API,该 API 会返回给定编号的 log。执行工作流并返回结果,然后将其传递给 Cloud Run 服务。
  4. 部署 Cloud Run 服务以仅允许经过身份验证的访问。该服务会返回给定数字的 math.floor
  5. 使用 Workflows 连接 Cloud Run 服务,执行整个工作流并返回最终结果。

下图简要展示了该过程并直观呈现了最终工作流:

Workflows 直观呈现

费用

本教程使用 Google Cloud 的以下收费组件:

请使用价格计算器根据您的预计用量来估算费用。

Google Cloud 新用户可能有资格申请免费试用

准备工作

如果您的组织将限制应用于您的 Google Cloud 环境,则本文档中的某些步骤可能无法正常工作。在这种情况下,您可能无法完成创建公共 IP 地址或服务帐号密钥等任务。如果您发出的请求会返回有关限制条件的错误,请参阅如何在受限的 Google Cloud 环境中开发应用

  1. 登录您的 Google Cloud 帐号。如果您是 Google Cloud 新手,请创建一个帐号来评估我们的产品在实际场景中的表现。新客户还可获享 $300 赠金,用于运行、测试和部署工作负载。
  2. 在 Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目。

    转到“项目选择器”

  3. 确保您的 Cloud 项目已启用结算功能。 了解如何确认您的项目是否已启用结算功能

  4. 启用 Cloud Build, Cloud Functions, Cloud Run, Cloud Storage, Container Registry, Workflows API。

    启用 API

  5. 在 Google Cloud Console 的项目选择器页面上,选择或创建一个 Google Cloud 项目。

    转到“项目选择器”

  6. 确保您的 Cloud 项目已启用结算功能。 了解如何确认您的项目是否已启用结算功能

  7. 启用 Cloud Build, Cloud Functions, Cloud Run, Cloud Storage, Container Registry, Workflows API。

    启用 API

  8. 安装并初始化 Cloud SDK。
  9. 更新 gcloud 组件:
    gcloud components update
  10. 使用您的帐号登录:
    gcloud auth login
  11. 为 Workflows 创建服务帐号,以供使用:

    export SERVICE_ACCOUNT=workflows-sa
    gcloud iam service-accounts create ${SERVICE_ACCOUNT}
    

  12. 如需允许服务帐号调用经过身份验证的 Cloud Run 服务,请向 Workflows 服务帐号授予 run.invoker 角色:

    gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
        --member "serviceAccount:${SERVICE_ACCOUNT}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
        --role "roles/run.invoker"
    

  13. 设置本教程中使用的默认位置:
    gcloud config set project PROJECT_ID
    export REGION=REGION
    gcloud config set run/region ${REGION}
    gcloud config set workflows/location ${REGION}
    

    您需要将:

    • PROJECT_ID 替换为您的 Google Cloud 项目 ID
    • REGION 替换为您选择的受支持的 Workflows 位置

部署第一项 Cloud Functions 服务

收到 HTTP 请求后,此 HTTP 函数会生成一个介于 1 到 100 之间的随机数字,然后以 JSON 格式返回该数字。

  1. 创建名为 randomgen 的目录并切换到该目录:

    mkdir ~/randomgen
    cd ~/randomgen
    
  2. 创建一个文件名为 main.py 且包含以下 Python 代码的文本文件:

    import random, json
    from flask import jsonify
    
    def randomgen(request):
        randomNum = random.randint(1,100)
        output = {"random":randomNum}
        return jsonify(output)
  3. 如需支持依赖于 Flask 进行 HTTP 处理,请为 pip 软件包管理器创建一个文本文件。为该文本文件指定文件名 requirements.txt 并添加以下内容:

    flask>=1.0.2
    
  4. 使用 HTTP 触发器部署函数,并允许未经身份验证的访问:

    gcloud functions deploy randomgen \
    --runtime python37 \
    --trigger-http \
    --allow-unauthenticated
    

    部署该函数可能需要几分钟的时间。或者,您也可以使用 Cloud Console 中的 Cloud Functions 界面来部署该函数。

  5. 部署该函数后,您可以确认 httpsTrigger.url 属性:

    gcloud functions describe randomgen
    
  6. 您可以通过以下 curl 命令来试用该函数:

    curl $(gcloud functions describe randomgen --format='value(httpsTrigger.url)')
    

    系统随机会生成一个数字并返回。

部署第二项 Cloud Functions 服务

收到 HTTP 请求后,此 HTTP 函数会从 JSON 正文中提取 input,将此数字乘以 2,然后以 JSON 格式返回结果。

  1. 创建名为 multiply 的目录并切换到该目录:

    mkdir ~/multiply
    cd ~/multiply
    
  2. 创建一个文件名为 main.py 且包含以下 Python 代码的文本文件:

    import random, json
    from flask import jsonify
    
    def multiply(request):
        request_json = request.get_json()
        output = {"multiplied":2*request_json['input']}
        return jsonify(output)
  3. 如需支持依赖于 Flask 进行 HTTP 处理,请为 pip 软件包管理器创建一个文本文件。为该文本文件指定文件名 requirements.txt 并添加以下内容:

    flask>=1.0.2
    
  4. 使用 HTTP 触发器部署函数,并允许未经身份验证的访问:

    gcloud functions deploy multiply \
    --runtime python37 \
    --trigger-http \
    --allow-unauthenticated
    

    部署该函数可能需要几分钟的时间。或者,您也可以使用 Cloud Console 中的 Cloud Functions 界面来部署该函数。

  5. 部署该函数后,您可以确认 httpsTrigger.url 属性:

    gcloud functions describe multiply
    
  6. 您可以通过以下 curl 命令来试用该函数:

    curl $(gcloud functions describe multiply --format='value(httpsTrigger.url)') \
    -X POST \
    -H "content-type: application/json" \
    -d '{"input": 5}'
    

    系统应会返回数字 10。

在工作流中连接两项 Cloud Functions 服务

工作流由一系列使用 Workflows 语法描述的步骤组成,该语法可以采用 YAML 或 JSON 格式编写。这是工作流的定义。如需了解详细说明,请参阅语法参考文档页面。

  1. 返回到您的主目录:

    cd ~
    
  2. 创建一个文件名为 workflow.yaml 且包含以下内容的文本文件:

    - randomgen_function:
        call: http.get
        args:
            url: https://REGION-PROJECT_ID.cloudfunctions.net/randomgen
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: https://REGION-PROJECT_ID.cloudfunctions.net/multiply
            body:
                input: ${randomgen_result.body.random}
        result: multiply_result
    - return_result:
        return: ${multiply_result}
    

    此操作会将这两个 HTTP 函数关联在一起,并返回最终结果。

  3. 创建工作流后,可以进行部署,使其可以执行。

    gcloud workflows deploy WORKFLOW_NAME --source=workflow.yaml
    

    WORKFLOW_NAME 替换为您的工作流名称。

  4. 执行工作流:

    gcloud workflows run WORKFLOW_NAME
    

    执行是指单次运行工作流定义中包含的逻辑。所有工作流都会独立执行,并且 Workflows 的快速扩缩允许大量并发执行。

    执行工作流后,输出应类似于以下内容:

    result: '{"body":{"multiplied":120},"code":200,"headers":{"Alt-Svc":"h3-29=\":443\";
    ...
    startTime: '2021-05-05T14:17:39.135251700Z'
    state: SUCCEEDED
    

在工作流中连接公共 REST 服务

使用 Google Cloud Console,更新现有工作流并连接公共 REST API (math.js),该 API 可评估数学表达式,例如 curl https://api.mathjs.org/v4/?'expr=log(56)'

  1. 打开 Google Cloud Console 中的 Workflows 页面:
    转到 Workflows 页面

  2. 选择您要更新的工作流的名称。

  3. 如需修改该工作流的来源,请点击 修改,然后点击下一步

  4. 将工作流编辑器中的源代码替换为以下内容:

    - randomgen_function:
        call: http.get
        args:
            url: https://REGION-PROJECT_ID.cloudfunctions.net/randomgen
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: https://REGION-PROJECT_ID.cloudfunctions.net/multiply
            body:
                input: ${randomgen_result.body.random}
        result: multiply_result
    - log_function:
        call: http.get
        args:
            url: https://api.mathjs.org/v4/
            query:
                expr: ${"log(" + string(multiply_result.body.multiplied) + ")"}
        result: log_result
    - return_result:
        return: ${log_result}
    

    这会将外部 REST 服务与 Cloud Functions 函数服务相关联,并返回最终结果。

  5. 点击部署

部署 Cloud Run 服务

部署 Cloud Run 服务,在收到 HTTP 请求后,该服务会从 JSON 正文中提取 input,计算其 math.floor,并返回结果。

  1. 创建名为 floor 的目录并切换到该目录:

    mkdir ~/floor
    cd ~/floor
    
  2. 创建一个文件名为 app.py 且包含以下 Python 代码的文本文件:

    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)))

  3. 在同一目录中,创建一个包含以下内容的 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

  4. 构建容器映像:

    export SERVICE_NAME=floor
    gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}
    
  5. 将容器映像部署到 Cloud Run,确保其仅接受经过身份验证的调用:

    gcloud run deploy ${SERVICE_NAME} \
    --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
    --platform managed \
    --no-allow-unauthenticated
    

当您看到服务网址时,表示部署完成。 在更新工作流定义时,您需要指定该网址。

在工作流中连接 Cloud Run 服务

  1. 打开 Google Cloud Console 中的 Workflows 页面:
    转到 Workflows 页面

  2. 选择您要更新的工作流的名称。

  3. 如需修改该工作流的来源,请点击 修改,然后点击下一步

  4. 将工作流编辑器中的源代码替换为以下内容:

    - randomgen_function:
        call: http.get
        args:
            url: https://REGION-PROJECT_ID.cloudfunctions.net/randomgen
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: https://REGION-PROJECT_ID.cloudfunctions.net/multiply
            body:
                input: ${randomgen_result.body.random}
        result: multiply_result
    - log_function:
        call: http.get
        args:
            url: https://api.mathjs.org/v4/
            query:
                expr: ${"log(" + string(multiply_result.body.multiplied) + ")"}
        result: log_result
    - floor_function:
        call: http.post
        args:
            url: CLOUD_RUN_SERVICE_URL
            auth:
                type: OIDC
            body:
                input: ${log_result.body}
        result: floor_result
    - return_result:
        return: ${floor_result}
    

    CLOUD_RUN_SERVICE_URL 替换为您的 Cloud Run 服务网址。

    这将连接工作流中的 Cloud Run 服务。请注意,auth 密钥可确保在调用 Cloud Run 服务时传递身份验证令牌。如需了解详情,请参阅 Workflows 身份验证

  5. 点击部署

执行最终工作流

  1. 更新工作流,并传入服务帐号:

    cd ~
    gcloud workflows deploy workflow \
    --source=workflow.yaml \
    --service-account=${SERVICE_ACCOUNT}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com
    
  2. 执行工作流:

    gcloud workflows run WORKFLOW_NAME
    

    输出应类似于以下内容:

    result: '{"body":{"multiplied":192},"code":200,"headers":{"Alt-Svc":"h3-29=\":443\";
    ...
    startTime: '2021-05-05T14:36:48.762896438Z'
    state: SUCCEEDED
    

恭喜!您已部署并执行一个将一系列服务连接在一起的工作流。

如需使用表达式、条件跳转、Base64 编码/解码、子工作流等创建更复杂的工作流,请参阅工作流语法参考文档标准库概览

清除数据

如果您为本教程创建了一个新项目,请删除项目。 如果您使用的是现有项目,希望保留此项目且不保留本教程中添加的任何更改,请删除为教程创建的资源

删除项目

为了避免产生费用,最简单的方法是删除您为本教程创建的项目。

要删除项目,请执行以下操作:

  1. 在 Cloud Console 中,转到管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

删除教程资源

  1. 删除您在本教程中部署的 Cloud Run 服务:

    gcloud run services delete SERVICE_NAME

    其中,SERVICE_NAME 是您选择的服务名称。

    您还可以从 Google Cloud Console 中删除 Cloud Run 服务。

  2. 移除您在教程设置过程中添加的 gcloud 默认配置。

     gcloud config unset run/region
     gcloud config unset workflows/location
     gcloud config unset project
    

  3. 删除在本教程中创建的工作流:

    gcloud workflows delete WORKFLOW_NAME
    
  4. 从 Container Registry 中删除名为 gcr.io/PROJECT_ID/SERVICE_NAME容器映像

后续步骤