😺

GCPのCloud Shellを使ってFirestoreのデータを別アカウント間で移行する

2021/06/28に公開

モチベ

個人的に作ったFlutter×Firebaseの出退勤アプリを社内で使ってもらってたんですが、退職することになったので、会社のアカウントにデータを移行することになりました。

使ったもの

  • Cloud Shell
  • Cloud Storage
  • Service Account
  • Firestore

前提条件

元々使っていたFirebaseアカウントをSRCアカウントとします。
新しく使うFirebaseアカウントをDSTアカウントとします。

  • SRCアカウント、DSTアカウント共に課金を有効かさせておくこと(少なくともBlazeプラン、Sparkプランはだめです)
  • SRCアカウント、DSTアカウント共にCloud IAMの権限が与えられていること。https://cloud.google.com/iam/docs/granting-changing-revoking-access?hl=ja#grant_access
  • SRC、DST共にFirestoreの構成リージョンを確認しておくこと。
  • 今回はSRCはusマルチリージョン、DSTはasiaマルチリージョンです。

手順

最初に大まかな流れを説明すると以下のようになります。

  1. GCPコンソールでCloud Shellを準備する
  2. SRCアカウントのFirestore からデータのエクスポートを利用してCloud Storageバケットにデータを移す
  3. DSTアカウントでサービスアカウントを作成する
  4. そのサービスアカウントにSRCアカウントのバケットにアクセスする権限を与える
  5. SRCアカウントのバケットをDSTアカウントに転送する
  6. DSTアカウントでデータのインポートを利用してバケットからFirestoreにデータを取り入れる

それでは一つ一つ説明していきます〜
タイトルのかっこの中は作業をSRCアカウントとDSTアカウントのどちらでやるのかを表しています。

1. (SRC,DST) Cloud Shellを準備する

まずはCloud Shellを起動します。GCPコンソールでCloud Shellターミナルを出します。
おそらく最初は別のプロジェクトが指定されていると思います。

user_name@cloudshell:~ (river-woodland)$

このriver-woodlandがCloud Shell内で指定されているプロジェクトです。ここを変えずにそのまま進めると、別プロジェクトの操作しちゃうってことになるので気をつけましょう。
というわけでgcloudコマンドを使ってFirebaseプロジェクトのIDを指定しましょう。
ちなみにFirebaseプロジェクトのIDはFirebaseコンソールのプロジェクトの設定画面から確認できます。

gcloud config set project [FIREBASE_PROJECT_ID]

仮にFirebaseプロジェクトのIDがfirebase-icetowerだとすると

gcloud config set project firebase-icetower

で指定できます。

user_name@cloudshell:~ (firebase-icetower)$

みたいな表示に変われば成功です。

2. (SRC) Firestore → Cloud Storage Bucket (エクスポート)

それでは今まで使っていたFirestoreのデータをCloud Storage Bucketにエクスポートしていきます。
まずはバケットの作成です。公式ドキュメントに書いてある通りに作成していきます。
今回はCloud Shellを使って作成していきます。

gsutil mb -p [PROJECT_ID] -c [STORAGE_CLASS] -l [BUCKET_LOCATION] -b on gs://[BUCKET_NAME]

なんかたくさんオプションがあってわけわかめだと思いますので説明していきます。

  • p : GCPプロジェクトのIDを指定します。Firebaseプロジェクトと同じでOKです。
  • c : ストレージクラスです。一時的なデータ格納なのでStandardでいいと思います。
  • l : バケットのリージョンを指定できます。Firestoreのリージョンと同じにしましょう。じゃないとダメらしいです。
  • b : 均一なバケットレベルのアクセスを有効にするか否かです。onでいいでしょう。
    SRCのFirestoreプロジェクトの構成リージョンはusマルチリージョンなので、仮にPROJECT_IDfirebase-icetowerだとするとこうなります。
gsutil mb -p firebase-icetower -c Standard -l us -b on gs://source_bucket

source_bucketは自分で決めてOKです。neo_armstrong_cyclone_jet_armstrong_bucketでも大丈夫です。
gsutil ls でバケットの作成が確認できれば成功です。

そうしたら漸くですが、Firestoreのデータを作成したバケットの中に入れていきます。
と、その前にもしエクスポートは時間がかかる作業なのでその間にFirestoreへの書き込みが行われないことを担保する必要があります。

ポイントは2つです.

  1. Firestoreのセキュリティルールを変更して書き込みを一時的に阻止する
  2. Firebaseの管理サーバーがあるのであれば、シャットダウンするか書き込みオペレーションを停止させる。

今回は平日のみの使用を想定しているのと、管理サーバーを利用していないことから、手順を省きます。

上記2つ確認できたらFirestoreのデータをエクスポートしていきます。

gcloud firestore export gs://source_bucket --async

はいOKです。出力の中にoutputUriPrefixがあると思うんですが、後で使います。必ずメモしておきましょう

