【Firebase】Firebase EmulatorをDocker上で起動する

割と既出かもしれませんが、DockerでFirebase Emulatorを動かしてみました。しかし、終了時のexportなどちょい手こずった箇所があったのでまとめてみます。

2024年03月13日
関連記事

毎度のこと、このリポジトリを使用して作業を進めていきます。

前提

  • DockerでFirebaseEmulatorを動かしたい人
  • Firebase Emulatorのセットアップが完了していること(firebase.jsonを確認)
  • Firebase Storageのセットアップが完了していること
  • Firebase Authのセットアップが完了していること

ディレクトリ構成

詳細はこちらをご覧ください

containers/
├── Dockerfile
├── bin
├── config
├── data
├── export.sh
└── start_firebase.sh
docker-compose.yml
package.json
yarn.lock
node_modules
.output
.firebaserc
firebase.json
firestore.indexes.json
firestore.rules
storage.rules

Dockerfile

エミュレーターを動かすだけなので、基本的にこのままでいいと思います。

FROM ubuntu:20.04

RUN apt update && \
    apt install -y ca-certificates-java && \
    update-ca-certificates -f && \
    apt install -y curl openjdk-17-jdk && \
    curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
    apt install -y nodejs imagemagick

RUN npm install -g yarn firebase-tools

RUN ln -sf /usr/share/zoneinfo/Japan /etc/localtime

docker-compose.yml

コンテナ名やvolumesは各々お好きなように。
ちなみにFirebase Functionsには対応させておりませんのでご了承を。

version: '3.9'

services:
  firebase:
    container_name: study-firebase
    build:
      context: .
      dockerfile: ./containers/Dockerfile
    volumes:
      - ./package.json:/usr/src/app/package.json
      - ./yarn.lock:/usr/src/app/yarn.lock
      - ./node_modules/:/usr/src/app/node_modules
      - ./.output/:/usr/src/app/.output
      - ./.firebaserc:/usr/src/app/.firebaserc
      - ./firebase.json:/usr/src/app/firebase.json
      - ./firestore.indexes.json:/usr/src/app/firestore.indexes.json
      - ./firestore.rules:/usr/src/app/firestore.rules
      - ./storage.rules:/usr/src/app/storage.rules
      - ./containers/:/usr/src/app/containers
      - ./containers/bin/:/root/.cache:cached
      - ./containers/config/:/root/.config:cached
    ports:
      - 9099:9099 # Firebase Authentication
      - 8080:8080 # Cloud Firestore
      - 5000:5000 # Firebase Hosting
      - 9199:9199 # Cloud Storage
      - 4000:4000 # Emulator Suite UI
      - 9150:9150 # Firestore Emulator UI websocket
    working_dir: /usr/src/app
    command: ./containers/start_firebase.sh ${EXPORT_INTERVAL}
    tty: true

もし認証情報が必要な場合は以下のコマンドを。

docker compose run --rm firebase firebase login --no-localhost

ちょっとした問題点

通常、エミュレータ起動のコマンドの引数に--export-on-exitをつければ、終了時にエクスポートできるのですが…

どうにも再起動時にデータが保存されていないようで、各所で悲鳴が上がっています。

定期的にexportする

docker-compose.ymlにも記載しましたが、./containers/start_firebase.sh ${EXPORT_INTERVAL} としています。

ちょっと力技な気がしますが、デフォルトで60秒おきに。EXPORT_INTERVAL=0とすると保持しないようにしています。

#! /bin/bash

SCRIPT_DIR="$(dirname "$0")"
BASE_DIR="$(dirname "$SCRIPT_DIR")"
DATA_DIR="${BASE_DIR}/containers/data"

# Set export interval
EXPORT_INTERVAL=${1:-60}
if ! [[ $EXPORT_INTERVAL =~ ^[0-9]+$ ]]; then
  echo "デフォルトの60秒に設定します。"
  EXPORT_INTERVAL=60
fi

echo "INTERVAL: ${EXPORT_INTERVAL}"

# Javaオプションを設定し、Firebaseエミュレータを起動
export JAVA_TOOL_OPTIONS="-Xms4g -Xmx8g"
TZ=JST firebase emulators:start --project=default --import="${DATA_DIR}" &

# エミュレータが起動したかどうかをチェック
EMULATOR_URL="http://127.0.0.1:4000"
MAX_RETRIES=5
for ((i=1; i<=MAX_RETRIES; i++)); do
  sleep 5
  if curl -LI "${EMULATOR_URL}" -o /dev/null -w '%{http_code}\n' -s | grep -q "200"; then
    echo "Firebaseエミュレータが起動しました。"
    break
  fi
  echo "エミュレータの起動を待っています... 試行回数 $i / $MAX_RETRIES"
done

# スクリプト終了時の処理関数
cleanup() {
  echo "Firebaseエミュレータを停止しています..."
  firebase emulators:export "${DATA_DIR}"
  exit
}

# シグナルトラップの設定
trap cleanup SIGINT SIGTERM

# 定期的なエクスポート
while [ ${EXPORT_INTERVAL} -ne 0 ]; do
  sleep "${EXPORT_INTERVAL}"
  "${SCRIPT_DIR}/export.sh"
done

wait

エクスポート用のスクリプトは以下の通り。

#! /bin/bash

SCRIPT_DIR="$(dirname "$0")"
BASE_DIR="$(dirname "$SCRIPT_DIR")"
DATA_DIR="${BASE_DIR}/containers/data"

firebase emulators:export -f ${DATA_DIR}

おわり

今後この環境で認証、テストなどを書いていきます。
今回の記事では要点のみを書いておりますので、試したい方はこちらのリポジトリをご参考にどうぞ。

筆者情報
IT業界経験6年目のフルスタックエンジニア。
フロントエンドを軸として技術を研鑽中でございます。