使用 Workflows 搭配 Cloud Run 和 Cloud Run functions 教學課程

本教學課程說明如何使用 Workflows 連結一系列服務。您可以連結兩個公開 HTTP 服務 (使用 Cloud Run 函式)、外部 REST API 和私有 Cloud Run 服務,藉此建立彈性的無伺服器應用程式。

目標

在本教學課程中,您將使用 Google Cloud CLI 建立單一工作流程,並一次連結一項服務:

  1. 部署兩項 Cloud Run 函式:第一項函式會產生隨機數字,然後將該數字傳遞至第二項函式,由第二項函式將該數字相乘。
  2. 使用 Workflows 將這兩個 HTTP 函式連結在一起。 執行工作流程並傳回結果,然後將結果傳遞至外部 API。
  3. 使用 Workflows 連線至外部 HTTP API,針對指定數字傳回 log。執行工作流程,然後傳回結果,再將結果傳遞至 Cloud Run 服務。
  4. 部署只允許通過驗證存取的 Cloud Run 服務。服務會傳回指定號碼的 math.floor
  5. 使用 Workflows 連線至 Cloud Run 服務、執行整個工作流程,並傳回最終結果。

下圖顯示程序總覽,以及最終工作流程的圖表:

工作流程圖表

費用

在本文件中,您會使用下列 Google Cloud的計費元件:

如要根據預測用量估算費用,請使用 Pricing Calculator

初次使用 Google Cloud 的使用者可能符合免費試用期資格。

事前準備

