はじめに
こんにちは。GMO NIKKO の KONCE です。
今回は Cloud Run 関数について Functions Framework と TypeScript を導入する機会があったので方法と Cloud Run 関数のそれぞれのトリガーについてまとめていければと思います。
弊社の過去のデータフロー周りの記事はこちら
Cloud Run 関数について
Cloud Run 関数は、 リクエスト、Cloud Storage イベント、Pub/Sub メッセージなど、様々なトリガーに対応したコードを実行できます。
- イベントドリブン: 特定のイベントが発生すると自動的に実行されます。
- スケーラブル: 必要に応じて自動的にスケールアップまたはスケールダウンします。
- サーバーレス: サーバー管理は Google Cloud が行います。
またCloud Run 関数は、Cloud FunctionsがCloud Runと統合されています。今後UIやコマンドも統合されていきます。
Functions Frameworkについて
Functions Framework は、Google Cloud が提供する、サーバーレス関数を開発するためのオープンソースのフレームワークで、関数をローカルでテストし、エミュレートし、デプロイすることが容易になります。
- 軽量: 依存関係が少ないため、小さいコンテナサイズを実現できます。
- 構造化: 標準的なインターフェースを提供することで、コードの可読性と保守性を向上させます。
- クロスプラットフォーム: Node.js、Python、Go などの様々な言語に対応しています。
コードサンプル
サンプルで HTTPリクエスト、Pub/Sub、GCSのファイル作成のイベントの Cloud Run 関数を用意しました。
Functions Framework は特に指定がなければローカルで8080でHTTPリクエストしてテストすることができます。
またGoogleのCloudEventの構造は @google/events
を使用すると使いやすいかと思います。
ディレクトリ
1 2 3 4 5 6 7 8 |
. ├── dist │ └── index.js ├── package-lock.json ├── package.json ├── src │ └── index.ts └── tsconfig.json |
package.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "main": "dist/index.js", "scripts": { "build": "tsc", "start": "functions-framework --target=$npm_config_function", "prestart": "npm run build", "gcp-build": "npm run build" }, "dependencies": { "@google-cloud/functions-framework": "^3.4.2", "@google/events": "^5.4.0" }, "devDependencies": { "@types/node": "^22.10.1", "typescript": "^5.7.2" } } |
tsconfig.json
1 2 3 4 5 6 7 8 9 10 11 |
{ "compilerOptions": { "target": "es2016", "module": "commonjs", "esModuleInterop": true, "strict": true, "outDir": "dist" }, "include": ["src/**/*"], "exclude": ["node_modules"] } |
index.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import * as ff from '@google-cloud/functions-framework'; import {StorageObjectData} from "@google/events/cloud/storage/v1/StorageObjectData"; import {MessagePublishedData} from "@google/events/cloud/pubsub/v1/MessagePublishedData"; ff.http('http', (req: ff.Request, res: ff.Response) => { console.log('Received HTTP request'); console.log(req.body); res.send('OK'); }); ff.cloudEvent('storage', ce => { console.log('Received storage_finalized event'); console.log(ce.data as StorageObjectData); }); ff.cloudEvent('pubsub', ce => { console.log('Received message_published event'); console.log(ce.data as MessagePublishedData); }); |
トリガー別のCloud Run関数
HTTP関数
HTTPリクエストで関数を呼び出すことができ、多様な実装が可能かと思います。
今回サンプルで用意したのは単にtextを表示させるだけですが、Functions Frameworkのhttp関数を用いて簡単に実装することができます。
1 2 3 4 5 |
ff.http('http', (req: ff.Request, res: ff.Response) => { console.log('Received HTTP request'); console.log(req.body); res.send('OK'); }); |
ローカルでのテスト(HTTP関数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
npm run start --function=http > prestart > npm run build > build > tsc > start > functions-framework --target=$npm_config_function Serving function... Function: http Signature type: http URL: http://localhost:8080 |
1 2 3 4 5 6 7 8 |
curl localhost:8080 \ -H 'content-type: text/plain;charset=UTF-8' \ -d 'test http' //OK //Received HTTP request //test http |
デプロイ(HTTP関数)
gcloud functions deploy
で --trigger-http
を指定してデプロイします。regionやruntimeはプロジェクトの実態に合わせる必要があると思います。
デプロイ後は Cloud Run 関数 のURLからテストできます。
1 2 3 4 5 6 7 8 |
gcloud functions deploy testhttp \ --gen2 \ --region=us-central1 \ --runtime=nodejs22 \ --source=. \ --entry-point=http \ --trigger-http \ --project={ YOUR_PROJECT } |
1 2 3 4 5 6 7 8 |
curl https://us-central1-{ YOUR_PROJECT }.cloudfunctions.net/testhttp \ -H 'content-type: text/plain;charset=UTF-8' \ -d 'test http' //OK //Received HTTP request //test http |
Cloud Storage イベント
プロジェクトの実態に合わせてオブジェクトの
- ファイナライズ(新規作成、上書きによる世代の更新)
- 削除
- アーカイブ(バージョンが現行でなくなった時)
- メタデータの更新
をトリガーとして、オブジェクトデータを渡して実行できます。(Cloud Run第二世代はEventarc 経由でのイベント)
こちらも様々な用途ありますが、ログファイルを Cloud Logging → ログルーター → ストレージに集めて実行できたりします。
1 2 3 4 |
ff.cloudEvent('storage', ce => { console.log('Received storage_finalized event'); console.log(ce.data as StorageObjectData); }); |
ローカルでのテスト(Cloud Storage イベント)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
npm run start --function=storage > prestart > npm run build > build > tsc > start > functions-framework --target=$npm_config_function Serving function... Function: storage Signature type: cloudevent URL: http://localhost:8080/ |
CloudEvents形式の場合はヘッダーを合わせる必要があります。以下はマスクしたcurlのサンプルです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
curl localhost:8080 \ -X POST \ -H "Content-Type: application/json" \ -H "ce-id: 123451234512345" \ -H "ce-specversion: 1.0" \ -H "ce-time: 2024-07-15T10:11:10.789Z" \ -H "ce-type: google.cloud.storage.object.v1.finalized" \ -H "ce-source: //storage.googleapis.com/projects/_/buckets/my-bucket" \ -H "ce-subject: objects/my-file.txt" \ -d '{ "kind": "storage#object", "id": "...", "selfLink": "...", "name": "test.json", "bucket": "...", "generation": "1", "metageneration": "1", "contentType": "application/json", "timeCreated": "2024-11-29T17:17:57.003Z", "updated": "2024-11-29T17:17:57.003Z", "storageClass": "STANDARD", "timeStorageClassUpdated": "2024-11-29T17:17:57.003Z", "size": "...", "md5Hash": "...", "mediaLink": "...", "contentLanguage": "en", "crc32c": "...", "etag": "..." }' |
デプロイ(Cloud Storage イベント)
--trigger-resource
でストレージを指定しています。以下でデプロイするとEventarcのトリガーが自動で作成され、オブジェクトの作成更新で実行できます。適当なローカルのファイルをgsutil cp
して確認するのが手っ取り早いかと思います。
1 2 3 4 5 6 7 8 9 |
gcloud functions deploy teststorage \ --gen2 \ --region=us-central1 \ --runtime=nodejs22 \ --source=. \ --entry-point=storage \ --trigger-resource={ YOUR_BACKET } \ --trigger-event=google.cloud.storage.object.v1.finalized \ --project={ YOUR_PROJECT } |
Pub/Sub
Pub/Subメッセージに応答して関数を実行することができます。
プロジェクトでのPub/Sub利用状況に合わせた実装ももちろんできますし、Monitoringアラートの通知チャンネルや、ログルーターの送信先も選択できるので既存プロジェクトからの拡張も容易です。
1 2 3 4 |
ff.cloudEvent('pubsub', ce => { console.log('Received message_published event'); console.log(ce.data as MessagePublishedData); }); |
ローカルでのテスト(Pub/Sub)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
npm run start --function=pubsub > prestart > npm run build > build > tsc > start > functions-framework --target=$npm_config_function Serving function... Function: pubsub Signature type: cloudevent URL: http://localhost:8080/ |
ストレージ同様ヘッダーを合わせてリクエストします。またmessageのdataは通知元によってはJSONだったりするのでbase64でエンコードされています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
curl localhost:8080 \ -X POST \ -H "Content-Type: application/json" \ -H "ce-id: 123451234512345" \ -H "ce-specversion: 1.0" \ -H "ce-time: 2024-11-29T17:17:57.003Z" \ -H "ce-type: google.cloud.pubsub.topic.v1.messagePublished" \ -H "ce-source: //pubsub.googleapis.com/projects/gmo-am-ssp-stg/topics/{ TOPIC }" \ -d '{ "message": { "data": "dGVzdHRlc3Q=", "messageId": 123451234512345, "message_id": 123451234512345, "publishTime": "2024-11-29T17:17:57.003Z", "publish_time": "2024-11-29T17:17:57.003Z" } }' |
デプロイ(Pub/Sub)
Pub/Subトピックスを事前に作成する必要があります。
こちらもEventarcのトリガーが自動で作成されます。
1 2 3 4 5 6 7 8 9 10 |
gcloud pubsub topics create testtopic gcloud functions deploy testpubsub \ --gen2 \ --runtime=nodejs22 \ --region=us-central1 \ --source=. \ --entry-point=pubsub \ --trigger-topic=testtopic \ --project={ YOUR_PROJECT } |
デプロイ後は任意のメッセージpublishして確認できます。
gcloud pubsub topics publish testtopic --message="hello"
終わりに
Cloud Run 関数でのFunctions Frameworkについてまとめました。
Curlサンプルなどは意外と用意するのめんどくさいのでどこかで役立てばと思います。
様々なCloudEventに対してCloud Run 関数を容易に実行できることで今後も業務改善に繋げていきたいです。