1. 概要
前のラボでは、Google Cloud Storage でトリガーされた Cloud Functions を Image Analysis サービスに使用し、Pub/Sub 経由で GCS でトリガーされた Cloud Run コンテナを Thumbnail サービスに使用し、Eventarc を使用して Cloud Run で Image Garbage Collector サービスをトリガーする、イベント ドリブン バージョンの Pic-a-daily アプリを構築しました。Cloud Scheduler によってトリガーされるコラージュ サービスもありました。

このラボでは、アプリのオーケストレートされたバージョンを作成します。システムを流れるさまざまなタイプのイベントの代わりに、Workflows を使用して次のようにサービスをオーケストレートして呼び出します。

学習内容
- App Engine
- Cloud Firestore
- Cloud Functions
- Cloud Run
- Workflows
2. 設定と要件
セルフペース型の環境設定
- Cloud コンソールにログインして、新しいプロジェクトを作成するか、既存のプロジェクトを再利用します(Gmail アカウントも Google Workspace アカウントもまだお持ちでない場合は、アカウントを作成してください)。



プロジェクト 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 の概要

Workflows を使用して、定義した順序で一連のサーバーレス タスクを関連付けるサーバーレス ワークフローを作成できます。Google Cloud の API の機能、Cloud Functions や Cloud Run などのサーバーレス プロダクトを組み合わせ、外部 API を呼び出して柔軟なサーバーレス アプリケーションを作成できます。
オーケストレーターで想定されるように、ワークフローを使用すると、YAML/JSON ベースのワークフロー定義言語でビジネス ロジックのフローを定義でき、そのフローをトリガーする Workflows 実行 API と Workflows UI が提供されます。
ワークフローは単なるオーケストレーターではなく、以下の構成可能な組み込み機能を備えています。
- ステップ間の柔軟な再試行とエラー処理により、ステップを確実に実行できます。
- JSON 解析とステップ間の変数の受け渡しにより、グルーコードを回避できます。
- 決定の式では、条件付きステップの実行が可能です。
- モジュール式で再利用可能な Workflows のサブワークフロー。
- 外部サービスのサポートにより、Google Cloud 以外のサービスのオーケストレーションが可能になります。
- Google Cloud と外部サービスの認証サポートにより、安全なステップ実行が可能になります。
- Pub/Sub、Firestore、Tasks、Secret Manager などの Google Cloud サービスへのコネクタにより、統合が容易になります。
ワークフローがフルマネージド型のサーバーレス プロダクトであることは言うまでもありません。サーバーの構成やスケーリングは不要で、使用分に対してのみ料金が発生します。
4. API を有効にする
このラボでは、Cloud Functions と Cloud Run サービスを Workflows に接続します。また、App Engine、Cloud Build、Vision API などのサービスも使用します。
Cloud Shell で、必要なサービスがすべて有効になっていることを確認します。
gcloud services enable \ appengine.googleapis.com \ cloudbuild.googleapis.com \ cloudfunctions.googleapis.com \ compute.googleapis.com \ firestore.googleapis.com \ run.googleapis.com \ vision.googleapis.com \ workflows.googleapis.com \
しばらくすると、オペレーションが正常に完了したことが表示されます。
Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.
5. コードを取得する
前のコードラボでまだコードを取得していない場合は、次の手順で取得します。
git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop
このラボに関連するフォルダ構造は次のようになります。
frontend | workflows | ├── functions ├── |── trigger-workflow ├── |── vision-data-transform ├── services ├── |── collage ├── |── thumbnails ├── workflows.yaml
関連するフォルダは次のとおりです。
frontendには、ラボ 4 で再利用する App Engine フロントエンドが含まれています。functionsには、Workflow 用に作成された Cloud Functions が含まれています。servicesには、Workflow 用に変更された Cloud Run サービスが含まれています。workflows.yamlは、Workflow 定義ファイルです。
6. Workflows YAML を確認する
workflows.yaml は、一連のステップでワークフローを定義します。詳しく見ていきましょう。
ワークフローの開始時に、いくつかのパラメータが渡されます。これらは、Workflows をトリガーする 2 つの Cloud Functions によって渡されます。これらの関数については後で説明しますが、ワークフローは次のように開始されます。

