Cloud Firestoreのバックアップ・リストア

Photo by imgix on Unsplash

Cloud Firestoreにバックアップの仕組みが無いことは以前からの課題でしたが、ようやく gcloud コマンドとしてimport・exportが提供されました🎉
(Cloud Next 2018 でもアナウンスがあったそうですが、以下の記事で知りました。)

ちなみに、これまでは次のOSSを利用するのが定番だったと思います。

Export・Importのやり方は次のドキュメントによくまとまっていますが、本記事ではそれらを実際に使いながら解説していきます。


前提条件

GCPへの課金を有効化する必要があります。FirebaseはBlaze planにする必要が出てきます。

また、いくつかの権限も必要です。自身がオーナーのプロジェクトで自ら実行する場合は特に気にせずで大丈夫ですが、そうでない場合、以下の権限割り当てを済ませておく必要があります。

gcloudコマンド実行環境の用意

以下の2通りがありますが、コマンドライン操作だけで済む後者のやり方がおすすめです。

すでにインストール済みの手元のSDKが古くて後述の gcloud alpha firestore コマンドがない場合は以下のコマンドで更新が必要です。

gcloud components update

プロジェクト設定

次のコマンドなどで、gcloudコマンドに設定されているプロジェクトが確認できます。

gcloud info | grep project

操作対象のプロジェクトと異なっている場合は、次のコマンドで切り替えておきます。特にインポート先のプロジェクトを間違える大事故を起こさないように注意です。

gcloud config set project [PROJECT_ID]

Google Cloud StorageのBucket用意

Google Cloud Storage にエクスポート先のBucketをあらかじめ用意しておく必要があります(既存の適当なBucketから選ぶことも可能ですが隔離した方が扱いやすいはずです)。

名前は、Realtime Databaseのバックアップは [PROJECT_ID]-backups というBucketでなされるので[PROJECT_ID]-backups-firestore あたりの名前が良いかなと思って、僕はそうしています。

リージョンは、以下のどちらかですが、前者の必要性は薄く後者の方が安いので後者を選びました。

  • Multi-Regional
  • Regional (us-central1などFirestoreのリージョンと揃える)
Google Cloud StorageのBucket作成

Firestoreドキュメントのエクスポート

次のコマンドを実行するだけです。 [BUCKET_NAME] はもちろん上で用意したものを指定します。

gcloud alpha firestore export gs://[BUCKET_NAME]

成功すると、次のようなログを吐きつつ処理が終了します。

cloud alpha firestore export gs://[PROJECT_ID]-backups-firestore
Waiting for [projects/[PROJECT_ID]/databases/(default)/operations/ASA1MTcwOTI5NDQJGnRsdWFmZWQHEmxhcnRuZWNzdS1
zYm9qLW5pbWRhFAosEg] to finish...done.
metadata:
'@type': type.googleapis.com/google.firestore.admin.v1beta1.ExportDocumentsMetadata
operationState: PROCESSING
outputUriPrefix: gs://[PROJECT_ID]-backups-firestore/2018-08-09T03:27:33_84792
startTime: '2018-08-09T03:27:33.459300Z'
name: projects/[PROJECT_ID]/databases/(default)/operations/ASA1MTcwOTI5NDQJGnRsdWFmZWQHEmxhcnRuZWNzdS1zYm9qLW5pbWRhFAosEg

--collection-ids フラグを指定して、特定のコレクションだけのエクスポートも可能です。

gcloud alpha firestore export gs://[BUCKET_NAME] --collection-ids='[COLLECTION_ID_1]','[COLLECTION_ID_2]'

ただし、 --collection-ids フラグで指定したコレクションのサブコレクションは対象外なので、サブコレクションも含めたい場合はそれらも明示的に指定する必要があります。--collection-ids フラグ無指定なら、サブコレクション含めてすべてエクスポートされます。バックアップ目的なら通常無指定が良いはずです。--collection-ids フラグは基本的にはバックアップ目的ではなく別プロジェクトにデータを移して検証・データ分析などするためのものであると認識しています。

Realtime Databaseの記事ですが、バックアップは次の用途などで有用と書かれています。

  • オフライン スクリプティング
  • 履歴データ分析
  • 破損データやデータロストからのリカバリ