outputUriPrefix: gs://source_bucket/2021-06-27T08:06:32_12345

↑こういうやつです。

3. (DST) サービスアカウントの作成

ここまでできたら続いてサービスアカウントを作成していきます。
DSTアカウント側で1.と同じCloud Shellの準備を忘れずに行いましょう。

Cloud Shellの準備ができたら、サービスアカウントの作成を行っていきます。
Cloud Consoleでもできますが今回はCloud Shellを使っていきます。

gcloud iam service-accounts create [SERVICE_ACCOUNT_ID] \
    --description="[DESCRIPTION]" \
    --display-name="[DISPLAY_NAME]"

[DESCRIPTION]はなくてもOKですが、後でこれなんのために作ったっけ?を防止するためにも説明を書いておきましょう。
[SERVICE_ACCOUNT_ID][DISPLAY_NAME]はIDと名前です。必須ですが自分で決めてOKです。

後でこのサービスアカウントを使って作業する時にオーナー権限が必要になるので付与していきます。
(*)コマンドで作成する方法が見つからなかったのでCloud Console(GUI)を使って付与していきます…!

左上のハンバーガーメニューからIAMと管理/IAMを選択します。

Selecting IAM

選択できたらIAMの追加ボタンを押して追加していきます。追加ボタンを押すと下の画面が出てくると思います。

Creating IAM

ここでメンバーとロールを聞かれますが、メンバーはさっき追加したサービスアカウントのEMAIL、ロールはオーナーで作成します。

サービスアカウントのEMAILはgcloud iam service-accounts listで確認できます。

保存したら完了です。

(補足)
gcloud projects add-iam-policy-bindingでも同じことができるかなと思いましたがうまくいきませんでした。上手くいった方がいましたら教えていただけると幸いです…!

4. (SRC) DSTのサービスアカウントにSRCバケットへのアクセス権限を付与

DST側のサービスアカウントが作成できたらSRC側でSRCバケットへのアクセス権限を付与します。

gsutil iam ch \
  serviceAccount:[SERVICE_ACCOUNT_EMAIL]:objectViewer \
  gs://at10dance_transform

[SERVICE_ACCOUNT_EMAIL]はそのままですが、さっき作ったサービスアカウントのEMAILです。
service-account@firebase-icetower.iam.gserviceaccount.comみたいなやつです。

5. (DST) SRCバケットをDSTバケットに転送

DSTのサービスアカウントにSRCバケットへのアクセス権限が付与までできたと思うので、DST側からSRCバケットのコピーをDSTプロジェクト内に作ることで転送が完了できます。

まずは先ほど作ったサービスアカウントを有効にします。
サービスアカウントのキーファイルを作成して

gcloud iam service-accounts keys create [key-file] \
    --iam-account=[SERVICE_ACCOUNT_EMAIL]

[key-file]はキーファイルのPATHです。なんでもOKですkeys.jsonでも./neo_armstrong/cyclone_jet/armstrong.jsonでもなんでもいいです。あとで分かれば。
[SERVICE_ACCOUNT_EMAIL]はサービスアカウントのEMAILです。

キーファイルをもとにサービスアカウントを有効化していきます。

gcloud auth activate-service-account [SERVICE_ACCOUNT_EMAIL] --key-file=[key-file]

これでサービスアカウントの有効化ができました。

次に転送先のバケットも作っておきます。

gsutil mb -p firebase-icetower -c Standard -l us -b on gs://dst_bucket

あとは転送するのみです

gsutil cp -r gs://source_bucket gs://dst_bucket

Operation Completedて表示されたらOKです。

6. (DST) Cloud Storage Bucket → Firestore (インポート)

ついに来ました最後です…!DSTアカウントのFirestoreにデータをインポートします!!
最後だからって気を抜いたらあかんで!!

gcloud firestore import gs://[SOURCE_BUCKET]/[EXPORT_PREFIX] --async

[SOURCE_BUCKET]はSRC側のバケット名ですsource_bucketです。
[EXPORT_PREFIX]はSRC側でFirestoreからエクスポートした時のoutputUriPrefixです2021-06-27T08:06:32_12345っていうさっきメモしてねって言ったやつです。

gcloud firestore operations listoperationStateSUCCESSFULになってたら完了です。Firestoreを見にいって確認してみましょう!!

はい!!!終わり!!!!!

参考文献

https://firebase.google.com/docs/firestore/manage-data/move-data?hl=ja
https://firebase.google.com/docs/firestore/manage-data/export-import?hl=ja
https://cloud.google.com/storage/docs/creating-buckets?hl=ja#storage-create-bucket-gsutil
https://blog.jicoman.info/2019/10/access-gcs-bucket-in-other-project/
https://cloud.google.com/iam/docs/creating-managing-service-accounts#iam-service-accounts-create-gcloud
https://cloud.google.com/iam/docs/creating-managing-service-account-keys?hl=ja#iam-service-account-keys-create-gcloud

Discussion