Help us understand the problem. What is going on with this article?

Firebaseプロジェクトのデプロイについて

More than 1 year has passed since last update.

2018/02/15追記

この記事以降、Alpine Linuxイメージだとしばしばfirebase-toolsのインストール中にgrpcのバイナリファイルが存在されずにインストールが失敗することがありました。

現時点(v3.17.4)ではこの問題は起きていませんが、安定を考えてnode-slimイメージを使った方がいいかもしれません。

前置き

この記事は「Firebase Advent Calendar 2017」7日目の記事となります。

Firebaseを使ったプロダクトの知見はちらほら見るようになりましたが、デプロイ周りの知見はまだほとんど見ません。ですので私が実際にやっていることをまとめてみました。参考になれば幸いです。

前提とする必須条件

  • 開発、ステージング、本番などにデプロイ先を切り替えられる
  • 秘匿情報はリポジトリに組み込まない
  • CIでデプロイ可能にする

まずはこれが達成できていることを前提にします。

Firebase CLI

まず本記事はFirebase CLIの利用を前提としています。そしてFirebase CLIに対する解説はほぼしないため、こちらについては公式のドキュメントを参照してください。

Firebase CLI リファレンス  |  Firebase

デプロイ先を切替可能とする

たとえばHostingやDatabase関連は、ひとつのプロジェクトにつき、ひとつしか用意されていません。そのため本番環境とステージング環境など複数の環境を用意したい場合は、それぞれのFirebaseプロジェクトを新規作成する必要があります。
これはGoogle公式のドキュメントでも、そんな風に指示しています。

プロジェクトへの追加は firebase use --add を使う方法もありますが、.firebaserc を直接編集した方が手っ取り早いと思います。

.firebaserc
{
  "projects": {
    "release": "project-id",
    "develop": "develop-project-id"
  }
}

firebase initでデフォルト連打してプロジェクトを作成すると default 枠が作られているので、これを意図的に削除しておきます。デプロイ先を明示的に指定することで、デプロイ先間違えという事故を防ぐためです。

# develop環境へdeployを実施する
$ firebase use develop
$ firebase deploy

CI用に認証トークンを用意する

通常、Firebase CLIを使用する場合、firebase loginで必要なGoogleアカウントへログインする必要があります。しかしそれだとデプロイするたびにログインが必要となりますし、なにより一度ブラウザに遷移するためCIでは利用できません。

という問題を回避するために、 login:ci というコマンドがあります。実行すると login 同様にブラウザで認証処理が呼び出されます。この認証が完了するとトークンを返却します。

$ firebase login:ci

Visit this URL on any device to log in:
https://accounts.google.com/o/oauth2/auth?client_id=......

Waiting for authentication...

✔  Success! Use this token to login on a CI server:

1/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Example: firebase deploy --token "$FIREBASE_TOKEN

# 使用例
$ firebase use develop --token 1/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
$ firebase deploy --token 1/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# 認証トークンを無効化する
$ firebase logout --token 1/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

✔  Logged out token "1/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

ここで取得した認証トークンを使うことで、ログインしていない環境からでもFirebase CLIを使うことができます。

# tokenを利用してdevelop環境でdeployを実施
$ firebase use develop --token 1/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
$ firebase deploy --token 1/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

認証トークンは「Firebaseのプロジェクトに紐づくトークン」ではない

気を付てほしいことがあります。ここで発行した認証トークンは、Googleアカウントに紐付いたトークンです。認証したGoogleアカウントが他のFirebaseプロジェクトにもアクセス可能な場合、そのプロジェクトにも利用可能です。

たとえば開発環境(ステージング)の認証トークンでは本番環境にデプロイさせたくない、というケースがあるとします。その場合、開発環境のFirebaseプロジェクトだけアクセスできるGoogleアカウントからトークンを発行しないといけません。また、該当するGoogleアカウントが削除された場合、当然発行された認証トークンは使えなくなります。

これまで生成した認証トークンって確認できる?

わかりません…。少なくとも、Firebase周りの管理画面では確認できる場所がありませんでした。私も知りたい。

Dockerでデプロイ環境を作る

ということで、CLIだけでデプロイできる準備が整ったのでここからが本番です。私の個人的な趣味と、Circle CI 2.0を利用してデプロイできるようにしたかったので、Dockerでデプロイ環境を構築します。

また、なるべくimageを軽くしたかったので、alpineイメージを利用しています。

deploy.dockerfile
FROM node:6.11-alpine