YAML では、これらのパラメータが init ステップの変数に割り当てられていることがわかります。たとえば、イベントをトリガーするファイル名とバケット名、Workflows が呼び出す Cloud Functions と Cloud Run サービスの一部の URL などです。
main:
params: [args]
steps:
- init:
assign:
- file: ${args.file}
- bucket: ${args.bucket}
- gsUri: ${"gs://" + bucket + "/" + file}
- projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
- urls: ${args.urls}
次に、ワークフローはイベントタイプを確認します。サポートされているイベントタイプは 2 つあります。object.finalize(ファイルがクラウド ストレージ バケットに保存されたときに発行される)と object.delete(ファイルが削除されたときに発行される)です。それ以外の場合は、イベントがサポートされていない例外が発生します。

YAML ワークフロー定義で、ファイル ストレージ イベントのタイプを確認する手順は次のとおりです。
- eventTypeSwitch:
switch:
- condition: ${args.eventType == "google.storage.object.finalize"}
next: imageAnalysisCall
- condition: ${args.eventType == "google.storage.object.delete"}
next: pictureGarbageCollectionGCS
- eventTypeNotSupported:
raise: ${"eventType " + args.eventType + " is not supported"}
next: end
Workflows が switch ステートメントと例外処理をサポートしていることに注目してください。switch 命令とそのさまざまな条件、イベントが認識されない場合にエラーを発生させる raise 命令があります。
次に、imageAnalysisCall を見てみましょう。これは、Workflows から Vision API を呼び出して画像を分析し、Vision API のレスポンス データを変換して写真で認識されたもののラベルを並べ替え、主要な色を選択し、画像を表示しても安全かどうかを確認してから、メタデータを Cloud Firestore に保存する一連の呼び出しです。
Vision Transform Cloud Functions(後でデプロイします)を除き、すべて Workflows で実行されます。

YAML での手順は次のようになります。
- imageAnalysisCall:
call: http.post
args:
url: https://vision.googleapis.com/v1/images:annotate
headers:
Content-Type: application/json
auth:
type: OAuth2
body:
requests:
- image:
source:
gcsImageUri: ${gsUri}
features:
- type: LABEL_DETECTION
- type: SAFE_SEARCH_DETECTION
- type: IMAGE_PROPERTIES
result: imageAnalysisResponse
- transformImageAnalysisData:
call: http.post
args:
url: ${urls.VISION_DATA_TRANSFORM_URL}
auth:
type: OIDC
body: ${imageAnalysisResponse.body}
result: imageMetadata
- checkSafety:
switch:
- condition: ${imageMetadata.body.safe == true}
next: storeMetadata
next: end
- storeMetadata:
call: http.request
args:
url: ${"https://firestore.googleapis.com/v1/projects/" + projectId + "/databases/(default)/documents/pictures/" + file + "?updateMask.fieldPaths=color&updateMask.fieldPaths=labels&updateMask.fieldPaths=created"}
auth:
type: OAuth2
method: PATCH
body:
name: ${"projects/" + projectId + "/databases/(default)/documents/pictures/" + file}
fields:
color:
stringValue: ${imageMetadata.body.color}
created:
timestampValue: ${imageMetadata.body.created}
labels:
arrayValue:
values: ${imageMetadata.body.labels}
result: storeMetadataResponse
画像を分析したら、次の 2 つのステップとして、画像のサムネイルと最新画像のコラージュを作成します。これは、2 つの Cloud Run サービスをデプロイし、thumbnailCall ステップと collageCall ステップからそれらを呼び出すことで行われます。

