羊をめぐるブログ

趣味の色々について書きます

Firebase周りのCI/CDと,環境分離について

はじめに

これは2021年振り返りカレンダーの5日目の記事です.

前回はBitrise上でExpo OTAを行うワークフローを構築するという内容でした.

serenard.hatenablog.com

今回は,最近の初期アプリにはほとんど使われてそうなFirebase周りのCI/CDと, 環境分けについて書いていきます.

CI/CDの対象となるFirebaseのサービスはFirebase Functionです. また,storageやfirestoreのセキュリティールールのデプロイは 環境ごとに対象バケット名が少し変わったりするので, そこをどう分けて管理するかについてです.

仕様

今回は,service-dev,service-prd の2つのfirebase projectがあり, それぞれのために以下を作りたいとします.

  • firestore のセキュリティルール及びインデックスのデプロイコマンド
  • firebase storage のセキュリティルールのデプロイコマンド
  • firebase functions のCI/CD

実装

まず,ディレクトリ構造は以下のようになります.

root/
├── firebase
│  ├── functions
│  ├── .firebaserc
│  ├── firebase_dev.json
│  ├── firebase_prd.json
│  ├── firestore.indexes.json
│  ├── firestore.rules
│  └── storage_assets.rules
├── release
   ├── dev
    │   └── deploy_functions.yaml
   └── prd
        └── deploy_functions.yaml

セキュリティルールなどのデプロイコマンド

各環境で,どのセキュリティールールをデプロイするかなどを,firebase_{dev|prd}.jsonで管理します. 内容は以下の感じになります.

{
  "firestore": {
    "rules": "firestore.rules",
    "indexes": "firestore.indexes.json"
  },
  "storage": [
    {
      "rules": "storage_assets.rules",
      "bucket": "service-dev-public-assets"
    }
  ]
}

また,デプロイは以下のようなコマンドを用意しておきます.

# ストレージのセキュリティルールのデプロイ
firebase deploy --only storage:rules --config firebase_{dev|prd}.json
# firestoreのセキュリティルール
firebase deploy --only firestore:rules  --config firebase_{dev|prd}.json

configを用意したことで毎回それをオプションで指定する必要が出てきますが, 常に環境を意識させられるのでまぁいいかぁという印象です. デフォルトはfirebase.jsonを参照するので,devはそれにしてもいいかもしれません.

firebase functions のCI/CD

functions のCI/CDの設定は,release下の各環境ごとのCloud Buildファイルを参照させて行います.

Cloud Buildの設定ファイルの流れは以下のようになっています.

  1. functionsのコードのビルド
  2. デプロイ先の環境を設定
  3. 環境変数,シークレット変数を設定
  4. デプロイ

シークレット変数は,secret managerに入れておき,Cloud Buildからそれを参照します.

cloud.google.com

実際のCloud Buildのファイルは以下のような感じです.トリガーのタイミング自体は適当に設定しましょう.

steps:
  - id: build_functions
    name: node:14.15.4
    dir: firebase/functions
    entrypoint: bash
    args:
      - -c
      - |
        npm i \
        && npm run build
  - id: deploy_functions
    name: gcr.io/$_PROJECT_ID/firebase
    dir: firebase
    entrypoint: bash
    args:
      - -c
      - |
        firebase use dev --config $_FIREBASE_CONFIG_JSON \
        && firebase functions:config:set slack.channel=$_SLACK_NOTIFICATION_CHANNEL --config $_FIREBASE_CONFIG_JSON \
        && firebase functions:config:set slack.oauth_token=$$SLACK_OAUTH_TOKEN --config $_FIREBASE_CONFIG_JSON \
        && firebase deploy --project=$_PROJECT_ID --only functions --config $_FIREBASE_CONFIG_JSON
    secretEnv: ["SLACK_OAUTH_TOKEN"]
    timeout: "600s"
substitutions:
  _PROJECT_ID: service-dev
  _FIREBASE_CONFIG_JSON: firebase_dev.json
  _SLACK_NOTIFICATION_CHANNEL: service_dev_notice_test
availableSecrets:
  secretManager:
    - versionName: projects/service-dev/secrets/service-dev-slack-oauth-token/versions/latest
      env: "SLACK_OAUTH_TOKEN"

その他細かい知見など

  • firebase functions のCloud Build上でのビルドはコードにエラーが無くてもたまに落ちることがある(nodeのエラーが出てたがよくわからなかった).再実行しやすくしておくとよい.
  • GCPのプロジェクト切り替えてもfirebaseは切り替わらないのでデプロイの際は注意.

最後に

内容薄いのですが備忘録として.firebaseも色々terraform化できるようになったら嬉しいな〜と少し思いました.