14
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Cloud Functions を使って Firestore の定期バックアップ

Last updated at Posted at 2019-02-27

Motivation

Firestore のバックアップを Cloud Scheduler と Cloud Functions で完全サーバーレス的に実行したい。 もちろん、既に先人達が実装済み。

https://tech.ginco.io/post/cloud_scheduler/
https://qiita.com/Kasanomo/items/566191f0c106b4669f22

が、サービスアカウントの秘密鍵を使うようなサンプルになっている。
折角 Cloud Functions 自体が既に権限を持っているのだから、別口で秘密鍵をアップロードする事なくできないだろうかと思って調べてみた。

下準備

コード書く前に環境設定

GCSバケット

まずバックアップ先であるバケットを作成する。 ここでは gs://foo とする。 不特定多数からアクセスされる訳じゃないので Regional でいいだろう。 注意すべきなのは、Firebase のプロジェクト作成時に選択したリージョンと同じにしておくこと。 じゃないと、あとでこける。

IAM

Firebase で Cloud Functions 作った場合のデフォルト権限である <PROJECT_NAME>@appspot.gserviceaccount.com は、Project Editor にもかかわらず、実は十分な権限がついてない。 ということで、Cloud Datastore Import Export Admin のロールを付与する。

Cloud Functions で PubSub トリガーを作る

PubSubの backup-firestore トピックへのメッセージのトリガーにする。

実際のバックアップは googleapis パッケージを使って REST API 呼び出し。 ちなみに、なんだかクセの強いライブラリで、使い方、コード追わないとよくわからんかった。

exports.onFirestoreBackup = functions.pubsub
  .topic('backup-firestore')
  .onPublish(async message => {
    const { google } = require('googleapis')
    const { GCP_PROJECT } = process.env

    const auth = await google.auth.getClient({
      scopes: [
        'https://www.googleapis.com/auth/datastore',
        'https://www.googleapis.com/auth/cloud-platform',
        'https://www.googleapis.com/auth/compute'
      ]
    })

    await google.firestore('v1').projects.databases.exportDocuments({
      name: `projects/${GCP_PROJECT}/databases/${GCP_PROJECT}`,
      requestBody: { outputUriPrefix: 'gs://foo' },
      auth
    })
  })

これで、gs://foo 以下に、2019-02-26T10:10:35_84272/ みたいなディレクトリがバックアップの度に生成されるようになる。 ちなみに outputUriPrefix にバケットを指定する際にバケット名の先(gs://foo/bar)まで指定すると、タイムスタンプのディレクトリが作られず、そのディレクトリ直下にファイルが置かれる仕様っぽい。

謎に https://www.googleapis.com/auth/compute を追加してあげる必要があった。なぜかはよくわからない。きっと内部の話なんだろう。

Cloud Scheduler

GCPコンソールからさらっと設定。 任意のタイミングで backup-firestore トピックへメッセージを投げる。 メッセージの中身は読まないのでなんでもいい。 空メッセージは送れなかったような気がしなくもないので {} とかにした。本当に空でもいいのかもしれない。

設定できたら Run Now で手動実行。

結果

普通にできた。Cloud Functions のログを確認。

リストアするには CLI から
gcloud alpha firestore import gs://[BUCKET_NAME]/[EXPORT_PREFIX]/

これで、また一つ秘密鍵の管理が減った。嬉しい。

追記

Cloud Functions にスケジュール実行機能が追加されてるようだ。 ↑の PubSub / Cloud Scheduler を使う必要がなくなって、より簡単に実装できるようになっている。
https://firebase.google.com/docs/functions/schedule-functions?hl=ja

14
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?