こんにちは。サーバ、インフラ周りを担当している鷲見(@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つのロールを持っている必要があります。

アクセストークンを取得して 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
    const scopes = ['https://www.googleapis.com/auth/datastore', '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!

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

address

0xd6d478dCe4585a394834690158cf83581223C08f