1. はじめに
Cloud Run 関数の作成を開始するには、次の Codelab を使用します。
そうでない場合は、この Codelab で Cloud Functions(第 2 世代)の関数を作成する方法について説明します。
概要
Cloud Functions(第 2 世代)は、Google Cloud の Functions as a Service サービスである Google Cloud Functions の次世代バージョンです。この新しいバージョンには高度な機能セットが組み込まれており、現在 Cloud Run と Eventarc を活用しています。これにより、パフォーマンスとスケーラビリティのより高度な制御と、90 を超えるイベントソースからの関数のランタイムとトリガーのより詳細な制御が可能になります。
この Codelab では、HTTP 呼び出しに応答し、Pub/Sub メッセージと Cloud Audit Logs によってトリガーされる Cloud Functions の関数の作成について説明します。
新機能
この新しいバージョンの Cloud Functions では、Cloud Run、Cloud Build、Artifact Registry、Eventarc を利用した FaaS の拡張エクスペリエンスが提供されます。
インフラストラクチャの強化
- より長いリクエストの処理: Cloud Functions をデフォルトの 5 分より長く実行できます。Cloud Storage や BigQuery からの大規模なデータ ストリームの処理など、より長いリクエストのワークロードを実行しやすくなります。HTTP 関数の場合、最大 60 分です。イベント ドリブン関数の場合、現在は最大 10 分です。
- より大きいインスタンス: 最大 16 GB の RAM と 4 つの vCPU を Cloud Functions で利用することで、より大きなインメモリの、コンピューティング負荷の高いワークロードを実行でき、より多くの並行するワークロードを実行できます。
- 同時実行: 1 つの関数インスタンスで最大 1, 000 件の同時リクエストを処理し、コールド スタートを最小限に抑え、スケーリング時のレイテンシを改善します。
- 最小インスタンス数: コールド スタートを減らし、アプリケーションのブートストラップ時間がアプリケーションのパフォーマンスに影響を与えないように、事前にウォームアップしたインスタンスを提供します。
- トラフィック分割: 関数の複数のバージョンをサポートし、異なるバージョン間でトラフィックを分割し、関数を以前のバージョンにロールバックします。
広範なイベント カバレッジと CloudEvents のサポート
- Eventarc の統合: Cloud Functions に Eventarc のネイティブ サポートが追加されました。これにより、Cloud Audit ログ(BigQuery、Cloud SQL、Cloud Storage など)を使用して 90 を超えるイベントソースが利用可能になりました。もちろん、Cloud Functions は引き続き、Cloud Pub/Sub に直接パブリッシュすることでカスタム ソースからのイベントをサポートします。
- CloudEvent の形式: デベロッパーに一貫したエクスペリエンスを提供するため、ソースに関係なく、すべてのイベント ドリブン関数は業界標準の CloudEvents(cloudevents.io)に準拠しています。ペイロードは、cloudevent.data ペイロードを含む構造化 CloudEvent を介して送信され、CloudEvent 標準を実装します。
学習内容
- Cloud Functions(第 2 世代)の概要。
- HTTP 呼び出しに応答する関数を作成する方法。
- Pub/Sub メッセージに応答する関数を作成する方法。
- Cloud Storage イベントに応答する関数を作成する方法。
- Cloud Audit Logs に応答する関数を作成する方法。
- 2 つのリビジョン間でトラフィックを分割する方法。
- 最小インスタンスを使用してコールド スタートを回避する方法。
- 同時実行を設定する方法。
2. 設定と要件
セルフペース型の環境設定
- Google Cloud Console にログインして、プロジェクトを新規作成するか、既存のプロジェクトを再利用します。Gmail アカウントも Google Workspace アカウントもまだお持ちでない場合は、アカウントを作成してください。
- プロジェクト名は、このプロジェクトの参加者に表示される名称です。Google API では使用されない文字列です。この値はいつでも更新できます。
- プロジェクト ID は、すべての Google Cloud プロジェクトにおいて一意でなければならず、不変です(設定後は変更できません)。Cloud コンソールでは一意の文字列が自動生成されます。通常は、この内容を意識する必要はありません。ほとんどの Codelab では、プロジェクト ID(通常は
PROJECT_ID
と識別されます)を参照する必要があります。生成された ID が好みではない場合は、ランダムに別の ID を生成できます。または、ご自身で試して、利用可能かどうかを確認することもできます。このステップ以降は変更できず、プロジェクトを通して同じ ID になります。 - なお、3 つ目の値として、一部の API が使用するプロジェクト番号があります。これら 3 つの値について詳しくは、こちらのドキュメントをご覧ください。
- 次に、Cloud のリソースや API を使用するために、Cloud コンソールで課金を有効にする必要があります。この Codelab の操作をすべて行って、費用が生じたとしても、少額です。このチュートリアルの終了後に請求が発生しないようにリソースをシャットダウンするには、作成したリソースを削除するか、プロジェクト全体を削除します。Google Cloud の新規ユーザーは、300 米ドル分の無料トライアル プログラムをご利用いただけます。
Cloud Shell の起動
Google Cloud はノートパソコンからリモートで操作できますが、この Codelab では、Google Cloud Shell(Cloud 上で動作するコマンドライン環境)を使用します。
Google Cloud Console で、右上のツールバーにある Cloud Shell アイコンをクリックします。
プロビジョニングと環境への接続にはそれほど時間はかかりません。完了すると、次のように表示されます。
この仮想マシンには、必要な開発ツールがすべて用意されています。永続的なホーム ディレクトリが 5 GB 用意されており、Google Cloud で稼働します。そのため、ネットワークのパフォーマンスと認証機能が大幅に向上しています。この Codelab での作業はすべて、ブラウザ内から実行できます。インストールは不要です。
gcloud を設定する
Cloud Shell で、プロジェクト ID が設定され、PROJECT_ID
変数に保存されていること、および REGION
が us-west1
に設定されていることを確認します。
gcloud config set project [YOUR-PROJECT-ID] PROJECT_ID=$(gcloud config get-value project) REGION=us-west1
API を有効にする
必要なサービスをすべて有効にします。
gcloud services enable \ artifactregistry.googleapis.com \ cloudfunctions.googleapis.com \ cloudbuild.googleapis.com \ eventarc.googleapis.com \ run.googleapis.com \ logging.googleapis.com \ pubsub.googleapis.com
3. HTTP 関数
最初の関数として、HTTP リクエストに応答する認証済みの Node.js 関数を作成します。また、10 分間のタイムアウトを使用して、関数で HTTP リクエストに応答する時間を長くする方法を説明します。
作成
アプリのフォルダを作成し、そのフォルダに移動します。
mkdir ~/hello-http && cd $_
HTTP リクエストに単純に応答する index.js
ファイルを作成します。
const functions = require('@google-cloud/functions-framework'); functions.http('helloWorld', (req, res) => { res.status(200).send('HTTP with Node.js in GCF 2nd gen!'); });
package.json
ファイルを作成して依存関係を指定します。
{ "name": "nodejs-functions-gen2-codelab", "version": "0.0.1", "main": "index.js", "dependencies": { "@google-cloud/functions-framework": "^2.0.0" } }
導入
関数をデプロイします。
gcloud functions deploy nodejs-http-function \ --gen2 \ --runtime nodejs16 \ --entry-point helloWorld \ --source . \ --region $REGION \ --trigger-http \ --timeout 600s
この手順では厳密に必要なわけではありませんが、タイムアウトは 600 秒です。これにより、関数の HTTP リクエストへの応答時間が長くなります。
関数がデプロイされると、Cloud コンソールの [Cloud Functions] セクションに表示されます。
テスト
次のコマンドを使用して関数をテストします。
gcloud functions call nodejs-http-function \ --gen2 --region $REGION
レスポンスとして HTTP with Node.js in GCF 2nd gen!
というメッセージが表示されます。
4. Pub/Sub 関数
2 番目の関数として、特定のトピックに公開された Pub/Sub メッセージによってトリガーされる Python 関数を作成します。
Pub/Sub 認証トークンを設定する
2021 年 4 月 8 日以前に Pub/Sub サービス アカウントを有効にした場合は、Pub/Sub サービス アカウントに iam.serviceAccountTokenCreator
ロールを付与します。
PROJECT_NUMBER=$(gcloud projects list --filter="project_id:$PROJECT_ID" --format='value(project_number)') gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:service-$PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \ --role roles/iam.serviceAccountTokenCreator
作成
サンプルに使用する Pub/Sub トピックを作成します。
TOPIC=cloud-functions-gen2-topic gcloud pubsub topics create $TOPIC
アプリ用のフォルダを作成し、そのフォルダに移動します。
mkdir ~/hello-pubsub && cd $_
CloudEvent ID を含むメッセージをログに記録するだけの main.py
ファイルを作成します。
import functions_framework @functions_framework.cloud_event def hello_pubsub(cloud_event): print('Pub/Sub with Python in GCF 2nd gen! Id: ' + cloud_event['id'])
次の内容の requirements.txt
ファイルを作成して、依存関係を指定します。
functions-framework==3.*
導入
関数をデプロイします。
gcloud functions deploy python-pubsub-function \ --gen2 \ --runtime python39 \ --entry-point hello_pubsub \ --source . \ --region $REGION \ --trigger-topic $TOPIC
デプロイされた関数は、Cloud コンソールの [Cloud Functions] セクションに表示されます。
テスト
トピックにメッセージを送信して関数をテストします。
gcloud pubsub topics publish $TOPIC --message="Hello World"
受信した CloudEvent がログに表示されます。
gcloud functions logs read python-pubsub-function \ --region $REGION --gen2 --format "value(log)"
5. Cloud Storage 関数
次の関数では、Cloud Storage バケットのイベントに応答する Node.js 関数を作成します。
設定
Cloud Storage の関数を使用するには、Cloud Storage サービス アカウントに pubsub.publisher
IAM ロールを付与します。
SERVICE_ACCOUNT=$(gsutil kms serviceaccount -p $PROJECT_NUMBER) gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$SERVICE_ACCOUNT \ --role roles/pubsub.publisher
作成
アプリのフォルダを作成し、そのフォルダに移動します。
mkdir ~/hello-storage && cd $_
Cloud Storage イベントにのみ応答する index.js
ファイルを作成します。
const functions = require('@google-cloud/functions-framework'); functions.cloudEvent('helloStorage', (cloudevent) => { console.log('Cloud Storage event with Node.js in GCF 2nd gen!'); console.log(cloudevent); });
package.json
ファイルを作成して依存関係を指定します。
{ "name": "nodejs-functions-gen2-codelab", "version": "0.0.1", "main": "index.js", "dependencies": { "@google-cloud/functions-framework": "^2.0.0" } }
導入
まず、Cloud Storage バケットを作成します(または既存のバケットを使用します)。
export BUCKET="gs://gcf-gen2-storage-$PROJECT_ID" gsutil mb -l $REGION $BUCKET
関数をデプロイします。
gcloud functions deploy nodejs-storage-function \ --gen2 \ --runtime nodejs16 \ --entry-point helloStorage \ --source . \ --region $REGION \ --trigger-bucket $BUCKET \ --trigger-location $REGION
関数がデプロイされると、Cloud Console の [Cloud Functions] セクションに表示されます。
テスト
バケットにファイルをアップロードして関数をテストします。
echo "Hello World" > random.txt gsutil cp random.txt $BUCKET/random.txt
受信した CloudEvent がログに表示されます。
gcloud functions logs read nodejs-storage-function \ --region $REGION --gen2 --limit=100 --format "value(log)"
6. Cloud Audit Logs 関数
次の関数では、Compute Engine VM インスタンスの作成時に Cloud Audit Logs イベントを受信する Node.js 関数を作成します。これにより、新しく作成された VM にラベルが追加され、VM の作成者が指定されます。
新しく作成された Compute Engine VM を確認する
Compute Engine は、VM の作成時に 2 つの監査ログを出力します。
最初のイベントは VM の作成の開始時に出力され、次のように表示されます。
2 つ目は VM の作成後に出力され、次のような形式になります。
first: true
と last: true
の値を含むオペレーション フィールドに注目してください。2 つ目の監査ログには、インスタンスのラベル付けに必要なすべての情報が含まれています。そのため、last: true
フラグを使用して Cloud Functions で検出します。
設定
Cloud Audit Logs 関数を使用するには、Eventarc の監査ログを有効にする必要があります。また、eventarc.eventReceiver
ロールを持つサービス アカウントを使用する必要があります。
- Compute Engine API に対して Cloud Audit Logs の 管理読み取り、データ読み取り、データ書き込みの各ログタイプを有効にします。
- デフォルトの Compute Engine サービス アカウントに
eventarc.eventReceiver
IAM ロールを付与します。
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \ --role roles/eventarc.eventReceiver
コードを取得する
アプリケーションを含むリポジトリのクローンを作成します。
git clone https://github.com/GoogleCloudPlatform/eventarc-samples.git
アプリのディレクトリに移動します。
cd eventarc-samples/gce-vm-labeler/gcf/nodejs
index.js
ファイルには、CloudEvent にラップされた監査ログを受け取るアプリケーション コードが含まれています。次に、Compute Engine VM インスタンスの詳細を抽出し、VM インスタンスにラベルを設定します。index.js
について、ご自身で詳しく学習してください。
導入
前と同じように、gcloud
を使用して関数をデプロイできます。この関数は、--trigger-event-filters
フラグを使用して Compute Engine の挿入の監査ログをフィルタリングしています。
gcloud functions deploy gce-vm-labeler \ --gen2 \ --runtime nodejs16 \ --entry-point labelVmCreation \ --source . \ --region $REGION \ --trigger-event-filters="type=google.cloud.audit.log.v1.written,serviceName=compute.googleapis.com,methodName=beta.compute.instances.insert" \ --trigger-location us-central1
Google Cloud コンソールから関数をデプロイして Eventarc トリガーを追加することもできます。
まず、[Cloud Functions] セクションに移動し、第 2 世代の環境で関数を作成します。
Add Eventarc Trigger
ボタンをクリックします。
右側にサイドパネルが開き、Eventarc トリガーにさまざまなイベント プロバイダとイベントを選択できます。
適切なイベント プロバイダとイベントを選択し、Save Trigger
をクリックします。
最後に、次のページで、GitHub の index.js
ファイルと package.json
ファイルを使用して index.js
ファイルと package.json
ファイルを更新し、[Deploy
] ボタンをクリックします。
テスト
監査ログ関数をテストするには、Cloud コンソールで Compute Engine VM を作成する必要があります(gcloud
を使用して VM を作成することもできますが、監査ログは生成されないようです)。
Cloud コンソールの [Compute Engine] > [VM インスタンス] セクションに移動し、新しい VM を作成します。VM の作成が完了すると、Cloud コンソールの [基本情報] セクションまたは次のコマンドを使用して、VM に追加された creator
ラベルが表示されます。
gcloud compute instances describe YOUR_VM_NAME
出力にラベルが表示されます。次の例をご覧ください。
... labelFingerprint: ULU6pAy2C7s= labels: creator: atameldev ...
7. トラフィック分割
Cloud Functions(第 2 世代)では、関数の複数のリビジョンを利用できます。トラフィックを異なるリビジョン間で分割し、関数を以前のバージョンにロールバックできます。これは、第 2 世代の関数は内部的には Cloud Run サービスであるためです。
このステップでは、関数の 2 つのリビジョンをデプロイし、トラフィックを 50% ずつ分割します。
作成
アプリのフォルダを作成し、そのフォルダに移動します。
mkdir ~/traffic-splitting && cd $_
色の環境変数を読み取り、その背景色で Hello World
を返す Python 関数を含む main.py
ファイルを作成します。
import os color = os.environ.get('COLOR') def hello_world(request): return f'<body style="background-color:{color}"><h1>Hello World!</h1></body>'
導入
オレンジ色の背景で関数の最初のリビジョンをデプロイします。
COLOR=orange gcloud functions deploy hello-world-colored \ --gen2 \ --runtime python39 \ --entry-point hello_world \ --source . \ --region $REGION \ --trigger-http \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
この時点で、ブラウザで HTTP トリガー(上記のデプロイ コマンドの URI 出力)を表示して関数をテストすると、オレンジ色の背景の Hello World
が表示されます。
黄色の背景の 2 番目のリビジョンをデプロイします。
COLOR=yellow gcloud functions deploy hello-world-colored \ --gen2 \ --runtime python39 \ --entry-point hello_world \ --source . \ --region $REGION \ --trigger-http \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
これは最新のリビジョンであるため、関数をテストすると、黄色の背景の Hello World
が表示されます。
トラフィックを 50% ずつ分割する
オレンジ色と黄色のリビジョン間でトラフィックを分割するには、基盤となる Cloud Run サービスのリビジョン ID を見つける必要があります。リビジョン ID を表示するコマンドは次のとおりです。
gcloud run revisions list --service hello-world-colored \ --region $REGION --format 'value(REVISION)'
出力例を以下に示します。
hello-world-colored-00001-man hello-world-colored-00002-wok
次に、トラフィックをこの 2 つのリビジョンに分割します(リビジョン名に応じて X-XXX
を更新します)。
gcloud run services update-traffic hello-world-colored \ --region $REGION \ --to-revisions hello-world-colored-0000X-XXX=50,hello-world-colored-0000X-XXX=50
テスト
公開 URL にアクセスして関数をテストします。半分はオレンジ色のリビジョンが、もう半分は黄色のリビジョンが表示されます。
詳細については、ロールバック、段階的なロールアウト、トラフィックの移行をご覧ください。
8. 最小インスタンス数
Cloud Functions(第 2 世代)では、ウォーム状態を維持し、いつでもリクエストを処理できる関数インスタンスの最小数を指定できます。これは、コールド スタートの数を制限するのに役立ちます。
このステップでは、初期化に時間がかかる関数をデプロイします。コールド スタートの問題が発生します。次に、最小インスタンス値を 1 に設定して関数をデプロイし、コールド スタートを回避します。
作成
アプリのフォルダを作成し、そのフォルダに移動します。
mkdir ~/min-instances && cd $_
main.go
ファイルを作成します。この Go サービスには、10 秒間スリープして長い初期化をシミュレートする init
関数があります。また、HTTP 呼び出しに応答する HelloWorld
関数もあります。
package p import ( "fmt" "net/http" "time" ) func init() { time.Sleep(10 * time.Second) } func HelloWorld(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Slow HTTP Go in GCF 2nd gen!") }
導入
デフォルトの最小インスタンス値 0 で関数の最初のリビジョンをデプロイします。
gcloud functions deploy slow-function \ --gen2 \ --runtime go116 \ --entry-point HelloWorld \ --source . \ --region $REGION \ --trigger-http \ --allow-unauthenticated
次のコマンドを使用して関数をテストします。
gcloud functions call slow-function \ --gen2 --region $REGION
最初の呼び出しでは 10 秒の遅延(コールド スタート)が発生し、その後メッセージが表示されます。それ以降の呼び出しは、すぐに結果を返す必要があります。
最小インスタンス数を設定する
最初のリクエストのコールド スタートを回避するには、次のように --min-instances
フラグを 1 に設定して関数を再デプロイします。
gcloud functions deploy slow-function \ --gen2 \ --runtime go116 \ --entry-point HelloWorld \ --source . \ --region $REGION \ --trigger-http \ --allow-unauthenticated \ --min-instances 1
テスト
関数を再度テストします。
gcloud functions call slow-function \ --gen2 --region $REGION
最初のリクエストで 10 秒の遅延は発生しなくなります。最小インスタンスにより、長時間使用しなかった後の最初の呼び出しで発生するコールド スタートの問題が解消されました。
詳細については、最小インスタンスの使用をご覧ください。
9. 同時実行
Cloud Functions(第 2 世代)では、関数インスタンスはデフォルトで 1 つの同時リクエストを処理しますが、インスタンスで同時に処理できる同時リクエストの数を指定できます。また、並列リクエストごとに新しい関数インスタンスを作成する必要がないため、コールド スタートを防ぐにも役立ちます。
このステップでは、前のステップの遅い初期化の関数を使用します。10 件のリクエストを送信し、リクエストを処理するために新しい関数インスタンスを作成する必要があるため、コールド スタートの問題が再び発生します。
コールド スタートの問題を解決するには、同時実行値が 100 の別の関数をデプロイします。10 件のリクエストでコールド スタートの問題が発生しなくなり、1 つの関数インスタンスですべてのリクエストを処理できることがわかります。
同時実行なしでテストする
関数の URL を取得します。
SLOW_URL=$(gcloud functions describe slow-function --region $REGION --gen2 --format="value(serviceConfig.uri)")
hey
というオープンソースのベンチマーク ツールを使用して、10 個の同時リクエストを遅い関数に送信します。hey
は Cloud Shell にすでにインストールされています。
hey -n 10 -c 10 $SLOW_URL
hey
の出力から、一部のリクエストに時間がかかっていることがわかります。
Summary: Total: 10.9053 secs Slowest: 10.9048 secs Fastest: 0.4439 secs Average: 9.7930 secs Requests/sec: 0.9170 Total data: 310 bytes Size/request: 31 bytes Response time histogram: 0.444 [1] |■■■■ 1.490 [0] | 2.536 [0] | 3.582 [0] | 4.628 [0] | 5.674 [0] | 6.720 [0] | 7.767 [0] | 8.813 [0] | 9.859 [0] | 10.905 [9] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
これは、リクエストを処理するために関数インスタンスがさらに作成されているためです。関数のアクティブなインスタンス数を確認すると、ある時点で複数のインスタンスが作成され、これがコールド スタートの問題の原因となっていることも確認できます。
導入
前の関数と同じ新しい関数をデプロイします。デプロイすると、同時実行数が増加します。
gcloud functions deploy slow-concurrent-function \ --gen2 \ --runtime go116 \ --entry-point HelloWorld \ --source . \ --region $REGION \ --trigger-http \ --allow-unauthenticated \ --min-instances 1
同時実行を設定する
関数の基盤となる Cloud Run サービスの同時実行数を 100 に設定します(最大 1,000 に設定できます)。これにより、1 つの関数インスタンスで少なくとも 100 件のリクエストを処理できます。
gcloud run services update slow-concurrent-function \ --concurrency 100 \ --cpu 1 \ --region $REGION
同時実行でテストする
関数の URL を取得します。
SLOW_CONCURRENT_URL=$(gcloud functions describe slow-concurrent-function --region $REGION --gen2 --format="value(serviceConfig.uri)")
次に、hey
を使用して 10 件の同時リクエストを送信します。
hey -n 10 -c 10 $SLOW_CONCURRENT_URL
hey
の出力に、すべてのリクエストが迅速に処理されていることが示されます。
Summary: Total: 0.2164 secs Slowest: 0.2163 secs Fastest: 0.0921 secs Average: 0.2033 secs Requests/sec: 46.2028 Total data: 310 bytes Size/request: 31 bytes Response time histogram: 0.092 [1] |■■■■ 0.105 [0] | 0.117 [0] | 0.129 [0] | 0.142 [0] | 0.154 [0] | 0.167 [0] | 0.179 [0] | 0.191 [0] | 0.204 [0] | 0.216 [9] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
同時実行性の向上により、1 つの関数インスタンスですべてのリクエストを処理できるようになり、コールド スタートの問題は解消されました。
詳細については、同時実行をご覧ください。
10. 完了
以上で、この Codelab は完了です。
学習した内容
- Cloud Functions(第 2 世代)の概要。
- HTTP 呼び出しに応答する関数を作成する方法。
- Pub/Sub メッセージに応答する関数を作成する方法。
- Cloud Storage イベントに応答する関数を作成する方法。
- Cloud Audit Logs に応答する関数を作成する方法。
- 2 つのリビジョン間でトラフィックを分割する方法。
- 最小インスタンスを使用してコールド スタートを回避する方法。
- 同時実行を設定する方法。