YAML の手順:
- thumbnailCall:
call: http.post
args:
url: ${urls.THUMBNAILS_URL}
auth:
type: OIDC
body:
gcsImageUri: ${gsUri}
result: thumbnailResponse
- collageCall:
call: http.get
args:
url: ${urls.COLLAGE_URL}
auth:
type: OIDC
result: collageResponse
この実行ブランチは、finalizeCompleted ステップで各サービスからステータス コードを返すことで終了します。
- finalizeCompleted:
return:
imageAnalysis: ${imageAnalysisResponse.code}
storeMetadata: ${storeMetadataResponse.code}
thumbnail: ${thumbnailResponse.code}
collage: ${collageResponse.code}
実行のもう 1 つのブランチは、高解像度の写真を含むファイルがメインのストレージ バケットから削除された場合です。このブランチでは、サムネイルを含むバケット内の画像のサムネイルを削除し、Firestore からそのメタデータを削除します。どちらも Workflows からの HTTP 呼び出しで行われます。

YAML の手順:
- pictureGarbageCollectionGCS:
try:
call: http.request
args:
url: ${"https://storage.googleapis.com/storage/v1/b/thumbnails-" + projectId + "/o/" + file}
auth:
type: OAuth2
method: DELETE
result: gcsDeletionResult
except:
as: e
steps:
- dummyResultInOutVar:
assign:
- gcsDeletionResult:
code: 200
body: "Workaround for empty body response"
- pictureGarbageCollectionFirestore:
call: http.request
args:
url: ${"https://firestore.googleapis.com/v1/projects/" + projectId + "/databases/(default)/documents/pictures/" + file}
auth:
type: OAuth2
method: DELETE
result: firestoreDeletionResult
削除ブランチは、各ステップの結果 / コードを返すことで終了します。
- deleteCompleted:
return:
gcsDeletion: ${gcsDeletionResult}
firestoreDeletion: ${firestoreDeletionResult.code}
次の手順では、Workflows の外部依存関係(バケット、Cloud Functions、Cloud Run サービス、Firestore データベース)をすべて作成します。
7. バケットを作成する
画像用に 2 つのバケットが必要です。1 つは元の高解像度画像を保存するためのバケット、もう 1 つは画像のサムネイルを保存するためのバケットです。
gsutil ツールを使用して、ユーザーが写真をアップロードするための均一アクセスが有効な公開リージョン(この場合はヨーロッパ)バケットを作成します。
export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
gsutil mb -l EU gs://${BUCKET_PICTURES}
gsutil uniformbucketlevelaccess set on gs://${BUCKET_PICTURES}
gsutil iam ch allUsers:objectViewer gs://${BUCKET_PICTURES}
サムネイル用の別の一般公開リージョン バケットを作成します。
export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
gsutil mb -l EU gs://${BUCKET_THUMBNAILS}
gsutil uniformbucketlevelaccess set on gs://${BUCKET_THUMBNAILS}
gsutil iam ch allUsers:objectViewer gs://${BUCKET_THUMBNAILS}
バケットが作成され、一般公開されていることを確認するには、Cloud Console の Cloud Storage セクションにアクセスします。

8. Vision Data Transform(Cloud Functions)
Workflows.yaml は、init、eventTypeSwitch、eventTypeNotSupported の各ステップで始まります。これにより、バケットから送信されたイベントが正しいステップに転送されます。
object.finalize イベントの場合、imageAnalysisCall ステップは Vision API を呼び出して、作成された画像のメタデータを抽出します。これらの手順はすべて Workflows 内で行われます。

次に、Vision API から返されたデータを変換してから、Firestore に保存する必要があります。具体的には、次のことを行う必要があります。
- 画像に対して返されたラベルを一覧表示します。
- 画像のドミナント カラーを取得します。
- 写真が安全かどうかを判断します。
これは Cloud Functions のコードで行われ、Workflows はこの関数を呼び出すだけです。

