Workflows を使用したサーバーレス オーケストレーションの概要

1. はじめに

c9b0cc839df0bb8f.png

Workflows を使用して、定義した順序で一連のサーバーレス タスクを関連付けるサーバーレス ワークフローを作成できます。Google Cloud の API の機能、Cloud Functions や Cloud Run などのサーバーレス プロダクトを組み合わせ、外部 API を呼び出して柔軟なサーバーレス アプリケーションを作成できます。

ワークフローでは、インフラストラクチャの管理が不要であり、需要に合わせてシームレスにスケールします(ゼロへのスケールダウンなど)。料金モデルは従量課金制で、料金は実行時間に対してのみ発生します。

この Codelab では、さまざまな Google Cloud サービスと外部 HTTP API を Workflows で接続する方法について説明します。具体的には、2 つのパブリック Cloud Functions サービス、1 つのプライベート Cloud Run サービス、外部パブリック HTTP API をワークフローに接続します。

学習内容

  • Workflows の基本。
  • パブリック Cloud Functions を Workflows に接続する方法。
  • プライベート Cloud Run サービスを Workflows に接続する方法。
  • 外部 HTTP API を Workflows に接続する方法。

2. 設定と要件

セルフペース型の環境設定

  1. Cloud Console にログインし、新しいプロジェクトを作成するか、既存のプロジェクトを再利用します(Gmail アカウントまたは G Suite アカウントをお持ちでない場合は、アカウントを作成する必要があります)。

H_hgylo4zxOllHaAbPKJ7VyqCKPDUnDhkr-BsBIFBsrB6TYSisg6LX-uqmMhh4sXUy_hoa2Qv87C2nFmkg-QAcCiZZp0qtpf6VPaNEEfP_iqt29KVLD-gklBWugQVeOWsFnJmNjHDw

dcCPqfBIwNO4R-0fNQLUC4aYXOOZhKhjUnakFLZJGeziw2ikOxGjGkCHDwN5x5kCbPFB8fiOzZnX-GfuzQ8Ox-UU15BwHirkVPR_0RJwl0oXrhqZmMIvZMa_uwHugBJIdx5-bZ6Z8Q

jgLzVCxk93d6E2bbonzATKA4jFZReoQ-fORxZZLEi5C3D-ubnv6nL-eP-iyh7qAsWyq_nyzzuEoPFD1wFOFZOe4FWhPBJjUDncnTxTImT3Ts9TM54f4nPpsAp52O0y3Cb19IceAEgQ

プロジェクト ID を忘れないようにしてください。プロジェクト ID はすべての Google Cloud プロジェクトを通じて一意の名前にする必要があります(上記の名前はすでに使用されているので使用できません)。以降、このコードラボでは PROJECT_ID と呼びます。

  1. 次に、Google Cloud リソースを使用するために、Cloud Console で課金を有効にする必要があります。

このコードラボを実行しても、費用はほとんどかからないはずです。このチュートリアル以外で請求が発生しないように、リソースのシャットダウン方法を説明する「クリーンアップ」セクションの手順に従うようにしてください。Google Cloud の新規ユーザーは $300 の無料トライアル プログラムをご利用いただけます。

Cloud Shell の起動

Google Cloud はノートパソコンからリモートで操作できますが、この Codelab では、Google Cloud Shell(Cloud 上で動作するコマンドライン環境)を使用します。

GCP Console で右上のツールバーにある Cloud Shell アイコンをクリックします。

STgwiN06Y0s_gL7i9bTed8duc9tWOIaFw0z_4QOjc-jeOmuH2TBK8l4udei56CKPLoM_i1yEF6pn5Ga88eniJQoEh8cAiTH79gWUHJdKOw0oiBZfBpOdcEOl6p29i4mvPe_A6UMJBQ

プロビジョニングと環境への接続にはそれほど時間はかかりません。完了すると、次のように表示されます。

r6WRHJDzL-GdB5VDxMWa67_cQxRR_x_xCG5xdt9Nilfuwe9fTGAwM9XSZbNPWvDSFtrZ7DDecKqR5_pIq2IJJ9puAMkC3Kt4JbN9jfMX3gAwTNHNqFmqOJ-3iIX5HSePO4dNVZUkNA

