こんにちは。サーバ、インフラ周りを担当している鷲見(@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 バックアップのアーキテクチャは下図のようになります。
まず Cloud Scheduler で起動する、Firestore をバックアップする 関数 を実装します。
バックアップには FirestoreのCloud API を利用します。
他にも GCP のリソースを操作する様々な API が提供されているので、 GCP のサービスを連携する際には所望の API がないか見てみると面白いと思います。
https://cloud.google.com/apis/docs/overview
また、API を利用する際にはアクセストークンの発行が必要です。アクセストークンを発行するサービスアカウントは次の2つのロールを持っている必要があります。
- Firestore: Owner, Cloud Datastore Owner, or Cloud Datastore Import Export Admin
- Cloud Storage roles: Owner or Storage Admin
アクセストークンを取得して 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 が追加されているので、選択します。
その後、ジョブの詳細を入力します。 今回は Cloud Functions を用いて Firestore のバックアップを行います。 前節での実装に合わせて、ターゲットは Pub/Sub、トピックは FirestoreBackup、ペイロードは backup とします。
頻度欄の書式はこちらの公式ドキュメントを参考にしてください。
これでジョブの追加は完了です。簡単ですね。
動作を確認する
以上で、Cloud SchedulerとCloud Functionsの連携が完了しました。動作確認してみましょう。
GCPコンソールから直接ジョブを起動できます。ジョブの一覧から今すぐ実行ボタンを押します。
すると FirestoreBackupトピックに Pub/Sub メッセージが送られ、FirestoreBackup 関数が起動します。
Cloud storageをみてみるとバックアップファイルが作成されています。restoreは gcloud beta firestore import gs://${projectId}-firestore-backup
で行うことができます。
以上により、Cloud SchedulerでFirestoreを定期的にバックアップできるようになりました。
まとめ
Cloud Scheduler を用いて Firestore のバックアップを簡単にスケジューリングできました。GAEやGASで定期実行のためのプログラムを書く必要がなくなり、便利ですね。
料金もジョブ 3つまで無料、4 つ以降はジョブ1つ辺り $0.1 / Month ととても安いです。(参考: Cloud Scheduler Pricing)
定期的に行っているタスクがある場合はぜひ使ってみて下さい!
Tip us!
エンジニアチームのブログを書くモチベーションが上がります!