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

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

こんにちは。サーバ、インフラ周りを担当している鷲見(@soichisumi)です。

先日、GCP に Cloud Scheduler が追加されました。 GCP のコンソールまたは CLI から、定期的にタスクを実行できるというサービスです。

実行できるタスクは以下の3つです.

  • HTTPリクエスト
  • Pub/Sub メッセージ
  • App Engineアプリケーション

App Engine の cron job が HTTP リクエスト、Pub/Sub もターゲットに指定できるようになって外出しされたようなサービスだと思えば良さそうです。

これで今まで定期実行のために行っていた、App Engine + cron job や Apps Script の実装・デプロイが不要になります 🎉🎉🎉

早速使ってみましょう。

Cloud Firestore をバックアップする 関数 の実装

今回作る Firestore バックアップのアーキテクチャは下図のようになります。

image

まず Cloud Scheduler で起動する、Firestore をバックアップする 関数 を実装します。

バックアップには FirestoreのCloud API を利用します。

他にも GCP のリソースを操作する様々な API が提供されているので、 GCP のサービスを連携する際には所望の API がないか見てみると面白いと思います。

https://cloud.google.com/apis/docs/overview

また、API を利用する際にはアクセストークンの発行が必要です。アクセストークンを発行するサービスアカウントは次の2つのロールを持っている必要があります。

アクセストークンを取得して Cloud API を呼び出し、バックアップジョブを登録する Javascript コードが下記になります。

また、保存先のバケットも合わせて作成します。下記コードであればgs://${projectId}-firestore-backup となります(${projectId}は GCP or Firebase のプロジェクトID)。リージョンは、 Multi-Regional or Regional を選択し、関数 と同じリージョンを選択するようにしてください。


const functions = require('firebase-functions');
const { google } = require('googleapis');
const rp = require('request-promise');
const projectId = process.env.GCLOUD_PROJECT; // 関数が属しているGCPプロジェクトIDが環境変数に登録されている

async function getAccessToken(){
	// [**https://developers.google.com/identity/protocols/googlescopes**](https://developers.google.com/identity/protocols/googlescopes)
	const scopes = [**'[https://www.googleapis.com/auth/datastore](https://www.googleapis.com/auth/datastore)', '[https://www.googleapis.com/auth/cloud-platform](https://www.googleapis.com/auth/cloud-platform)'**];
	let serviceAccount = require('./keys/service-account.json');
	
	const jwtClient = new google.auth.JWT(
	    serviceAccount.client_email,
	    undefined,
	    serviceAccount.private_key,
	    scopes,
	    undefined
	);
	try{
	    const authorization = await jwtClient.authorize();
	    return authorization.access_token;
	}catch(err){
	    return err;
	}
}

async function exportFirestore(){
	try{
		const accessToken = await getAccessToken();
		const endpoint = `https://firestore.googleapis.com/v1beta1/projects/${projectId}/databases/(default):exportDocuments`;
		const option = {
			headers: {
				Authorization: `Bearer ${accessToken}`
			},
			json: true,
			body: {
				outputUriPrefix: `gs://${projectId}-firestore-backup`,
			}
		};
		const res = await rp.post(endpoint, option);
		return res;
	}catch(err){
		console.log(`error occurred when doing backup: ${err}`);
		return err;
	}
}

exports.FirestoreBackup = functions.pubsub
																		.topic('FirestoreBackup')
																		.onPublish(async (msg)=>{
	try{
		const res = await exportFirestore();
		console.log(`firestore backup job is successfully registered: ${res}`);
		return res;
	}catch(err){
		console.log(`error occurred when backuping: ${err}`);
	}
	});

package.jsonは次のようになります。async/awaitを使うため、ランタイムは Node 8 とします。


{
	"name": "functions",
	"description": "Cloud Functions for Firebase",
	"scripts": {
	},
	"dependencies": {
		"firebase-admin": "^6.0.0",
		"firebase-functions": "^2.0.5",
		"googleapis": "^34.0.0",
		"request": "^2.88.0",
		"request-promise": "^4.2.2"
	},
	"devDependencies": {
		"eslint": "^4.12.0",
		"eslint-plugin-promise": "^3.6.0"
	},
	"private": true,
	"engines": {
	"node": "8"
	}
}

上記実装は GCPUGのブログ記事を参考にしています。こちらも読んでみると参考になるかもしれません。

以上で Firestoreをバックアップするfunctionの準備が終わりました。

Cloud Scheduler でジョブを作成する

それでは本題の Cloud Scheduler を使っていきましょう。

サービス一覧の中に Cloud Scheduler が追加されているので、選択します。

image

その後、ジョブの詳細を入力します。 今回は Cloud Functions を用いて Firestore のバックアップを行います。 前節での実装に合わせて、ターゲットは Pub/Sub、トピックは FirestoreBackup、ペイロードは backup とします。

頻度欄の書式はこちらの公式ドキュメントを参考にしてください。

image

これでジョブの追加は完了です。簡単ですね。

動作を確認する

以上で、Cloud SchedulerとCloud Functionsの連携が完了しました。動作確認してみましょう。

GCPコンソールから直接ジョブを起動できます。ジョブの一覧から今すぐ実行ボタンを押します。

image

すると FirestoreBackupトピックに Pub/Sub メッセージが送られ、FirestoreBackup 関数が起動します。

image

Cloud storageをみてみるとバックアップファイルが作成されています。restoreは gcloud beta firestore import gs://${projectId}-firestore-backup で行うことができます。

image

以上により、Cloud SchedulerでFirestoreを定期的にバックアップできるようになりました。

まとめ

Cloud Scheduler を用いて Firestore のバックアップを簡単にスケジューリングできました。GAEやGASで定期実行のためのプログラムを書く必要がなくなり、便利ですね。

料金もジョブ 3つまで無料、4 つ以降はジョブ1つ辺り $0.1 / Month ととても安いです。(参考: Cloud Scheduler Pricing)

定期的に行っているタスクがある場合はぜひ使ってみて下さい!

Tip us!

エンジニアチームのブログを書くモチベーションが上がります!

image