貴機構定義的安全性限制,可能會導致您無法完成下列步驟。如需疑難排解資訊,請參閱「在受限的 Google Cloud 環境中開發應用程式」。

  1. 登入 Google Cloud 帳戶。如果您是 Google Cloud新手,歡迎 建立帳戶,親自評估產品在實際工作環境中的成效。新客戶還能獲得價值 $300 美元的免費抵免額,可用於執行、測試及部署工作負載。
  2. 安裝 Google Cloud CLI。

  3. 若您採用的是外部識別資訊提供者 (IdP),請先使用聯合身分登入 gcloud CLI

  4. 執行下列指令,初始化 gcloud CLI:

    gcloud init
  5. 建立或選取 Google Cloud 專案

    選取或建立專案所需的角色

    • 選取專案:選取專案時,不需要具備特定 IAM 角色,只要您已獲授角色,即可選取任何專案。
    • 建立專案:如要建立專案,您需要具備專案建立者角色 (roles/resourcemanager.projectCreator),其中包含 resourcemanager.projects.create 權限。瞭解如何授予角色
    • 建立 Google Cloud 專案:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替換為您要建立的 Google Cloud 專案名稱。

    • 選取您建立的 Google Cloud 專案:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替換為 Google Cloud 專案名稱。

  6. 確認專案已啟用計費功能 Google Cloud

  7. 啟用 Artifact Registry、Cloud Build、Cloud Run、Cloud Run functions、Cloud Storage 和 Workflows API:

    啟用 API 時所需的角色

    如要啟用 API,您需要具備服務使用情形管理員 IAM 角色 (roles/serviceusage.serviceUsageAdmin),其中包含 serviceusage.services.enable 權限。瞭解如何授予角色

    gcloud services enable artifactregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com cloudfunctions.googleapis.com storage.googleapis.com workflows.googleapis.com
  8. 安裝 Google Cloud CLI。

  9. 若您採用的是外部識別資訊提供者 (IdP),請先使用聯合身分登入 gcloud CLI

  10. 執行下列指令,初始化 gcloud CLI:

    gcloud init
  11. 建立或選取 Google Cloud 專案

    選取或建立專案所需的角色

    • 選取專案:選取專案時,不需要具備特定 IAM 角色,只要您已獲授角色,即可選取任何專案。
    • 建立專案:如要建立專案,您需要具備專案建立者角色 (roles/resourcemanager.projectCreator),其中包含 resourcemanager.projects.create 權限。瞭解如何授予角色
    • 建立 Google Cloud 專案:

      gcloud projects create PROJECT_ID

      PROJECT_ID 替換為您要建立的 Google Cloud 專案名稱。

    • 選取您建立的 Google Cloud 專案:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替換為 Google Cloud 專案名稱。

  12. 確認專案已啟用計費功能 Google Cloud

  13. 啟用 Artifact Registry、Cloud Build、Cloud Run、Cloud Run functions、Cloud Storage 和 Workflows API:

    啟用 API 時所需的角色

    如要啟用 API,您需要具備服務使用情形管理員 IAM 角色 (roles/serviceusage.serviceUsageAdmin),其中包含 serviceusage.services.enable 權限。瞭解如何授予角色

    gcloud services enable artifactregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com cloudfunctions.googleapis.com storage.googleapis.com workflows.googleapis.com
  14. 更新 Google Cloud CLI 元件:
    gcloud components update
  15. 如果您在 Cloud Shell 中執行指令,系統會自動驗證 gcloud CLI;否則,請使用帳戶登入:
    gcloud auth login
  16. 設定本教學課程中使用的預設位置:
    gcloud config set project PROJECT_ID
    export REGION=REGION
    gcloud config set functions/region ${REGION}
    gcloud config set run/region ${REGION}
    gcloud config set workflows/location ${REGION}

    REGION 替換為您選擇的支援 Workflows 位置

  17. 如果您是專案建立者,系統會授予基本「擁有者」角色 (roles/owner)。根據預設,這個身分與存取權管理 (IAM) 角色包含完全存取大多數 Google Cloud資源所需的權限,因此您可以略過這個步驟。

    如果您不是專案建立者,必須在專案中將必要權限授予適當的主體。舉例來說,主體可以是 Google 帳戶 (適用於使用者),也可以是服務帳戶 (適用於應用程式和運算工作負載)。詳情請參閱活動目的地的「角色和權限」頁面。

    所需權限

    如要取得完成本教學課程所需的權限,請要求管理員在專案中授予您下列 IAM 角色:

    如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。

    您或許也能透過自訂角色或其他預先定義的角色,取得必要權限。

  18. 部署工作流程時,您會將其與指定的服務帳戶建立關聯。建立供 Workflows 使用的服務帳戶:
    export SERVICE_ACCOUNT=workflows-sa
    gcloud iam service-accounts create ${SERVICE_ACCOUNT}
  19. 根據預設,所有 Cloud Run 服務都會以私密方式部署,且只有專案擁有者、專案編輯者、Cloud Run 管理員和 Cloud Run 叫用者可以呼叫。如要允許服務帳戶呼叫已通過驗證的 Cloud Run 服務,請將 run.invoker 角色授予 Workflows 服務帳戶:
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member "serviceAccount:${SERVICE_ACCOUNT}@PROJECT_ID.iam.gserviceaccount.com" \
        --role "roles/run.invoker"

部署第一個 Cloud Run 函式

收到 HTTP 要求後,此 HTTP 函式會產生介於 1 到 100 之間的隨機數字,然後以 JSON 格式傳回該數字。

  1. 建立名為 randomgen 的目錄,然後切換至該目錄:

    mkdir ~/randomgen
    cd ~/randomgen
  2. 建立名為 main.py 的文字檔,其中包含下列 Python 程式碼:

    import functions_framework
    import random
    from flask import jsonify
    
    
    @functions_framework.http
    def randomgen(request):
        randomNum = random.randint(1, 100)
        output = {"random": randomNum}
        return jsonify(output)
  3. 如要支援 Flask 的 HTTP 處理依附元件,請為 pip 套件管理工具建立文字檔。將檔案命名為 requirements.txt,並加入下列內容:

    flask>=1.0.2
    functions-framework==3.0.0
  4. 使用 HTTP 觸發條件部署函式,並允許未經驗證的存取:

    gcloud functions deploy randomgen-function \
        --gen2 \
        --runtime python310 \
        --entry-point=randomgen \
        --trigger-http \
        --allow-unauthenticated

    部署函式可能需要幾分鐘的時間。或者,您也可以使用 Cloud Run 函式介面,在 Google Cloud 控制台中部署函式。

  5. 部署 randomgen 函式後,您可以確認 httpsTrigger.url 屬性:

    gcloud functions describe randomgen-function \
        --gen2 \
        --format="value(serviceConfig.uri)"
  6. 儲存網址。您需要在後續練習中,將其新增至工作流程來源檔案。

  7. 您可以使用下列 curl 指令試用函式:

    curl $(gcloud functions describe randomgen-function \
        --gen2 \
        --format="value(serviceConfig.uri)")

    系統會隨機產生並傳回一個數字。

