はじめに
オープンソースで公開している個人開発プロジェクト「あえるまっぷ」を2人で開発していたとき、こんな問題が出てきました。
-
「自分の環境では動くのに」が起きる
-
本番のFirestoreやAuthを開発用に使うのが怖い
-
cloneした人がすぐ動かせる環境にしたい
OSSとして公開している以上、誰がcloneしても同じように動く環境にしたい。そこで Docker + Firebase Emulator を組み合わせてローカル開発環境を統一しました。
この記事では、その構成と実際の設定をまとめます。
構成の全体像
┌─────────────────────────────────────────┐
│ docker compose │
│ │
│ ┌──────────────┐ ┌───────────────┐ │
│ │ react │ │ firebase │ │
│ │ │ │ Auth :9099 │ │
│ │ :3000 │───>│ Firestore │ │
│ │ │ │ :8080 │ │
│ │ │ │ Functions │ │
│ │ │ │ :5001 │ │
│ └──────────────┘ │ UI :4000 │ │
│ └───────────────┘ │
└─────────────────────────────────────────┘
ポイントはシンプルで、2つのコンテナだけです。
| コンテナ | 役割 |
|---|---|
react |
フロントエンドの開発サーバー |
firebase |
Firebase Emulator一式(Auth / Firestore / Functions) |
本番はFirebase(クラウド)、開発はEmulator(ローカル)と明確に分けることで、開発中に本番データを汚す心配がなくなります。
設定ファイルの中身
docker-compose.yml
version: "3.9"
services:
firebase:
build:
context: .
dockerfile: docker/firebase/Dockerfile
container_name: firebase-emulator
ports:
- "9099:9099" # Auth
- "4000:4000" # Emulator UI
- "5001:5001" # Functions
- "8080:8080" # Firestore
volumes:
- ./firebase:/app
tty: true
react:
build:
context: .
dockerfile: docker/react/Dockerfile
container_name: react-app
ports:
- "3000:3000"
volumes:
- ./app:/app
working_dir: /app
command: sh -c "npm install && npm start"
depends_on:
- firebase
depends_on で firebase コンテナの起動順を先にしています(ただし、Emulator の起動完了までは保証しないため、必要に応じてリトライで吸収します)。
Dockerfile(firebase)
FROM node:18-alpine
# JavaとFirebase CLIをインストール
RUN apk add --no-cache openjdk17 && \
npm install -g firebase-tools typescript
WORKDIR /app
CMD ["sh", "-c", "cd functions && npm install && npm run build && cd .. && firebase emulators:start --project demo-project --only functions,firestore,auth"]
Firebase EmulatorはJavaが必要なので openjdk17 を忘れずに入れています。
firebase.json(Emulator設定)
{
"emulators": {
"auth": {
"port": 9099,
"host": "0.0.0.0"
},
"firestore": {
"port": 8080,
"host": "0.0.0.0"
},
"functions": {
"port": 5001,
"host": "0.0.0.0"
},
"ui": {
"enabled": true,
"port": 4000,
"host": "0.0.0.0"
}
}
}
host: "0.0.0.0" が重要です。 localhost バインドのままだと、コンテナ外(ホストPCや他コンテナ)からアクセスできません。
環境変数(.env.local)
REACT_APP_USE_FIREBASE_EMULATOR=true
REACT_APP_API_KEY=dummy
REACT_APP_AUTH_DOMAIN=localhost
REACT_APP_PROJECT_ID=demo-project
REACT_APP_APP_ID=dummy
REACT_APP_API_BASE_URL=http://localhost:5001/demo-project/us-central1
--project demo-project で起動したEmulatorに合わせて、PROJECT_ID も demo-project に揃えています。Emulator 利用時は実Firebaseに接続しないため、ここではダミー値を使っています(SDK初期化用のプレースホルダです)。
やってよかったこと
誰がcloneしても docker compose up で動く
OSSとして公開している以上、初めて触れる人でもすぐ動かせることが大事です。必要な前提(Docker / Docker Compose)が揃っていれば、Firebase CLIのバージョン差異や手元の環境差を気にせず、コマンド1つで同じ状態を再現できるようになりました。
本番データを汚さない
開発中のテストデータや誤ったセキュリティルールの検証を、本番のFirestoreに向けてやってしまうリスクがなくなります。Emulatorのデータはコンテナを落とせばリセットされるので、気軽に試せます。
Emulator UIで状態を確認しやすい
localhost:4000 でEmulator UIが開き、Firestoreのドキュメントの中身やAuthのユーザー一覧をブラウザ上で確認できます。デバッグが格段に楽になります。
まとめ
Docker + Firebase Emulatorの組み合わせで、「誰でもcloneしてすぐ動く」環境を実現できました。
設定のポイントは次の2つです。
-
firebase.jsonのhostを0.0.0.0にする(コンテナ外からアクセスするため) -
起動コマンドで
--project demo-projectを指定し、環境変数と合わせる
本番のインフラ選定やセキュリティ設計については前回の記事をご覧ください。