Google Cloud Build を使って Cloud Firestore のバックアップを定期実行
[追記] gcloud
コマンドを使わずにFirestoreのREST APIのexportDocuments をGoogle Cloud Functionsから直接叩いた方が簡単でした
こちらの記事をご覧ください:
以下のGoogle Cloud Buildを利用したアプローチはFirestoreのバックアップとしてはここまで必要無かったですが、何かの要件でCloud Functionsではできないことをやりたい時の1つの選択肢にはなると思います。
gcloud firestore export
コマンドだけでは、Firestoreドキュメントのバックアップはできても、その定期実行ができません。本記事では、その定期実行を行うための手順を説明します。Google Cloud Buildを使いますが、DockerベースなのでCircleCI 2.0を使うなど、その他様々な手段があり得ると思います。いずれにせよやる内容はある程度共通なので参考になるところはあるはずです。
gcloud
コマンドの firestore export
については次の記事をご覧ください。
対応手順の流れ
なかなかやることが多いので、まず初めに対応手順の流れを示します。
gcloud alpha firestore export
コマンドを認証情報付きで実行可能なDockerfileを作成- Google Cloud Build にて、作成したDockerfileをビルド・実行するトリガーを作成
- Google Apps Engine(GAE)にて用意したCronから定期的にPublishされるバックアップ用のTopicをGoogle Cloud Functions の pubsub トリガーで監視して、Cloud Buildのトリガーを実行
- Cloud Buildの処理が終了されるとPublishされるTopicをCloud Functions の pubsub トリガーで監視して必要に応じてSlackなどに通知
1. `gcloud alpha firestore export`
コマンドを認証情報付きで実行可能なDockerfileを作成
Google Cloud Functionsから直接 gcloud
コマンドを実行するのは難しそうなので、Dockerにて構築します。
次のようなDockerfileを作成しました(Docker初心者なので突っ込みどころがあれば教えてください)。
上から順に補足説明していきます。
# gcloud alphaコマンド実行環境を用意
まずは、 gcloud
コマンドを実行できるようにします。次の公式のDockerfileがあるのでほとんど真似をしました。
次のようにしなかったのは、バージョンが 206.0.0
と少し古めの設定になっていて、 gloud alpha firestore
コマンドが使えなかったからです。
FROM google/cloud-sdk:alpine
色々やりようがありますが、今回は本家に追従したい気持ちも薄かったのでforkなどせず、他のインストールコマンドは真似つつバージョンだけ 211.0.0
に書き換えましたが、もっとスマートなやり方もあるかもしれません。
また、alpineは軽量Linuxのことです。
最後に以下を付け足して、 gcloud alpha
コマンドを実行できるようにします。
gcloud -q components install alpha
途中、確認プロンプトが挟まれるので、 -q
( --quiet
) オプションを付けて、自動的にデフォルトの yes が選ばれるようにしているのがポイントです。
次のドキュメントにこのあたり書かれています。
# gcloud認証情報をDockerイメージ内にコピー
あらかじめDockerfileと同じディレクトリにGCPサービスアカウントのキーを含む keys
ディレクトリを配置しておいて、それをDockerイメージ内にコピーします。
これらのサービスアカウントは後の backup.sh
内で使われます。
Cloud Firestoreのバックアップ・リストア — Medium にも書いた通り、次の権限が必要です。
- Cloud Firestore roles:
Owner
,Cloud Datastore Owner
, orCloud Datastore Import Export Admin
- Cloud Storage roles:
Owner
orStorage Admin
最低権限だと次の2つで、基本的にはこれだけを選択することをオススメします。
Cloud Datastore Import Export Admin
Storage Object Admin
次のように、IAM & adminのService accountsから、+ CREATE SERVICE ACCOUNTボタンを押します。
そして、次のように権限を選択します。この時Finish a new private keyを選択しておくと一緒にJSON形式のprivate keyが生成されて便利です。
ここで生成されたkeyを上述のkeysディレクトリに配置しておきます。
# バックアップスクリプトをDockerイメージ内にコピー
あらかじめ次のような backup.sh
ファイルを用意しておいて、それをコピーしておきます。
#!/bin/bash
をきちんと書いておかないと実行時エラーが発生するので気をつけましょう。
処理としては、先ほど生成したサービスアカウントのプライベートキーで認証して、エクスポートしたいFirestoreの[PROJECT_ID]をセットして、適切なGoogle Cloud StorageのBucketに向けてエクスポートコマンドを実行しています。
以上が、 docker build .
などを実行した時にビルドされるDockerイメージとなります。
最後のこちらは docker run
などを実行した時に実行されるコマンドです。
CMD ["/backup.sh"]
ここまでで、ローカルで実行できるDockerfileが出来上がったので、次のコマンドで試せて、うまくいくと実際にバックアップ処理までなされます。
# ビルド
docker build . -t backup
# バックアップ実行
docker run backup
初回以外はビルド込みで実行しても数十秒程度で処理が終わります。ほとんど gcloud alpha firestore export
コマンドの実行時間で、実際の処理はバックグラウンドでなされるので、もしデータ量が増えてもあまり長引くことはないはずです(コレクション数に応じて実行時間が伸びそうなイメージ)。
うまくいかない場合は、 docker run -it backup
でコンテナ内にそのまま入って、色々試行錯誤してみてください。
2. Google Cloud Build にて、作成したDockerfileをビルド・実行するトリガーを作成
ここまででFirestoreのバックアップを実行可能なDockerイメージができたので、あとはこれを定期実行可能にすればOKです。正直、CircleCI 2.0のScheduling jobs の方がシンプルに組める気がしつつ(実際に試していないので分かりませんが)、今回は少し前から興味があったGoogle Cloud Buildを使ってみることにしました。また、GCP(Google Cloud Platform)サービス群になるべく寄せることで管理しやすくなるメリットもあると思っています。
ビルド時間が1日あたり120分まで無料なので、コスト的にも安心して使えます(コスト的にはバックアップ処理でかかるFirestoreのRead料金が一番気になります)。
また、以下の記事のようにGoogle Cloud Functions にてDockerを実行することもできそうですが、公式にサポートされているやり方ではなく今後とも安心して使えるとは思えないので避けました。
Google Container Registry にDokerイメージを作成
それでは、Google Container Registry にDokerイメージを作成する方法から説明していきます。次のような cloudbuild.yaml
ファイルをDockerfileと同じディレクトリに作成します。
stepsの1つめで docker build . -t gcr.io/[PROJECT_ID]/gcloud
相当、2つめで docker run gcr.io/[PROJECT_ID]/gcloud
相当のことをしています。
そして、次のコマンドを実行すると、Google Container Registry にDokerイメージが作成されます。
gcloud builds submit --config cloudbuild.yaml .
次のコマンドでこのイメージを実行することができます。
docker login -u oauth2accesstoken -p "$(gcloud auth application-default print-access-token)" https://gcr.io
docker run gcr.io/[PROJECT_ID]/gcloud
手元のイメージが古い時は次のコマンドで更新します。
docker pull gcr.io/[PROJECT_ID]/gcloud:latest
その他、詳しくはこちらのドキュメントに書いてあります。
Google Cloud BuildにてDockerのビルド・実行
上記手順ではまだContainer RegistryにDockerイメージが作成されただけなので、次にGoogle Cloud Buildにてビルド・実行できるように設定します。
まずは、これまで用意したDockerfileおよび関連ファイルの含まれたディレクトリをプライベートなGitリポジトリーにPUSHします。Cloud Buildに対応したリポジトリは以下の3つなのでそこからお好みのものを選びます。
GitHubを選んだ前提で説明していきます。まず、リポジトリのルートはこういう状態になります。
次にCloud BuildのBuild triggersを選択して、Add triggerボタンを押します。
あとは、次のように画面に従って所望の設定をしていきます。
トリガーができたら、まずはRun triggerを押して動作確認してみます。
このように、Build historyで処理が開始されるのが確認できるはずです。
Build detailsからログなどの詳細を確認できます。
次のように無事に成功して、GCS(Google Cloud Storage)上でもエクスポートされていることが確認します。
3. Google Apps Engine(GAE)にて用意したCronから定期的にPublishされるバックアップ用のTopicをGoogle Cloud Functions の pubsub トリガーで監視して、Cloud Buildのトリガーを実行
次に、いよいよCloud Buildトリガーの定期実行を設定していきます。
Google Apps Engine(GAE)にてCron環境を用意
こちらは、公式の分かりやすい日本語記事があるので、そちらに従ってください。
まだアルファ版ですが、それが許容できればCloud Schedulerを使うのも良さそうです。
上記の方法ではCloud FunctionsではPub/Subトリガーを使うことになりますが、より手軽に扱える cron-job.org を使ってHTTPSトリガーを使う選択肢もあります。
GAEのCron環境の場合、次のような cron.yaml
を記述します。この場合、毎朝5時にバックアップ用の backup-firestore
トピックが発行されます。
Google Cloud FunctionsのPub/Subトリガーを用いてCloud Buildトリガーを実行
このような感じで、Pub/Subトリガーを用いてCloud BuildトリガーをREST APIで叩くように設定します。
次のパッケージのインストールが必要です。
Cloud Build のREST APIのURLに設定している[TRIGGER_ID]
はトリガーの詳細ページのURLなどから取得できます。また、APIのリファレンスはこちらです。
これにて、ようやくFirestoreバックアップの定期実行の仕組みが整いました🎉
4. Cloud Buildの処理が終了されるとPublishされるTopicをCloud Functions の pubsub トリガーで監視して必要に応じてSlackなどに通知
最後に、Firestoreバックアップ処理が正常動作していることを確認できる監視の仕組みを設定します。
まず、Cloud Buildは、処理の開始・終了時にPub/Subの cloud-builds
トピックへメッセージを発行するようにデフォルトでなっています。
つまり、単純に以下のようにGoogle Cloud Functionsで cloud-builds
トピックにて以下を記述するだけでOKです。
メッセージの内容は実際の結果を見たり、以下のドキュメントを参考に適宜整形して、状況に応じて然るべきところに通知を発行します。
これにて、監視もバッチリです👍