部署第二個 Cloud Run 函式

收到 HTTP 要求後,這項 HTTP 函式會從 JSON 主體中擷取 input,然後將其乘以 2,並以 JSON 格式傳回結果。

  1. 返回主目錄:

    cd ~
  2. 建立名為 multiply 的目錄,然後切換至該目錄:

    mkdir ~/multiply
    cd ~/multiply
  3. 建立名為 main.py 的文字檔,其中包含下列 Python 程式碼:

    import functions_framework
    from flask import jsonify
    
    
    @functions_framework.http
    def multiply(request):
        request_json = request.get_json()
        output = {"multiplied": 2 * request_json['input']}
        return jsonify(output)
  4. 如要支援 Flask 的 HTTP 處理依附元件,請為 pip 套件管理工具建立文字檔。將檔案命名為 requirements.txt,並加入下列內容:

    flask>=1.0.2
    functions-framework==3.0.0
  5. 使用 HTTP 觸發條件部署函式,並允許未經驗證的存取:

    gcloud functions deploy multiply-function \
        --gen2 \
        --runtime python310 \
        --entry-point=multiply \
        --trigger-http \
        --allow-unauthenticated

    部署函式可能需要幾分鐘的時間。或者,您也可以使用 Cloud Run 函式介面,在 Google Cloud 控制台中部署函式。

  6. 部署 multiply 函式後,您可以確認 httpsTrigger.url 屬性:

    gcloud functions describe multiply-function \
        --gen2\
        --format="value(serviceConfig.uri)"
  7. 儲存網址。您需要在後續練習中,將其新增至工作流程來源檔案。

  8. 您可以使用下列 curl 指令試用函式:

    curl -X POST MULTIPLY_FUNCTION_URL \
        -H "Authorization: Bearer $(gcloud auth print-identity-token)" \
        -H "Content-Type: application/json" \
        -d '{"input": 5}'

    系統應會傳回數字 10。

在工作流程中連結這兩項 Cloud Run 函式

工作流程是由一系列步驟組成,這些步驟使用 Workflows 語法描述,且可採用 YAML 或 JSON 格式編寫。這是工作流程的定義。如需詳細說明,請參閱「語法參考資料」頁面。

  1. 返回主目錄:

    cd ~
  2. 建立名為 workflow.yaml 的文字檔,並在當中加入下列內容:

    - randomgen_function:
        call: http.get
        args:
            url: RANDOMGEN_FUNCTION_URL
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: MULTIPLY_FUNCTION_URL
            body:
                input: ${randomgen_result.body.random}
        result: multiply_result
    - return_result:
        return: ${multiply_result}
    

    這個來源檔案會將兩個 HTTP 函式連結在一起,並傳回最終結果。

  3. 建立工作流程後,您可以部署工作流程以準備執行。

    gcloud workflows deploy WORKFLOW_NAME \
        --source=workflow.yaml \
        --service-account=${SERVICE_ACCOUNT}@PROJECT_ID.iam.gserviceaccount.com

    WORKFLOW_NAME 替換成工作流程的名稱。

  4. 執行工作流程:

    gcloud workflows run WORKFLOW_NAME

    執行作業是指單次執行工作流程定義中包含的邏輯。 所有工作流程執行作業都是獨立的,而且工作流程可快速調度資源,因此能同時執行大量作業。

    工作流程執行完畢後,輸出內容應如下所示:

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

在工作流程中連結公開 REST 服務

更新現有工作流程,並連結可評估數學運算式的公開 REST API (math.js)。例如:curl https://api.mathjs.org/v4/?'expr=log(56)'