コードを確認する
Cloud Functions の関数が vision-data-transform で呼び出されます。完全なコードは index.js で確認できます。ご覧のとおり、この関数の唯一の目的は、JSON から JSON への変換を行い、Firestore に写真のメタデータを簡単に保存することです。
Cloud Functions にデプロイする
フォルダに移動します。
cd workflows/functions/vision-data-transform/nodejs
任意のリージョンを設定します。
export REGION=europe-west1
gcloud config set functions/region ${REGION}
次のコマンドで関数をデプロイします。
export SERVICE_NAME=vision-data-transform
gcloud functions deploy ${SERVICE_NAME} \
--source=. \
--runtime nodejs10 \
--entry-point=vision_data_transform \
--trigger-http \
--allow-unauthenticated
関数がデプロイされると、Workflows の transformImageAnalysisData ステップでこの関数を呼び出して Vision API のデータ変換を行うことができます。
9. データベースを準備する
ワークフローの次のステップでは、画像データから画像の安全性を確認し、Vision API から返された画像に関する情報を、高速、フルマネージド、サーバーレス、クラウドネイティブの NoSQL ドキュメント データベースである Cloud Firestore データベースに保存します。

どちらも Workflows で行われますが、メタデータの保存に使用する Firestore データベースを作成する必要があります。
まず、Firestore データベースを配置するリージョンに App Engine アプリを作成します(Firestore の要件)。
export REGION_FIRESTORE=europe-west2
gcloud app create --region=${REGION_FIRESTORE}
次に、同じリージョンに Firestore データベースを作成します。
gcloud firestore databases create --region=${REGION_FIRESTORE}
ドキュメントはコレクションにプログラムで作成され、4 つのフィールドが含まれます。
- name(文字列): アップロードされた写真のファイル名。ドキュメントのキーでもあります。
- labels(文字列の配列): Vision API によって認識されたアイテムのラベル
- color(文字列): ドミナント カラーの 16 進数カラーコード(例: #ab12ef)
- created(日付): この画像のメタデータが保存されたときのタイムスタンプ
- thumbnail(ブール値): この写真のサムネイル画像が生成された場合に存在し、true になる省略可能なフィールド
Firestore でサムネイルが利用可能な写真を探し、作成日で並べ替えるため、検索インデックスを作成する必要があります。次のコマンドでインデックスを作成できます。
gcloud firestore indexes composite create --collection-group=pictures \ --field-config field-path=thumbnail,order=descending \ --field-config field-path=created,order=descending
インデックスの作成には 10 分ほどかかることがあります。
インデックスを作成すると、Cloud Console に表示されます。

Workflows storeMetadata ステップで、画像のメタデータを Firestore に保存できるようになりました。
10. サムネイル サービス(Cloud Run)
チェーンの次のステップは、画像のサムネイルを作成することです。これは Cloud Run サービスのコードで行われ、Workflows は thumbnailCall ステップでこのサービスを呼び出します。

コードを確認する
Cloud Run サービスは thumbnails と呼ばれます。完全なコードは index.js で確認できます。
コンテナ イメージをビルドして公開する
Cloud Run はコンテナを実行しますが、最初にコンテナ イメージ(Dockerfile で定義)をビルドする必要があります。Google Cloud Build を使用してコンテナ イメージをビルドし、Google Container Registry にホストできます。
フォルダに移動します。
cd workflows/services/thumbnails/nodejs
構築:
export SERVICE_SRC=thumbnails
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
. \
--tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}
1 ~ 2 分後にビルドが成功し、コンテナが Google Container Registry にデプロイされます。
Cloud Run へのデプロイ
必要な変数と構成を設定します。
export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed
次のコマンドを使用してデプロイします。
gcloud run deploy ${SERVICE_NAME} \
--image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
--no-allow-unauthenticated \
--memory=1Gi \
--update-env-vars BUCKET_THUMBNAILS=${BUCKET_THUMBNAILS}
サービスがデプロイされると、Workflows の thumbnailCall ステップでこのサービスを呼び出すことができます。
11. コラージュ サービス(Cloud Run)
チェーンの次のステップは、最新の画像からコラージュを作成することです。これは Cloud Run サービスのコードで行われ、Workflows は collageCall ステップでこのサービスを呼び出します。

