はじめに
firebase functionsを用いて手軽にAPIを公開したいと思い、ローカル開発環境構築を行いましたので、その構築メモを記載しました。
API開発に向けてローカルでの開発環境を構築するためには、firebase CLIをインストールし、設定をしなければいけません。
しかし、以下3点の理由からdockerコンテナ内で開発できる環境を用意することにしました。
- ローカル環境を汚したくない
- 環境依存しない形で書きたい
- (将来的に)別のfirebaseアカウントに簡単に切り替えられるようにしておきたい
前提条件
- docker, docker-composeがインストールされていること
ファイルの準備
フォルダ構成
今回は環境変数を.envファイルでまとめて管理できるような構成にしました。
/
┝ firebase/
│ └ Dockerfile
┝ .env
└ docker-compose.yml
docker-composeファイル
$で始まる変数は、後述の.envファイルから読み取っています
version: '3'
services:
firebase:
build:
context: ./firebase
args:
WORKDIR: $WORKDIR
volumes:
- ./firebase:/$WORKDIR
ports:
- "$FIREBASE_CLI_PORT:$FIREBASE_CLI_PORT"
- "$FIREBASE_UI_PORT:$FIREBASE_UI_PORT"
- "$FIREBASE_FUNCTIONS_PORT:$FIREBASE_FUNCTIONS_PORT"
tty: true
Dockerfile
コンテナ内でfirebase CLI(firebase-tools)をインストールしています。
FROM node:14-alpine
ARG WORKDIR
ENV HOME=/${WORKDIR} \
LANG=C.UTF-8 \
TZ=Asia/Tokyo \
HOST=0.0.0.0
WORKDIR ${HOME}
RUN yarn global add firebase-tools
CMD ["/bin/sh"]
.envファイル
これは好みですので直接docker-composeファイルに書いてもOKです。
ここでは、ポート番号やフォルダ等の設定を変数として.envファイルで管理し、docker-composeで読み込むようにしています。
WORKDIR=app
FIREBASE_CLI_PORT=9005
FIREBASE_FUNCTIONS_PORT=5001
FIREBASE_UI_PORT=4000
9005: firebase CLIの設定時の通信ポート
5001: firebase functions通信ポート
4000: firebase エミュレータをブラウザから見られるようにする
これらのポートを開けておくことで、ゲストOSとfirebaseへの接続、ホストOSからゲストOSへのAPI接続確認が可能になります。
dockerコンテナ立ち上げ
docker-composeをビルド・立ち上げ
docker-compose build
docker-compose up -d
コンテナ内に入る
※ベースのdockerイメージにalpineを利用したためashコマンドになっている
docker-compose exec firebase ash
以降の手順はdockerコンテナ内で行う
コンテナ内でのfirebase設定
今回はdocker-compose.ymlの設定によりワークスペースのパスを/appにしているため、/app/firebase直下でfirebase CLIコマンドを実行します
cd /app/firebase
firebase login
firebase init functions
これで/app/firebase 下にファイルが作成されます。
サーバを立ち上げる前に、firebase.jsonを以下のように変更することで、ホストOSからアクセスできるようにしておきます。
※ハマりポイント
ホストOSからlocalhostでアクセスする場合は、
ゲストOS内のfirebase APIが0.0.0.0でlistenするようにしなければならない
{
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint",
"npm --prefix \"$RESOURCE_DIR\" run build"
]
},
"emulators": {
"functions": {
"host": "0.0.0.0",
"port": 5001
},
"ui": {
"enabled": true,
"host": "0.0.0.0",
"port": 4000
}
}
}
サーバ実行
このままでも実行することはできますが、一つのfunctionsに対し1つしかAPIを定義できません。そのため、expressライブラリを利用し複数APIを作成できるようにしました。今回は例として、indexファイルを以下のように書き換え、/helloへアクセスするとHello Express!と表示するAPIを作成しました。
import * as functions from "firebase-functions";
const express = require("express");
const app = express();
app.get('/hello', (req:any, res:any) => {
// レスポンスの設定
res.send('Hello Express!');
});
const api = functions.https.onRequest(app);
module.exports = { api };
以下コマンドを実行して立ち上がるか確認します。
npm run serve
立ち上がると以下のような文字がコンソールに出力されます。
i ui: Emulator UI logging to ui-debug.log
i functions: Watching "/app/functions" for Cloud Functions...
✔ functions[us-central1-api]: http function initialized (http://0.0.0.0:5001/xxx).
ここで http://0.0.0.0:5001/xxx がapiのベースurlになります。
最後にホストOSのブラウザからhttp://0.0.0.0:5001/xxx/hello へアクセスして、ブラウザ上で"Hello Express!"と表示されれば完了です。