本記事では、需要の高そうなバックアップ・リストア(上の箇条書きの3点目に相当)に敢えて焦点を当てて説明しています。

実行結果の確認

上記コマンドではエクスポートの開始が成功しただけで、処理はバックグラウンドで実行されています。

エクスポートのログの最後の行の [OPERATION_NAME] を用いて、次のコマンドで確認することができます。出力の1行目に done: true と記載されていれば完了したということです。

gcloud alpha firestore operations describe ASA1MTcwOTI5NDQJGnRsdWFmZWQHEmxhcnRuZWNzdS1zYm9qLW5pbWRhFAosEg

最近の実行結果を全件確認したい場合は次のコマンドです。

gcloud alpha firestore operations list

削除・キャンセルもできますが、キャンセルはロールバックではなく途中の中途半端な状態で終わるだけなので、やらかした時のキャンセル用途としてはあまり使えないと思います(中途半端でも良いからとにかくキャンセルしたいというケースはあるかもしれません)。

gcloud alpha firestore operations delete [OPERATION_NAME]
gcloud alpha firestore operations cancel [OPERATION_NAME]

Google Cloud StorageのBucketを覗くと、次のようにパスで区切られたものが生成されているのを確認できます。中身はおそらく独自フォーマットです。とりあえずインポート作業に必要になってくるのは、 2018-08-09T01:58:11_44344 などの名前のみです。

Firestoreドキュメントのインポート

次のコマンドでインポートができます。[EXPORT_PREFIX]部分に上の例だと2018-08-09T01:58:11_44344 などを指定します。

gcloud alpha firestore import gs://[BUCKET_NAME]/[EXPORT_PREFIX]/

成功すると、次のようなログが吐かれます。

cloud alpha firestore import gs://[PROJECT_ID]-backups-firestore/2018-08-09T01:58:11_44344/
Waiting for [projects/[PROJECT_ID]/databases/(default)/operations/AiA4NDcwNjE1NDQJGnRsdWFmZWQHEmxhcnRuZWNzdS1zYm9qLW5pbWRhFAosEg] to finish...done.
metadata:
'@type': type.googleapis.com/google.firestore.admin.v1beta1.ImportDocumentsMetadata
inputUriPrefix: gs://[PROJECT_ID]-backups-firestore/2018-08-09T01:58:11_44344
operationState: PROCESSING
startTime: '2018-08-09T04:07:22.151940Z'
name: projects/[PROJECT_ID]/databases/(default)/operations/AiA4NDcwNjE1NDQJGnRsdWFmZWQHEmxhcnRuZWNzdS1zYm9qLW5pbWRhFAosEg

これもエクスポートと同様に実際の処理はバックグラウンドで行われていて、以下で進捗・最終結果を確認できます。

gcloud alpha firestore operations describe AiA4NDcwNjE1NDQJGnRsdWFmZWQHEmxhcnRuZWNzdS1zYm9qLW5pbWRhFAosEg

出力の1行目に done: true と記載されていれば、Firestore上でもデータがインポートされていることが確認できるはずです。


以上がFirestoreのエクスポート・インポートの流れとなります。実際にやる場合は、次のような流れになると思います。

  1. 本番環境ではなく別途開発環境など用意してそこでエクスポート・インポートを試す
  2. うまくいったら本番環境でもエクスポート
  3. 何かしらの事故で本番環境のFirestoreのデータをエクスポート時に戻したい事態になったらインポート

あるいは、バックアップ・リストア用途以外にも、別環境のデータを移動してテスト環境で検証したい時にも有用かと思います。

バックアップ処理の定期実行

以下の別記事で構築手順例を説明しています。

初めは gcloud コマンドを実行可能な環境を用意するアプローチを取ってしまいましたが、

あとからREST APIの存在に気付いて、こちらのやり方の方がずっと簡単でおすすめです。

また、Realtime DatabaseではFirebase Webコンソール上の操作で簡単に日次バックアップが取れるようになっていて、Firestoreにも今後同様の機能が搭載されると予想しています。逆に言うと、それまでの間はエクスポートコマンドの定期実行の仕組みを自前で整えるしかないですね。

Realtime Database に提供されている自動バックアップ機能