コードを確認する
Cloud Run サービスは collage と呼ばれます。完全なコードは index.js で確認できます。
コンテナ イメージをビルドして公開する
Cloud Run はコンテナを実行しますが、最初にコンテナ イメージ(Dockerfile で定義)をビルドする必要があります。Google Cloud Build を使用してコンテナ イメージをビルドし、Google Container Registry にホストできます。
フォルダに移動します。
cd services/collage/nodejs
構築:
export SERVICE_SRC=collage
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
. \
--tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}
1 ~ 2 分後にビルドが成功し、コンテナが Google Container Registry にデプロイされます。
Cloud Run へのデプロイ
必要な変数と構成を設定します。
export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed
デプロイ:
gcloud run deploy ${SERVICE_NAME} \
--image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
--no-allow-unauthenticated \
--memory=1Gi \
--update-env-vars BUCKET_THUMBNAILS=${BUCKET_THUMBNAILS}
サービスがデプロイされたら、Cloud Console の Cloud Run セクションで両方のサービスが実行されていることを確認できます。また、Workflows collageCall ステップでこのサービスを呼び出すことができます。

12. Workflows のデプロイ
Workflows のすべての外部依存関係をデプロイしました。残りの手順(finalizeCompleted、pictureGarbageCollectionGCS、pictureGarbageCollectionFirestore、deleteCompleted)はすべて Workflows 自体で完了できます。
ワークフローをデプロイします。
workflows.yaml ファイルを含むフォルダに移動し、次のコマンドでデプロイします。
export WORKFLOW_REGION=europe-west4
export WORKFLOW_NAME=picadaily-workflows
gcloud workflows deploy ${WORKFLOW_NAME} \
--source=workflows.yaml \
--location=${WORKFLOW_REGION}
数秒後にワークフローがデプロイされ、Cloud Console の [ワークフロー] セクションに表示されます。

必要に応じて、ワークフローをクリックして編集できます。編集時には、ワークフローの視覚的な表現が表示されます。

Cloud コンソールから適切なパラメータを使用してワークフローを手動で実行することもできます。代わりに、次のステップで Cloud Storage イベントに応答して自動的に実行します。
13. ワークフロー トリガー(Cloud Functions)
ワークフローがデプロイされ、準備が整いました。次に、Cloud Storage バケットでファイルが作成または削除されたときに Workflows をトリガーする必要があります。これらはそれぞれ storage.object.finalize イベントと storage.object.delete イベントです。
Workflows には、Workflows の作成、管理、実行に使用できる API とクライアント ライブラリがあります。この場合、Workflows Execution API(特に Node.js クライアント ライブラリ)を使用して、ワークフローをトリガーします。
Cloud Storage イベントをリッスンする Cloud Functions から Workflows をトリガーします。Cloud Functions は 1 つのイベントタイプのみをリッスンできるため、作成イベントと削除イベントの両方をリッスンする 2 つの Cloud Functions をデプロイします。

コードを確認する
Cloud Functions の関数が trigger-workflow で呼び出されます。完全なコードは index.js で確認できます。
Cloud Functions にデプロイする
フォルダに移動します。
cd workflows/functions/trigger-workflow/nodejs
必要な変数と構成を設定します。
export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
export WORKFLOW_NAME=picadaily-workflows
export WORKFLOW_REGION=europe-west4
export COLLAGE_URL=$(gcloud run services describe collage-service --format 'value(status.url)')
export THUMBNAILS_URL=$(gcloud run services describe thumbnails-service --format 'value(status.url)')
export VISION_DATA_TRANSFORM_URL=$(gcloud functions describe vision-data-transform --format 'value(httpsTrigger.url)')
gcloud config set functions/region ${REGION}
finalize イベントに応答する関数をデプロイします。
export SERVICE_NAME=trigger-workflow-on-finalize
gcloud functions deploy ${SERVICE_NAME} \
--source=. \
--runtime nodejs10 \
--entry-point=trigger_workflow \
--trigger-resource=${BUCKET_PICTURES} \
--trigger-event=google.storage.object.finalize \
--allow-unauthenticated \
--set-env-vars GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},WORKFLOW_REGION=${WORKFLOW_REGION},WORKFLOW_NAME=${WORKFLOW_NAME},THUMBNAILS_URL=${THUMBNAILS_URL},COLLAGE_URL=${COLLAGE_URL},VISION_DATA_TRANSFORM_URL=${VISION_DATA_TRANSFORM_URL}
削除イベントに応答する 2 つ目の関数をデプロイします。
export SERVICE_NAME=trigger-workflow-on-delete
gcloud functions deploy ${SERVICE_NAME} \
--source=. \
--runtime nodejs10 \
--entry-point=trigger_workflow \
--trigger-resource=${BUCKET_PICTURES} \
--trigger-event=google.storage.object.delete \
--allow-unauthenticated \
--set-env-vars GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},WORKFLOW_REGION=${WORKFLOW_REGION},WORKFLOW_NAME=${WORKFLOW_NAME},THUMBNAILS_URL=${THUMBNAILS_URL},COLLAGE_URL=${COLLAGE_URL},VISION_DATA_TRANSFORM_URL=${VISION_DATA_TRANSFORM_URL}
デプロイが完了すると、Cloud Console に両方の関数が表示されます。