この仮想マシンには、必要な開発ツールがすべて用意されています。永続的なホーム ディレクトリが 5 GB 用意されており、Google Cloud で稼働します。そのため、ネットワークのパフォーマンスと認証機能が大幅に向上しています。このラボでの作業はすべて、ブラウザから実行できます。

3. ワークフローの概要

基本

ワークフローは、Workflows の YAML ベースの構文を使用して記述された一連のステップで構成されます。これがワークフローの定義です。Workflows YAML 構文の詳細については、構文リファレンスのページをご覧ください。

ワークフローを作成するとデプロイされ、ワークフローを実行する準備が整います。実行とは、ワークフローの定義に含まれるロジックを 1 回だけ実行することです。すべてのワークフローの実行は独立しており、このプロダクトは多数の同時実行をサポートしています。

サービスを有効にする

この Codelab では、Cloud Functions と Cloud Run サービスを Workflows に接続します。サービスのビルド中には、Cloud Build と Cloud Storage も使用します。

必要なサービスをすべて有効にします。

gcloud services enable \
  cloudfunctions.googleapis.com \
  run.googleapis.com \
  workflows.googleapis.com \
  cloudbuild.googleapis.com \
  storage.googleapis.com

次のステップでは、ワークフローで 2 つの 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 形式で呼び出し元に返します。

この関数は HTTP 処理に Flask を使用しているため、依存関係として追加する必要があります。Python における依存関係は pip で管理され、requirements.txt というメタデータ ファイルで表現されます。

同じディレクトリに、次の内容の requirements.txt ファイルを作成します。

flask>=1.0.2

次のコマンドを使用して、HTTP トリガーを含む関数をデプロイし、未認証リクエストを許可します。

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

関数がデプロイされると、コンソールに表示される url プロパティまたは gcloud functions describe コマンドで表示される関数の URL を確認できます。

次の curl コマンドを使用して、関数の URL にアクセスすることもできます。

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

関数はワークフローの準備が整っています。

5. 2 つ目の Cloud Functions の関数をデプロイする

2 つ目の関数は乗数です。受け取った入力を 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 python312 \
    --trigger-http \
    --allow-unauthenticated

関数がデプロイされたら、次の curl コマンドを使用して、関数の URL にアクセスすることもできます。

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

関数はワークフローの準備が整っています。

6. 2 つの Cloud Functions を接続する

最初のワークフローで、2 つの関数を接続します。

次の内容の 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}

このワークフローでは、最初の関数から乱数を取得し、2 番目の関数に渡します。結果は乗算された乱数です。

最初のワークフローをデプロイします。

gcloud workflows deploy workflow --source=workflow.yaml

最初のワークフローを実行します。

gcloud workflows execute workflow

ワークフローが実行されたら、前の手順で取得した実行 ID を渡して結果を確認できます。

gcloud workflows executions describe <your-execution-id> --workflow workflow

出力には resultstate が含まれます。

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 を見つけます。

7608a7991b33bbb0.png

ワークフローを見つけて、[Definition] タブをクリックします。

f3c8c4d3ffa49b1b.png

ワークフロー定義を編集して、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}

ワークフローは、multiply 関数の出力を math.js のログ関数呼び出しに渡すようになりました。

UI の指示に従ってワークフローを編集してデプロイします。デプロイしたら、Execute をクリックしてワークフローを実行します。実行の詳細が表示されます。

b40c76ee43a1ce65.png

ステータス コード 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.0PORT の環境変数にバインドする必要があります。そのため、上記のコードが必要になります。

この関数は、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 サービスを接続する

プライベート Cloud Run サービスを呼び出すように Workflows を構成する前に、Workflows が使用するサービス アカウントを作成する必要があります。

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}

ワークフローを更新します。今回は、service-account を渡します。

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

出力には、整数 resultstate が含まれます。

result: '{"body":"5","code":200 ... } 

...
state: SUCCEEDED

10. 完了

以上で、この Codelab は完了です。

学習した内容

  • Workflows の基本。
  • パブリック Cloud Functions を Workflows に接続する方法。
  • プライベート Cloud Run サービスを Workflows に接続する方法。
  • 外部 HTTP API を Workflows に接続する方法。