🔥

Firestore のデータをデイリーでバックアップする

2022/07/30に公開

経緯

いつのまにか 公式ドキュメント に手順が明記されていたので、こちらを試したときのメモです。基本的に公式の通りにやれば何の問題もありませんが、 Functions のコードだけは ESM 形式にしたり、 async/await に書き換えたり一部モダンにしています。

手順

1. バックアップ保存先となるバケットの作成および権限の変更

バケット作成時にリージョンと保護期間を指定しています。こちらは ドキュメント を参考にお好みで変更してください。 また、 PROJECT_IDBUCKET_NAME は環境に合わせて変更してください。

# プロジェクト ID を確認
$ gcloud projects list

# ターゲットのプロジェクトをデフォルトプロジェクトに指定する
$ gcloud config set project PROJECT_ID

# バケットを作成 (リージョンと保持期間を指定してます)
$ gsutil mb -l asia-northeast1 --retention 30d gs://BUCKET_NAME

# バケット一覧を表示し、作成されていることを確認する
$ gsutil ls
gs://BUCKET_NAME/

# Cloud Datastore インポート / エクスポート管理者ロールを割り当てる
$ 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

2. Functions にコードを追加する

公式のコードから以下の変更を加えています。

  • ESM 形式に変更
  • async/await を使用
  • バックアップスケジュールを日本時間の深夜 0 時に
import { v1 } from '@google-cloud/firestore';

export const backupFirestoreDaily = functions
  .region('asia-northeast1')
  .pubsub.schedule('0 0 * * *')
  .timeZone('Asia/Tokyo')
  .onRun(async () => {
    const projectId = process.env.GCP_PROJECT || process.env.GCLOUD_PROJECT;
    if (projectId === undefined) {
      throw new Error('Project ID is not specified.');
    }

    const firestoreAdminClient = new v1.FirestoreAdminClient();
    const databaseName = firestoreAdminClient.databasePath(projectId, '(default)');

    try {
      const responses = await firestoreAdminClient.exportDocuments({
        name: databaseName,
        outputUriPrefix: 'gs://BUCKET_NAME',
        collectionIds: [], // all collections
      });
      const response = responses[0];
      if (response.name !== undefined) {
        logBackupSucceeded(response.name);
      }
    } catch (error) {
      if (error instanceof Error) {
        logBackupError(error.message);
      }
      throw new Error('Export operation failed');
    }
  });

おわりに

これで夜中の 12 時頃に全コレクションのバックアップが走るので、 念の為 Functions のログやバケットの中身を確認してみるのが良いと思います。

Discussion