🐙

Firestoreの自動バックアップを試してみた。

2023/03/26に公開

どうやらFirestoreを自動でバックアップできるらしいので試してみました。
Cloud functionsを使ってバックアップスケジュールと、バックアップ処理を登録するようです。

バケットを作成

1.GCPにアクセスして「Cloud Storage」から「バケット」を選択します。
2.「作成」をクリックして作成画面へ行き、各設定を入力して「作成」をクリックします。

項目 設定内容
バケット名 なんでもOK。分かりやすいものにする。
データの保存場所 RegionでFirestoreと同じものを選択。
ストレージクラス 用途は日次バックアップなので、デフォルトのStandardで試してみる。
アクセス制御 当然公開アクセスは禁止で、細かい設定は難しそうなので「均一」を選択。
データ保護 公式の説明を読んでも理解できない。多分、取得したバックアップの世代管理だと思う。いったん「なし」を選択。

3.「公開アクセスの防止」というダイアログが開くので、そのまま「確認」をクリック。

ここまでで、バックアップ用のバケットがGCP上に作成されます。

バックアップ作成用のFunctionsを作成

Cloud functionsを利用してスケジューリングされたバックアップ処理を登録します。
プロジェクトの/functions/index.jsに以下のコードを記述してください。
コードは公式のものをそのまま転用していますが、BUCKET_NAMEを自身のプロジェクトに合わせて変更するようにしてください。

functions/index.js
const functions = require('firebase-functions');
const firestore = require('@google-cloud/firestore');
const client = new firestore.v1.FirestoreAdminClient();

// Replace BUCKET_NAME
const bucket = 'gs://BUCKET_NAME';

/**
 * 公式から引用したfirestoreのバックアップ用function。
 * .scheduleの引数でスケジューリングの間隔を細かく指定できる。
 * ※US時刻であることに注意。
 * 
 * 一番アプリが利用されない時間帯を考慮して、夜中の2時に実行されるようにしてみた。
 * ※US時刻で朝10時
 * 公式サンプルはschedule('every 24 hours')になっており、毎日0時に実行される。
 */
exports.scheduledFirestoreExport = functions.pubsub
                                            .schedule('every day 10:00')
                                            .onRun((context) => {

  const projectId = process.env.GCP_PROJECT || process.env.GCLOUD_PROJECT;
  const databaseName =
    client.databasePath(projectId, '(default)');

  return client.exportDocuments({
    name: databaseName,
    outputUriPrefix: bucket,
    // Leave collectionIds empty to export all collections
    // or set to a list of collection IDs to export,
    // collectionIds: ['users', 'posts']
    collectionIds: []
    })
  .then(responses => {
    const response = responses[0];
    console.log(`Operation Name: ${response['name']}`);
  })
  .catch(err => {
    console.error(err);
    throw new Error('Export operation failed');
  });
});

指定したコレクションのみをバックアップ対象にすることもできるようですが、コレクションを指定した場合はサブコレクション(使ったことがないが)が除外されるだろうことと、今回はデータ復旧のためのバックアップが目的なので、特段指定する必要はないと判断しました。

作成したfunctionをデプロイします。

firebase deploy --only functions

GCPで確認すると、正常に登録できた模様です。

アクセス権限の付与

functionをデプロイしただけではダメで、どうやらバックアップの取得を行うアカウントに権限を付与しなければならないとのこと。
公式:アクセス権限を構成する

gcloudやgsutilコマンドラインツールをインストールしていなかったので、cloud shellから実行しました。

gcloud projects add-iam-policy-binding PROJECT_ID \
    --member serviceAccount:PROJECT_ID@appspot.gserviceaccount.com \
    --role roles/datastore.importExportAdmin
gsutil iam ch serviceAccount:PROJECT_ID@appspot.gserviceaccount.com:admin \
    gs://BUCKET_NAME

実行結果を貼り付けたかったのですが、固有情報満載のようだったので割愛。
特にエラーは吐き出されませんでした。

テスト

Cloud Scheduler ジョブと Cloud Functions の関数をテストするに従って確認してみました。

Cloud Schedulerを確認すると、スケジューラーが登録されており、ステータスは「まだ実行されていません」となっていましたが、「強制実行(公式では「今すぐ実行」)」をしてみると、無事「成功」になりました。スケジューラーからFunctionの実行は問題ないようです。

Functionsのログを確認

Cloud Function のログを確認するに従ってさっそくログを確認してみると・・・

無事に完了している模様。

Bucketの確認

当然、Bucketを確認するとバックアップファイルが保存されていました。

まとめ・課題

無事にバックアップが取得できました。翌日にバックアップが増えていれば完璧。
ただ、このままだと無限にバックアップが増えてしまうので、それを何とか制御できないか。

リストアについては以下でまとめました。
https://zenn.dev/shisyamo4131/articles/60e0a5e4fc4b90

参考

こちらの記事を参考にさせていただきました。

Discussion