Edited at

Cloud Functions GoでFirestoreの定期バックアップ

Cloud Functions Goを使ってみるの第二弾です。(前回はこちら)


tl;dr


  • GoでFirestoreをバックアップするにはgoogle.golang.org/api/firestore/v1を使う必要がある

  • Cloud FunctionsでもApplication Default Credentialsが使えるので簡単にAPIを呼ぶことができる


まえがき

去年(2018年)の8月のアナウンスでFirestoreのimport/exportができるようになりました。

The Firebase Blog: More Cloud Firestore Improvements!

gcloudコマンドを使うか、以下のREST APIでExportできます。

Method: projects.databases.exportDocuments  |  Cloud Firestore  |  Google Cloud


Cloud Scheduler経由でFirestoreを定期バックアップ

詳しくは以下のGincoさんのブログで紹介されています。

Cloud Scheduler で Firestore を定期的にバックアップする - Ginco Tech Blog

Cloud Scheduler経由でPub/SubトピックをPublishし、SubscribeしたCloud Functions内で前述のREST APIを呼んでいます。

ExportするCloud Functionsのサンプルは大概Node.jsのものが多いので、今回Goのサンプルを作ってみました。

コードはGitHubにもあげてあります。

go-cloud-functions-examples/backup-firestore at master · iwata/go-cloud-functions-examples


Cloud Functions

REST APIなので素朴にhttp.Clientとかで実装してもよいですが、今回はGoogleのGoライブラリを使いました。

Export APIに対応しているのはgoogle.golang.org/api/firestore/v1になります。


This package is DEPRECATED. Use package cloud.google.com/go/firestore instead.


と書かれていますが、そのcloud.google.com/go/firestoreにはいまのところExport用のメソッドが存在しないため、google.golang.org/api/firestore/v1を使います。

package function

import (
"context"
"fmt"
"os"

"github.com/pkg/errors"
"google.golang.org/api/firestore/v1"
"google.golang.org/api/option"
)

var projectID string

// PubSubMessage is a body data from Pub/Sub payload
type PubSubMessage struct {
Data string `json:"data"`
}

func init() {
projectID = os.Getenv("GCP_PROJECT")
}

// BackupFirestore is triggered by Cloud Functions
func BackupFirestore(ctx context.Context, m PubSubMessage) error {
svc, err := firestore.NewService(ctx, option.WithScopes(firestore.DatastoreScope, firestore.CloudPlatformScope))
if err != nil {
return errors.Wrap(err, "Failed to create Firestore service")
}

req := &firestore.GoogleFirestoreAdminV1ExportDocumentsRequest{
OutputUriPrefix: fmt.Sprintf("gs://%s-backup-firestore", projectID),
}
_, err = firestore.NewProjectsDatabasesService(svc).ExportDocuments(
fmt.Sprintf("projects/%s/databases/(default)", projectID), req,
).Context(ctx).Do()
if err != nil {
return errors.Wrap(err, "Failed to export Firestore")
}

fmt.Println("Backup Successfully")

return nil
}

OAuthクライアントにはgoogle.DefaultClientを使います。

これを使うことでCloud Functionsを起動しているService AccountのApplication Default Credentialsで認証可能となり、アクセストークンの取得を省略できます。(便利!)


google.golang.org/api v0.3.0からgoogle.DefaultClient不要になりました。(さらに便利!)

詳細は以下のドキュメントを参照してください。

https://godoc.org/google.golang.org/api/firestore/v1#hdr-Creating_a_client

Cloud Functionsは特に指定なしだとGAEのデフォルトService Accountを使用しますので、特に設定していない場合はそのサービスアカウントの以下のRoleを付与します。


  • Cloud Datastore Import Export Admin

  • Storage Admin

OutputUriPrefixには保存先のCloud Storageを指定します。

こちらは任意で書き換えてください。

認証周りを気にしなくてよいのですこぶるシンプルに書けますね!