1. はじめに
Workflows を使用すると、一連のサーバーレス タスクを定義した順序でリンクするサーバーレス ワークフローを作成できます。Google Cloud の API、Cloud Functions や Cloud Run などのサーバーレス プロダクト、外部 API の呼び出し機能を組み合わせて、柔軟なサーバーレス アプリケーションを作成できます。
Workflows ではインフラストラクチャの管理が不要で、ゼロへのスケールダウンも含め、需要に応じてシームレスにスケーリングできます。料金モデルは従量課金制で、料金は実行時間に対してのみ発生します。
この Codelab では、さまざまな Google Cloud サービスと外部 HTTP API を Workflows に接続する方法を学びます。具体的には、2 つのパブリック Cloud Functions サービス(一方のプライベート Cloud Run サービスと外部の公開 HTTP API)をワークフローに接続します。
学習内容
- Workflows の基礎」へようこそ。
- パブリック Cloud Functions の関数を Workflows に接続する方法。
- 限定公開の Cloud Run サービスを Workflows に接続する方法。
- Workflows で外部 HTTP API を接続する方法。
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 の関数をデプロイする
1 つ目の関数は 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 python37 \ --trigger-http \ --allow-unauthenticated
関数がデプロイされると、コンソールの httpsTrigger.url
プロパティまたは gcloud functions describe
コマンドで関数の URL を確認できます。
次の curl
コマンドを使用して、関数の URL にアクセスすることもできます。
curl $(gcloud functions describe randomgen --format='value(httpsTrigger.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 python37 \ --trigger-http \ --allow-unauthenticated
関数がデプロイされたら、次の curl
コマンドを使用して、関数のその URL にアクセスすることもできます。
curl $(gcloud functions describe multiply --format='value(httpsTrigger.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}
ワークフローは、乗算関数の出力を 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 サービスを含めます。また、Workflows が Cloud Run サービスの呼び出しで認証トークンを渡すように、auth
フィールドも追加しています。
- 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 に接続する方法。
- Workflows で外部 HTTP API を接続する方法。