はじめに
GitHub Copilot Extensions というものが最近パブリックベータになったようで、コード開発支援ツールである GitHub Copilot の VSCode 拡張から、外部サービスとシームレスに連携できるような機能が利用可能となった。自分も Copilot のライトユーザーとして、何か試してみたいと思い、GitHub Marketplace で利用可能な拡張を物色していたところ、Sentry Copilot Extension を見つけた。「今稼働している Firebase Cloud Functions を Sentry で監視するようにしてエラー発生させてそれを VSCode から可視化できたら面白いかも」と思ったものの、本拡張が Firebase Cloud Functions に対応していないらしく、はたまた困ってしまったが、Google Cloud Run functions はサポートしているようで、いっちょ変えたれ、と思って本件に至る。
ユースケース
Pubsub からメッセージを受け取って発動する Functions を Firebase Cloud Functions(第 1 世代) から Google Cloud Run functions(第 2 世代) に書き換える。
前提
環境
node -v
# v18.18.0
gcloud -v
#Google Cloud SDK 494.0.0
#bq 2.1.8
#core 2024.09.20
#gcloud-crc32c 1.0.0
#gsutil 5.30
条件
- Pub/Sub トピックはあらかじめ作成されているとする(
my-topic
)
やったこと
環境準備
-
gcloud
をインストール する。 - gcloud の環境を初期化する。
gcloud init
詳しくは本家を参照
アプリ改修
functions のメイン?コンポーネントを変更する
- import * as functions from 'firebase-functions';
+ import * as functions from '@google-cloud/functions-framework';
もちろん、その前に install は必要だ
npm i --save @google-cloud/functions-framework
次に、エントリーポイント関数を書き換える。
Firebase Cloud Functions(第 1 世代) の場合、以下のようなコードであった:
import * as functions from 'firebase-functions';
exports.myFunction = functions
.runWith({ timeoutSeconds: 540, failurePolicy: true, memory: '1GB' })
.region('asia-northeast1')
.pubsub.topic("my-topic")
.onPublish(async (message, context) => {
// decode message
const decoded = Buffer.from(message.data, 'base64');
...
})
特徴として、後段の関数デプロイ時の設定値をプログラム内に書き込むことである。
タイムアウト (timeoutSeconds
)、関数に割り当てるメモリ (memory
)、リージョン (region()
)、対象 pubsub トピック (pubsub.topic()
) などを指定できる。
これを、新しくしたのがこちら:
import * as functions from '@google-cloud/functions-framework';
interface PubSubData {
subscription: string;
message: {
messageId: string;
publishTime: string;
data: string;
attributes?: { [key: string]: string };
};
}
functions
.cloudEvent<PubSubData>('myFunction', async (cloudEvent) => {
// access encoded event data
const data = cloudEvent.data?.message.data;
// decode event data
const decoded = Buffer.from(data, 'base64');
// ...
})
Firebase の場合のような指定項目はなく、シンプルになった。
が、これは後続のデプロイコマンドで指定することになる。
参考:
deploy
- Firebase Cloud Functions(第 1 世代) の場合
firebase deploy --only functions
- Google Cloud Run functions(第 2 世代) の場合
gcloud functions deploy <FUNCTION_NAME> --runtime <RUNTIME> --trigger-topic=<TOPIC_NAME> --region=<REGION> --memory=<memory> --timeout=<timeout_in_second>
#e.g.
# gcloud functions deploy myFunction --runtime nodejs18 --trigger-topic=my-topic --region=asia-northeast1 --memory=1GB --timeout=540
エントリーポイント関数が簡潔だった分、そっくりそのままデプロイコマンドに跳ね返ってきた形となる。
参考:
遭遇したエラー
secret manager 周りでエラー
本アプリでは、Secret Manager を 利用しており、API 経由で情報を取得してきているのだが、API アクセス時に以下のようなエラーが発生した:
Error: 7 PERMISSION_DENIED: Permission 'secretmanager.versions.access' denied for resource ...
対応は、こちら を参照した。
やるべきことは、以下のデプロイコマンド実行時のメッセージに対し:
gcloud functions deploy slackNotification-g2 --runtime nodejs18 --trigger-topic=notification-pubsub-topic2 --region=asia-northeast1 --memory=1GB
Preparing function...done. ...
service: projects/xxxxx/locations/asia-northeast1/services/myFunction
serviceAccountEmail: xxxxxxxxxxx@developer.gserviceaccount.com
...
serviceAccountEmail
のアカウント xxxxxxxxxxx@developer.gserviceaccount.com
のサービスアカウントに対して、IAM ページでロール(Secret Manager Secret Accessor
)を追加する。
- IAM と管理 > IAM に遷移し、編集アイコンクリック
- 「別のロールを追加」クリック
-
Secret Manager Secret Accessor
のロールを付与
Google Sheets API でエラー
本アプリでは、Google Sheets への書き込みを API 経由で行っており、API コール時に以下のようなエラーが発生した:
The caller does not have permission
対応は、こちら を参照した。
書き込みたい Sheets ページで、共有 クリック > サービスアカウントを追加する必要がある。このサービスアカウントは前述の Secret Manager Secret Accessor ロールを追加したアカウントと同じものである。
- 共有クリック

- サービスアカウントを追加

Secret Manager おより Google Sheets での両エラーは、思い返してみると最初本アプリを Firebase で作った時のも同じエラーが出た記憶がある。つまり、Google Cloud Run functions だから起こったのではなく、サービスアカウントが変更になったから、その分同じ権限を付与する必要があったということと考えられる。
移行完了
サービスアカウントのニアミスさえ気をつければ、移行作業は小一時間で終わりそうなものであった。
一応、両方の Functions を触ってみての感想としては、Firebase の方が好みであることもわかった。
理由は、デプロイ設定値をプログラム中に宣言的に記述できるからである。
デプロイにまつわる設定値の管理上、ソースコードに入れられた方が取り扱いがしやすいだろう(デプロイコマンドをシェルスクリプトに書いて、それを管理するという方法もあるが、取り回しが一段下がる気がする)
こうして、当初の目的を達成すべくようやくスタート地点につけた。
Sentry Copilot Extension については引き続き作業を継続し、成果が出たら共有したい。