14. フロントエンド(App Engine)
このステップでは、Pic-a-daily: ラボ 4 - ウェブ フロントエンドを作成するで作成したウェブ フロントエンドを Google App Engine 上に作成します。これにより、ユーザーはウェブ アプリケーションから写真をアップロードしたり、アップロードした写真とそのサムネイルを参照したりできるようになります。

App Engine の詳細とコードの説明については、Pic-a-daily: ラボ 4 - ウェブ フロントエンドを作成するをご覧ください。
コードを確認する
App Engine アプリは frontend と呼ばれます。完全なコードは index.js で確認できます。
App Engine にデプロイする
フォルダに移動します。
cd frontend
任意のリージョンを設定し、app.yaml の GOOGLE_CLOUD_PROJECT を実際のプロジェクト ID に置き換えます。
export REGION=europe-west1
gcloud config set compute/region ${REGION}
sed -i -e "s/GOOGLE_CLOUD_PROJECT/${GOOGLE_CLOUD_PROJECT}/" app.yaml
デプロイ:
gcloud app deploy app.yaml -q
1 ~ 2 分後に、アプリケーションがトラフィックを処理していることが通知されます。
Beginning deployment of service [default]... ╔════════════════════════════════════════════════════════════╗ ╠═ Uploading 8 files to Google Cloud Storage ═╣ ╚════════════════════════════════════════════════════════════╝ File upload done. Updating service [default]...done. Setting traffic split for service [default]...done. Deployed service [default] to [https://GOOGLE_CLOUD_PROJECT.appspot.com] You can stream logs from the command line by running: $ gcloud app logs tail -s default To view your application in the web browser run: $ gcloud app browse
Cloud Console の App Engine セクションにアクセスして、アプリがデプロイされていることを確認し、バージョニングやトラフィック分割などの App Engine の機能を試すこともできます。

15. ワークフローをテストする
テストするには、アプリ(https://<YOUR_PROJECT_ID>.appspot.com/)のデフォルトの App Engine URL に移動します。フロントエンド UI が起動して実行されていることを確認できます。

写真をアップロードします。これによりワークフローがトリガーされ、Cloud Console でワークフローの実行が Active 状態になっていることを確認できます。

ワークフローが完了したら、実行 ID をクリックして、さまざまなサービスの出力を確認できます。

さらに 3 枚の写真をアップロードします。Cloud Storage バケットと App Engine フロントエンドで、画像のサムネイルとコラージュが更新されていることも確認できます。

16. クリーンアップ(省略可)
アプリを保持しない場合は、プロジェクト全体を削除してリソースをクリーンアップし、費用を節約してクラウドのマナーを守りましょう。
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
17. 完了
Workflows を使用してサービスをオーケストレートし、呼び出すことで、アプリのオーケストレートされたバージョンを作成しました。
学習した内容
- App Engine
- Cloud Firestore
- Cloud Functions
- Cloud Run
- Workflows