RUN apk update
RUN apk add git
RUN npm install -g firebase-tools

RUN mkdir app
WORKDIR app

ARG FIREBASE_PROJECT="develop"
ARG FIREBASE_TOKEN="x/xxxxxxxxxxxx"

CMD cd functions && npm install && cd ../ \
    && firebase use ${FIREBASE_PROJECT} --token ${FIREBASE_TOKEN} \
    && firebase deploy --token ${FIREBASE_TOKEN}
deploy-develop-compose.yml
version: '2'
services:
  deploy:
    environment:
      - FIREBASE_PROJECT=develop
      - FIREBASE_TOKEN
    build:
      context: ./
      dockerfile: deploy.dockerfile
    volumes:
      - ./:/app

これで、 docker-compose -f ./deploy-develop-compose.yml up --build とすれば、Docker上でデプロイされるようになりました。
ステージング環境やリリース環境へデプロイする場合は、そのぶんだけ FIREBASE_PROJECT を変更したcompose.ymlを用意します。

Dockerfileの中身少し解説

ARGで初期値を適当にいれているのは、明示的に指定させないと必ず失敗させるようにしたいためです。

また、compose.ymlでは値を指定しないenvironmentがあると、同名のシステム環境変数から値を取得します。今回のプロジェクトで秘匿したい情報は認証トークンだけですので、これでリポジトリにトークンを書かずに済みます。

DockerfileのCMDで最初にやっていることは、Cloud Functionsのデプロイに必要な設定です。Cloud Functionsを触っていないのであれば、飛ばしても問題ありません。

Circle CI2.0で実行する

Circle CI2.0では、そのままconfig.ymlでcomposeを実行するだけです。
FIREBASE_TOKENはCircle CIの環境変数へ登録してください。ただしVM上での実行を前提とするため、 machine:true を忘れずに設定してください。

.circleci/config.yml
version: 2
jobs:
  build:
    machine: true
    steps:
      - checkout
      - run:
          name: deploy
          command: |
            docker-compose -f ./deploy-develop-compose.yml up --build

deployの動作について

firebase deploy を実行すると、プロジェクト内でdeploy対象となる各機能(Hosting、Database Rules(+Firestore Rules)、Storage Rules、Cloud Functions)のデプロイが実行されます。この中でひとつでもdeployに失敗すると、全てのdeployは中断されます。また、既にdeployに成功している機能もロールバックされます。

これはDatabaseやStorageのRulesの更新と同時にHostingやCloud Functionsをデプロイしたい場合には有効ですが、こうした仕様であることは留意する必要があります。

個別で確実にdeployを終わらせたい場合は、 firebase deploy --only [hosting|functions|database|storage] で機能ごとにdeployすればいいですが、普通使うことはないと思います。

ただCircle CI2.0だとたまにtimeoutエラーでコケることがあったので、自分は--onlyで別個でアップさせる設定を利用することもあります。

全般的に言えることですが、firebase deployはdeployに失敗してもsuccessが返ってくるため、deployの終了通知がきてもCircleCIのログを見て確認が必要です…。不便。

deploy.dockerfile
#(省略)

CMD cd functions && npm install && cd ../ \
    && firebase use ${FIREBASE_PROJECT} --token ${FIREBASE_TOKEN} \
    && firebase deploy --only database --token ${FIREBASE_TOKEN} \
    && firebase deploy --only firestore --token ${FIREBASE_TOKEN} \
    && firebase deploy --only storage --token ${FIREBASE_TOKEN} \
    && firebase deploy --only hosting --token ${FIREBASE_TOKEN} \
    && firebase deploy --only functions --token ${FIREBASE_TOKEN}

機能ごとにリポジトリを分けるべきか

今回紹介したデプロイでは、ひとつのリポジトリにHosting、DatabaseやStorageのRule、Cloud Functionsがすべて入ったリポジトリの場合、全部まるごとデプロイします。当然ながらその場合、不要な部分のデプロイも走ってしまい、無駄な時間ができてしまいます。

もし変更点をチェックして、必要な部分デプロイの判断をするやり方を知っているのであれば、その対応をするのが一番かもしれません。ちなみに私はやり方を知りません…。

そうでない場合、いきなり複数のリポジトリに分けても管理が大変だと思います。一番デプロイに時間がかかるのはCloud Functionsなので、やるにしてもまずはCloud Functionsとその他、ぐらいで分けるぐらいでも良いかもしれません。

以上です。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away