2025.01.14

Google Cloud のCloud Functions, Firestore, PubSub 開発Tips

こんにちは。次世代システム研究室のT.M です。

はじめに

Google Cloud のCloud FunctionsFirestorePubSub を利用すると手軽にサーバーレスのアプリケーションを開発することができます。ただ、公式ドキュメントに情報がなかったり、Firebase の情報が検索に引っかかったり、技術ブログ等で情報が網羅されていなかったりと、開発の際に困ったことがありました。そこで、本稿では、これらのサービスを使ってローカル環境で開発をして、クラウド環境にデプロイをする方法を説明します。

Cloud Functions

Functions Framework を使って開発します。実行のトリガーとして、http とイベントの2種類があります。

Httpトリガー

ソースコード

ソースコードは以下のようになります。functions.http 関数で定義します。

const functions = require('@google-cloud/functions-framework');

functions.http('testHttp', (req, res) => {
  res.send('success');
});

ローカル実行

この関数を実行するコマンドは以下になります。

functions-framework --target=testHttp

ちなみに、ソースコードがカレントディレクトリのindex.js でない場合、source オプションでファイルを指定することができます。

functions-framework --target=testHttp --source=./src/server.js

クラウドデプロイ

デプロイコマンドは以下になります。

gcloud functions deploy server --gen2 --region=asia-northeast1 --runtime=nodejs20 --entry-point=server --trigger-http

イベントトリガー

ソースコード

ソースコードは以下になります。functions.cloudEvent 関数で定義します。

const functions = require('@google-cloud/functions-framework');

functions.cloudEvent('testEvent', cloudEvent => {
  console.log('testEvent fired);
});

ローカル実行

この関数を実行するコマンドは以下になります。–signature-type オプションによりイベントトリガーの関数であることを指定します。

functions-framework --target=testEvent --port=18080 --signature-type=event

クラウドデプロイ

デプロイコマンドは以下になります。–trigger-topic オプションによりこのイベントを発火するPubSub トピックを指定します。

gcloud functions deploy testEvent --gen2 --region=asia-northeast1 --runtime=nodejs20 --entry-point=testEvent --trigger-topic=testTopic

環境変数

ローカル実行

set_env.js というスクリプトを用意します。ローカル用の環境変数は、.env.local.yaml に記述されているものとします。

set_env.js では、.env.local.yaml ファイルを読み出し、key=value の形で標準出力します。

import fs from 'fs';

fs.readFile('.env.local.yaml', 'utf8', (err, data) => {
    if (err) {
        console.error('ファイルの読み込みに失敗しました:', err);
        return;
    }

    const lines = data.split('\n').map(line => line.trim())
        .filter(line => line.length > 0 && !line.startsWith('#'));

    const keyValuePairs = lines.map(line => {
        const [key, value] = line.split(': ').map(part => part.trim());
        return key + '=' + value.replace('(', '\\(').replace(')', '\\)');
    });

    const output = keyValuePairs.join(' ');
    console.log(output);
});

実行コマンドは以下になります。set_env.js により展開された環境変数をランタイム変数として実行します。

bash -c \"$(node set_env.js) functions-framework --target=server

クラウドデプロイ

–env-vars-file オプションで環境変数のファイルを指定することで、ランタイム変数として設定することができます。

gcloud functions deploy server --gen2 --region=asia-northeast1 --runtime=nodejs20 --entry-point=server --env-vars-file=.env.dev.yaml --trigger-http

シークレット

ローカル実行

環境変数と同じように.env.local.yaml に定義し、ランタイム変数として実行します。

クラウドデプロイ

Secret Manager にシークレット情報を登録します。set-secrets オプションでSecret Manager のシークレット情報をランタイム変数に設定することができます。以下は、Secret Manager に登録されたTEST_SECRET というシークレットをprocess.env.TEST_SECRET で呼び出すことができるように設定したデプロイコマンドです。複数のシークレットを設定したい場合は、カンマ区切りで並べて記述します。

gcloud functions deploy server --gen2 --region=asia-northeast1 --runtime=nodejs20 --entry-point=server --set-secrets='TEST_SECRET=TEST_SECRET:latest' --trigger-http

Firestore

ソースコード

以下のソースコードで書き込むことができる。

import Firestore from '@google-cloud/firestore';

const db = new Firestore({
  projectId: 'YOUR_PROJECT_ID'
});

const res = await db.collection(testCollection).doc(testId).set(testData);

読み出すコードは以下の通りです。

const doc = await db.collection(testCollection).doc(testId).get();
if (doc.exists) {
    const data = doc.data()
}

ローカル環境

Firestore はエミュレーターがあるので、それを利用します。エミュレーターの起動コマンドは以下になります。port オプションでポート番号を指定することができます。ソースコードの環境変数にFIRESTORE_EMULATOR_HOST=localhost:8045 を定義することでエミュレーターに接続することができます。

gcloud emulators firestore start --port=8045

PubSub

ローカル実行

PubSub はエミュレーターがあるので、それを利用します。エミュレーターの起動コマンドは以下になります。ソースコードの環境変数にPUBSUB_EMULATOR_HOST=localhost:8043 を定義することでエミュレーターに接続することができます。

gcloud beta emulators pubsub start --host-port=localhost:8043 --project=test-project

トピックとサブスクリプションを設定します。createTopic でトピックを作成し、createSubscription でサブスクリプションを作成します。pushEndpoint には、イベントトリガーのCloud Functions のURL を設定します。

import { PubSub } from '@google-cloud/pubsub';

const pubSubClient = new PubSub();

const [topic] = await pubSubClient.createTopic('testTopic');
await pubSubClient.createSubscription(topic, 'testSubscription', { pushEndpoint: `http://localhost:18080/projects/test-project/topics/testTopic` });

クラウドデプロイ

コンソールでトピックを作成します。作成したトピックをtarget-topic オプションに指定して、Cloud Functions をデプロイします。

さいごに

公式ドキュメントに説明のない、ローカルでの環境変数やシークレット、PubSub の使い方を含めたGoogle Cloud のCloud FunctionsとFirestore、PubSub のローカル環境での実行方法やクラウド環境でのデプロイ方法を説明しました。

 

次世代システム研究室では、グループ全体のインテグレーションを支援してくれるアーキテクトを募集しています。インフラ設計、構築経験者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ募集職種一覧からご応募をお願いします。

皆さんのご応募をお待ちしています。

  • Twitter
  • Facebook
  • はてなブックマークに追加

グループ研究開発本部の最新情報をTwitterで配信中です。ぜひフォローください。

 
  • AI研究開発室
  • 大阪研究開発グループ

関連記事