1. はじめに

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. 設定と要件
セルフペース型の環境設定
- Cloud Console にログインし、新しいプロジェクトを作成するか、既存のプロジェクトを再利用します(Gmail アカウントまたは G Suite アカウントをお持ちでない場合は、アカウントを作成する必要があります)。
プロジェクト ID を忘れないようにしてください。プロジェクト ID はすべての Google Cloud プロジェクトを通じて一意の名前にする必要があります(上記の名前はすでに使用されているので使用できません)。以降、このコードラボでは PROJECT_ID と呼びます。
- 次に、Google Cloud リソースを使用するために、Cloud Console で課金を有効にする必要があります。
このコードラボを実行しても、費用はほとんどかからないはずです。このチュートリアル以外で請求が発生しないように、リソースのシャットダウン方法を説明する「クリーンアップ」セクションの手順に従うようにしてください。Google Cloud の新規ユーザーは $300 の無料トライアル プログラムをご利用いただけます。
Cloud Shell の起動
Google Cloud はノートパソコンからリモートで操作できますが、この Codelab では、Google Cloud Shell(Cloud 上で動作するコマンドライン環境)を使用します。
GCP Console で右上のツールバーにある Cloud Shell アイコンをクリックします。
プロビジョニングと環境への接続にはそれほど時間はかかりません。完了すると、次のように表示されます。
この仮想マシンには、必要な開発ツールがすべて用意されています。永続的なホーム ディレクトリが 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
出力には 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}
ワークフローは、multiply 関数の出力を math.js のログ関数呼び出しに渡すようになりました。
UI の指示に従ってワークフローを編集してデプロイします。デプロイしたら、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 サービスを接続する
プライベート 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
出力には、整数 result と state が含まれます。
result: '{"body":"5","code":200 ... }
...
state: SUCCEEDED
10. 完了
以上で、この Codelab は完了です。
学習した内容
- Workflows の基本。
- パブリック Cloud Functions を Workflows に接続する方法。
- プライベート Cloud Run サービスを Workflows に接続する方法。
- 外部 HTTP API を Workflows に接続する方法。