💬

publishされたファイルをCloud Storageに保存する

2024/03/25に公開

やりたいこと

Cloud pub/subでpublishされたメッセージデータをCloud Storageに保存します。
また、以下の条件のもと実現する方法を考えます。

  • publishされるメッセージはJSON形式
  • JSONデータを元にCloud Storageに保存するファイル名を生成する
  • pub/subトピックが外部組織(別プロジェクト)に存在している

調べた限りだと以下のような方法が考えられるようです。

このうち、前述した要件を満たしそうなのがCloud FunctionsのHTTPトリガーだったため、HTTPトリガーを使ってCloud Storageへファイルを保存することにします。

他を断念した理由

というわけで、Cloud pub/subとCloud FunctionsのHTTPトリガーを利用してCloud Storageへデータを保存する方法を説明していきます。

やっていく

一つずつ必要なリソースを作成していきます。

  1. Cloud Storage
  2. Cloud Functions
  3. Cloud pub/sub

の順で行います。

Cloud Storageを作成する

Cloud Storageは、以下のコマンドを実行します。

$ gcloud storage buckets create gs://test-http-trigger-bucket --location=asia-northeast1

Cloud Functionsを作成する

次に、HTTPトリガーで実行するCloud Functionsを作成します。
後に作成するサブスクリプションで設定されたURLを利用します。
まず、以下のファイルを作成します。

今回はJavaScriptで関数を作成しますが、CloudFunctionsの実行環境はいくつか用意されています。gcloud functions runtimes listコマンドなどを使用してみてください。

index.js
const functions = require('@google-cloud/functions-framework');
const dayjs = require('dayjs');
const { Storage } = require("@google-cloud/storage");

functions.http('myHttpFunction', (req, res) => {
  const base64data = req.body.message.data;

  if (!base64data) {
    console.log("failed recieving data.");
    res.send('error')
  }

  const currentTime = dayjs().format("YYYY-MM-DDTHH:mm:ss");

  const jsonString = Buffer.from(base64data, 'base64');
  const json = JSON.parse(jsonString);
  const fileName = `${currentTime}-${json.title}.json`
  console.log(fileName);

  const storage = new Storage();
  // 作成したCloud Storageの名前を指定する
  const myBucket = storage.bucket(<storage-name>);
  const file = myBucket.file(fileName);
  const contents = jsonString;
  file.save(contents).then(function() {});

  res.send('OK');
});

package.json
{
  "dependencies": {
    "@google-cloud/functions-framework": "^3.0.0",
    "@google-cloud/storage": "7.7.0",
    "dayjs": "1.11.10"
  }
}

作成したファイルをデプロイします。

$ gcloud functions deploy http-trigger \
--entry-point=myHttpFunction \
--region=asia-northeast1 \
--runtime=nodejs20 \
--trigger-http \
--gen2

作成されたことを確認します。

$ gcloud functions list
NAME          STATE   TRIGGER       REGION           ENVIRONMENT
http-trigger  ACTIVE  HTTP Trigger  asia-northeast1  2nd gen

サブスクリプションを作成する

gcloud pubsub subscriptions createコマンドを使用して任意のトピックに紐づくサブスクリプションを作成します。この時、サービスアカウントにデフォルトコンピュートアカウントを指定することで、認証されるようにします。
また、push-endpointには先に作成したCloud Functionsのエンドポイントを指定します。

$ gcloud pubsub subscriptions create my-subscription \
--topic=my-topic \
--topic-project=cloud-test-415104 \
--push-endpoint=https://asia-northeast1-cloud-test-415104.cloudfunctions.net/http-trigger \
--push-auth-service-account=9999999999-compute@developer.gserviceaccount.com

パブリッシュしてCloud Storageに保存されることを確認する

上記までで必要なリソースの設定が完了したので、メッセージをパブリッシュしてCloud Storageへ保存されるか試してみます。

$ gcloud pubsub topics publish my-topic --message='{"title": "helloworld"}'

Storageの中にファイルが作成されているかを確認します。

$ gcloud storage ls --recursive "gs://test-http-trigger-bucket/**"
gs://test-http-trigger-bucket/2024-02-27T01:42:06-helloworld.json
中身
{"title":"helloworld"}

大丈夫そうです。

参考

https://cloud.google.com/pubsub/docs/push?hl=ja#receive_push
https://cloud.google.com/functions/docs/concepts/version-comparison?hl=ja

GitHubで編集を提案
Welmo Engineer Blog

Discussion