初めに
背景
- Vue.jsを用いたWebアプリ(Vue.jsに限った話では無いと思うが念の為)
- FirebaseのFirestoreをDBとして用い、Firebase上にHostingがしたい.
- CI/CDにはCircleCIを用いる.
やりたいこと
- Production環境とStaging環境で接続するDBやHosting先をいい感じに分けてほしい.
ざっくりとした方針
- Production環境とStaging環境でそもそもFirebase上のプロジェクトを分離し、prodcutionブランチにpushされたときはProduction環境に、
StagingブランチにpushされたときはStaging環境に接続するように設定する.
- Production環境とStaging環境の両方のAPIキーなどをCircleCI上の環境変数として定義&
.env
ファイルに書き出すように設定 - build時は
NODE_ENV
の値により.env
から読み出す値を分ける. - deploy時は
firebase use {project}
でプロジェクトを指定した上でデプロイする.
なお、hosting
のみの場合はわざわざプロジェクトを分けたりする必要はありません.
しかし、firestore
はプロジェクトごとに1個しか使えないので、prodcutionとstaging等で分けたい場合はそもそものプロジェクトから分ける必要があります.
前提
- GithubにPushしたらCircleCIでjobが走るところまでは設定できているとします.
手順
1.Firebase上にプロジェクトを2つ作成する.
production用のプロジェクトと、とStaging用のプロジェクトを2つ作成します.
便宜上以下のふたつを作成したとします.
- MyProjectProd
- MyProjectStag
2. それぞれのAPIキー等を.env
に登録する.
本記事ではdotenv
を用いて環境変数を読み出します.
最終的には.env
はCircleCI上で自動的に作られるようにするので、この手順は飛ばしても構いません.
念の為ローカルで動作確認用に作成しているだけです.
まず、dotenv
をインストールしてなければインストールしてください.
project直下に.env
を作成してください.
FIREBASE_API_KEY_PROD=****************
FIREBASE_AUTH_DOMAIN_PROD=****************
FIREBASE_DATABASE_URL_PROD=****************
FIREBASE_PROJECT_ID_PROD=****************
FIREBASE_STORAGE_BUCKET_PROD=****************
FIREBASE_MESSAGING_SENDER_ID_PROD=****************
FIREBASE_API_KEY_STAG=****************
FIREBASE_AUTH_DOMAIN_STAG=****************
FIREBASE_DATABASE_URL_STAG=****************
FIREBASE_PROJECT_ID_STAG=****************
FIREBASE_STORAGE_BUCKET_STAG=****************
FIREBASE_MESSAGING_SENDER_ID_STAG=****************
_PROD
がついている方にはMyProjectProd
の値を、
_STAG
がついている方にはMyProjectStag
の値を、入力してください.
なお、これらの値はFirebase Console上から確認することが出来ます.
3.firebaseの初期化処理を記述する.
2で登録した値を用いてfirebaseの初期化処理を書いていきます.
使用しているフレームワークや構成によって記述する場所は違うと思いますが、筆者の環境(Vue.js
+Nuxt.js
)ではplugins/firebase.js
に記述しています.
if(!firebase.apps.length){if(process.env.NODE_ENV==="production"){//Prodcution環境firebase.initializeApp({apiKey:process.env.FIREBASE_API_KEY_PROD,authDomain:process.env.FIREBASE_AUTH_DOMAIN_PROD,databaseURL:process.env.FIREBASE_DATABASE_URL_PROD,projectId:process.env.FIREBASE_PROJECT_ID_PROD,storageBucket:process.env.FIREBASE_STORAGE_BUCKET_PROD,messagingSenderId:process.env.FIREBASE_MESSAGING_SENDER_ID_PROD});}else{//それ以外(Staging環境,develop環境)firebase.initializeApp({apiKey:process.env.FIREBASE_API_KEY_STAG,authDomain:process.env.FIREBASE_AUTH_DOMAIN_STAG,databaseURL:process.env.FIREBASE_DATABASE_URL_STAG,projectId:process.env.FIREBASE_PROJECT_ID_STAG,storageBucket:process.env.FIREBASE_STORAGE_BUCKET_STAG,messagingSenderId:process.env.FIREBASE_MESSAGING_SENDER_ID_STAG});}}
このようにprocess.env.NODE_ENV
の値によって.env
から読み取る値を変えています.
4. NODE_ENV
の値を設定できるようにする.
NODE_ENV
の値によって処理を変える記述が出来たので、次はNODE_ENV
を設定できるようにします.
本記事では、cross-env
を使用します.
cross-env
自体の使い方は
環境変数設定は基本cross-envだけどたまにenv-cmdも使う
等に書いてあるとおりです.
package.json
に以下のような設定をします.(nuxt.js
仕様)
{..."scripts":{..."build:stag":"cross-env NODE_ENV=\"staging\" nuxt build","build:prod":"cross-env NODE_ENV=\"prod\" nuxt build",...},...}
これで、
を実行すればstaging用の変数を用い、
を実行すればproduction用の変数を用いてbuildが走ります.
5. firebaseへのhostingの設定
buildしたものをfirebaseにhosting出来る設定をしていきます.
この手順は
Firebase Hosting でWebサイトを公開する方法
こちらの記事などで詳しく解説されていますので、参考にしながら進めると良いと思います.
本記事では簡易的に記述します.
staging用のプロジェクトと、prodcution用のプロジェクトがあるので、両方にエイリアスをつけて設定していきます.
で、staging用のプロジェクトをstag
,
prodcution用のプロジェクトをprod
として登録します.
これで、例えばstaging用にdeployしたい場合は、
firebase use stag
firebase deploy
で実行できます.
ここまでの動作確認
これで、手動であればprodcutionとstagingを分ける事ができます.
手順としては、
1. 任意の環境用にbuildする.
2. firebaseのプロジェクトを切り替える
3. deployする
となります.
例えば、staging環境であれば
yarn build:stag
firebase use stag
firebase deploy
を実行すればOKです.
ここまで手動で想定通りの動きになるか試してみましょう.
うまく行けば、これらをCircleCI上で実現できるようにします.
6..env
に記述した値の移植
2.で作成した.env
ファイルは、gitの管理化には入れないため、CircleCI上の環境変数に必要な値を登録し、build時に.env
ファイルを作成できるようにします.
具体的には、2.で記述したキーと値のセットをそのままCircleCI上のプロジェクトの環境変数に登録します.
7. deploy
のためのキーの設定
CircleCI上からfirebaseのhostingにdeployするためには、キー等を設定する必要があります.
この手順にも、参考になる記事があるのでそちらを参考に進めてください.
Circle CIからFirebase Hostingに自動ビルド&デプロイする
上記記事に従って、
firebase login:ci
により得られたキーをCircleIC上の環境変数に設定します.
但し、今回はprodcution用とstaging用の2つがあるので
firebase use prod
firebase login:ci
で得られたキーをFIREBASE_TOKEN_PROD
とし、
firebase use stag
firebase login:ci
で得られたキーをFIREBASE_TOKEN_STAG
として登録してください.
8. .circleci/config.yml
の記述
最後にcircleCIの設定ファイルを記述していきます.
基本的には、先程手動で行った、
yarn build:stag
firebase use stag
firebase deploy
を実行するような設定をすればOKです.
変更点は、
- 最初にcircleCIの環境変数から.env
を書き出す必要があること
- firebase
コマンドのパスを相対パスで指定すること
- deploy時にキー等を指定すること
の3点です.
必要な部分だけを記述したものが以下になります.
version:2.1orbs:#CircleCIが準備したnode用の設定を元として使うnode:circleci/node@1.1.6commands:make_env:#.envを書き出すコマンドをまとめておくsteps:-run:name:make .envcommand:|echo "FIREBASE_API_KEY_PROD=$FIREBASE_API_KEY_PROD" > .envecho "FIREBASE_AUTH_DOMAIN_PROD=$FIREBASE_AUTH_DOMAIN_PROD" >> .envecho "FIREBASE_DATABASE_URL_PROD=$FIREBASE_DATABASE_URL_PROD" >> .envecho "FIREBASE_MESSAGING_SENDER_ID_PROD=$FIREBASE_MESSAGING_SENDER_ID_PROD" >> .envecho "FIREBASE_PROJECT_ID_PROD=$FIREBASE_PROJECT_ID_PROD" >> .envecho "FIREBASE_STORAGE_BUCKET_PROD=$FIREBASE_STORAGE_BUCKET_PROD" >> .envecho "FIREBASE_API_KEY_STAG=$FIREBASE_API_KEY_STAG" >> .envecho "FIREBASE_AUTH_DOMAIN_STAG=$FIREBASE_AUTH_DOMAIN_STAG" >> .envecho "FIREBASE_DATABASE_URL_STAG=$FIREBASE_DATABASE_URL_STAG" >> .envecho "FIREBASE_MESSAGING_SENDER_ID_STAG=$FIREBASE_MESSAGING_SENDER_ID_STAG" >> .envecho "FIREBASE_PROJECT_ID_STAG=$FIREBASE_PROJECT_ID_STAG" >> .envecho "FIREBASE_STORAGE_BUCKET_STAG=$FIREBASE_STORAGE_BUCKET_STAG" >> .envcat .envjobs:deploy_stag:# staging環境にデプロイする用executor:name:node/defaulttag:"12.13"# 念の為バージョン(正確にはdockerのtag)を指定しておくsteps:-checkout-node/with-cache:steps:-run:yarn install-make_env-run:name:switch firebase project to productioncommand:./node_modules/.bin/firebase use stag-run:name:buildcommand:yarn build:stag-run:name:deploycommand:./node_modules/.bin/firebase deploy --project=$FIREBASE_PROJECT_ID_STAG --token=$FIREBASE_TOKEN_STAGdeploy_prod:# prodction環境にデプロイする用executor:name:node/defaulttag:"12.13"steps:-checkout-node/with-cache:steps:-run:yarn install-make_env-run:name:switch firebase project to productioncommand:./node_modules/.bin/firebase use prod-run:name:buildcommand:yarn build:prod-run:name:deploycommand:./node_modules/.bin/firebase deploy --project=$FIREBASE_PROJECT_ID_PROD --token=$FIREBASE_TOKEN_PRODworkflows:deploy:jobs:-deploy_stag:filters:# stagingブランチの場合はstaging環境へのデプロイbranches:only:staging-deploy_prod:filters:# releaseブランチの場合はrelease環境へのデプロイbranches:only:release
これで、
staging
ブランチにpushされた場合はdeploy_stag
が、
release
ブランチにpushされた場合はdeploy_prod
が実行されるはずです.
意図したとおりに挙動していれば無事終了です.
最後に
これがベストなやり方かどうかは分かりませんが、一応このやり方で特に問題は無いと思います.
方針さえ立てばそれぞれの手順自体は難しくないはずです.
やってみれば大したことないですが、自分はどういう方針で行くか結構手探りで進めたので、この記事が他の誰かのお役に立てれば幸いです.
また、firestore
のルールに関してCircleCI上で走らせるのも少しだけ手間取ったりしたので自分の備忘録のためにもそのうち書きたいと思ってます.
し
参考
環境変数設定は基本cross-envだけどたまにenv-cmdも使う
Firebase Hosting でWebサイトを公開する方法
Circle CIからFirebase Hostingに自動ビルド&デプロイする