請注意,由於您已部署工作流程,因此也可以透過 Google Cloud 控制台中的 Workflows 頁面編輯工作流程。

  1. 編輯工作流程的來源檔案,並將其替換為下列內容:

    - randomgen_function:
        call: http.get
        args:
            url: RANDOMGEN_FUNCTION_URL
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: MULTIPLY_FUNCTION_URL
            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 Run 函式,並傳回最終結果。

  2. 部署修改後的工作流程:

    gcloud workflows deploy WORKFLOW_NAME \
        --source=workflow.yaml \
        --service-account=${SERVICE_ACCOUNT}@PROJECT_ID.iam.gserviceaccount.com

部署 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. 建立 Artifact Registry 標準存放區,用於儲存 Docker 容器映像檔:

    gcloud artifacts repositories create REPOSITORY \
        --repository-format=docker \
        --location=${REGION}

    REPOSITORY 替換為存放區的專屬名稱。

  5. 建構容器映像檔:

    export SERVICE_NAME=floor
    gcloud builds submit --tag ${REGION}-docker.pkg.dev/PROJECT_ID/REPOSITORY/${SERVICE_NAME}
  6. 將容器映像檔部署至 Cloud Run,確保只接受已驗證的呼叫:

    gcloud run deploy ${SERVICE_NAME} \
        --image ${REGION}-docker.pkg.dev/PROJECT_ID/REPOSITORY/${SERVICE_NAME}:latest \
        --no-allow-unauthenticated

看到服務網址時,表示部署作業已完成。更新工作流程定義時,您需要指定該網址。

在工作流程中連結 Cloud Run 服務

更新現有工作流程,並指定 Cloud Run 服務的網址。

  1. 返回主目錄:

    cd ~
  2. 編輯工作流程的來源檔案,並將其替換為下列內容:

    - randomgen_function:
        call: http.get
        args:
            url: RANDOMGEN_FUNCTION_URL
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: MULTIPLY_FUNCTION_URL
            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
    - create_output_map:
        assign:
          - outputMap:
              randomResult: ${randomgen_result}
              multiplyResult: ${multiply_result}
              logResult: ${log_result}
              floorResult: ${floor_result}
    - return_output:
        return: ${outputMap}
    
    • RANDOMGEN_FUNCTION_URL 替換為randomgen函式的網址。
    • MULTIPLY_FUNCTION_URL 替換為multiply函式的網址。
    • CLOUD_RUN_SERVICE_URL 換成 Cloud Run 服務網址。

    這會連結工作流程中的 Cloud Run 服務。請注意,auth 金鑰可確保驗證符記會傳遞至 Cloud Run 服務的呼叫。詳情請參閱「從工作流程提出經過驗證的要求」。

  3. 部署修改後的工作流程:

    gcloud workflows deploy WORKFLOW_NAME \
        --source=workflow.yaml \
        --service-account=${SERVICE_ACCOUNT}@PROJECT_ID.iam.gserviceaccount.com
  4. 執行最終工作流程:

    gcloud workflows run WORKFLOW_NAME

    輸出內容應會如下所示:

    result: '{"floorResult":{"body":"4","code":200
      ...
      "logResult":{"body":"4.02535169073515","code":200
      ...
      "multiplyResult":{"body":{"multiplied":56},"code":200
      ...
      "randomResult":{"body":{"random":28},"code":200
      ...
    startTime: '2023-11-13T21:22:56.782669001Z'
    state: SUCCEEDED
    

恭喜!您已部署並執行工作流程,將一系列服務連結在一起。

如要使用運算式、條件式跳轉、Base64 編碼或解碼、子工作流程等功能建立更複雜的工作流程,請參閱 Workflows 語法參考資料標準程式庫總覽

清除所用資源

如果您是為了這個教學課程建立新專案,請刪除專案。如果您已使用現有專案,並想保留專案,但不要本教學課程新增的變更,請刪除為本教學課程建立的資源

刪除專案

如要避免付費,最簡單的方法就是刪除您為了本教學課程所建立的專案。

刪除專案的方法如下:

  1. 前往 Google Cloud 控制台的「Manage resources」(管理資源) 頁面。

    前往「Manage resources」(管理資源)

  2. 在專案清單中選取要刪除的專案,然後點選「Delete」(刪除)
  3. 在對話方塊中輸入專案 ID,然後按一下 [Shut down] (關閉) 以刪除專案。

刪除教學課程資源

後續步驟