17
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

2020年にDockerでFirebaseアプリの開発環境を構築してみた

Last updated at Posted at 2020-12-21

この記事は「【マイスター・ギルド】本物の Advent Calendar 2020」15日目の記事です。


ちょっと前ですがWindows System for Linux2(WSL2)がリリースされました。これでWindows上でLinuxを動かすことができます。
それともう一つ、WSL2にすることでHomeなWindowsでもDocker Desktop for Windowsを使うことができます。案外これは知らない人もいるかもしれません。
Homeな私はこれまでDocker ToolBoxを使ってましたが、あまり良い体験とは言えず、Dockerに対してのモチベーションがあまりありませんでした。
しかしDocker Desktop for Windowsを使ったところ、非常に使いやすかったので、DockerでFirebase Cloud FunctionsをバックエンドにしたTSアプリを開発する環境を構築してみました。フロントはVue.jsにしてみます。これはそれの結果をまとめた記事になります。

↓はこの記事で説明する環境構築に関係のあるファイルのディレクトリ構成図です。もちろんこれ以外にソースファイルやアプリケーションの設定ファイルがあります。

ディレクトリ構成図
.
├──app
│  ├──functions
│  │  ├──lib
│  │  ├──node_modules
│  │  ├──.dockerignore
│  │  ├──copy-node_modules.sh
│  │  ├──Dockerfile
│  │  └──package.json
│  │     
│  ├──vuejs
│  │  ├──dist
│  │  ├──node_modules
│  │  ├──.dockerignore
│  │  ├──copy-node_module.sh
│  │  ├──Dockerfile
│  │  └──vue.vonfig.js
│  │
│  └──firebase.json
│
├──swagger
│  └──index.yml
│
└──docker-compose.yml

Dockerコンテナ群は↓のようになります。
image.png

ちなみに今回はたまたまDBを使わないアプリの開発でした。DBを使う場合、FirebaseのCloud Firestoreなんかを使う場合はおそらくこの構成のままですが、もしMySQLなんかが必要になる場合はdbのコンテナが追加されると思います。

TSアプリの開発がほとんど今回初めてだったのですが、Dockerで開発環境を構築する場合、次の問題に当たりました。

  • TSのビルド先をWindowsと共有するとホットリロードが効かない
  • node_modulesをWindowsと共有するとビルドがめっちゃ遅い
  • *.d.tsがエディタ側に無いと開発時に型の恩恵が受けられない

またFirebaseの次の仕様も頭を悩ませました。

  • エミュレーターを立ち上げるとAPIにプロジェクト名/リージョン名/のプレフィックスが付く

では、それぞれのコンテナを見ていきます。

firebaseコンテナ

package.json
"scripts": {
  ...
  "emulators": "tsc-watch --onFirstSuccess \"firebase emulators:start --token ${FIREBASE_TOKEN}\""
  ...
},
...
"dependencies": {
  ...
  "firebase-admin": "^9.2.0",
  "firebase-functions": "^3.6.1",
  ...
}
...
"devDependencies": {
  ...
  "tsc-watch": "^4.2.9"
  ...
}

Firebase CLIのCloud Functions Emulatorsを利用します。tsc-watchを導入してホットリロードで開発できるようにします。

$ npm run emulators

でホットリロードしつつ開発が行えるエミュレーターが立ち上がります。

firebase.json
...
  "hosting": {
    "public": "vuejs/dist",
    ...
    "rewrites": [
      {
        "source": "/get-users",
        "function": "get-users"
      }
    ]
  },
  "emulators": {
    "functions": {
      "host": "0.0.0.0",
      "port": 5001
    },
    "hosting": {
      "host": "0.0.0.0",
      "port": 5000
    },
    "ui": {
      "enabled": true,
      "host": "0.0.0.0",
      "port": 4000
    }
  }
...

Firebaseの設定です。
hostingではまず公開ディレクトリをVue.jsのデフォルトのビルド先に指定しています(public)。rewritesでは/~にアクセスすることでCloud Functionsの各関数を呼び出せるようにしています。これはCloud Functions Emulatorsで用意されるAPIのエンドポイントにはプレフィックスにプロジェクト名、リージョン名が付くのですが、SwaggerからAPIを叩くときにこのプレフィックス部分を無視したいからです(Swaggerのymlファイルにプロジェクト名、リージョン名を書きたくない)。APIが増えればここに追記する必要が出てきます。
emulatorsではDocker外からアクセスできるようにhostを指定しているのと、Cloud Functions EmulatorsのUI画面を有効にし、一番小さいポート番号が割り当たるようにしています。あまり使わないかもですが、これでDocker Desktop for Windowsの「OPEN IN BROWSER」でエミュレーターのダッシュボード的な画面が開くようになります。

docker-compose.yml
volumes:
  firebase-node_modules:
  firebase-lib:

services:
  firebase:
    build: ./app/functions
    image: firebase
    container_name: firebase
    ports:
      - 4000:4000
      - 5000:5000
      - 5001:5001
    volumes:
      - ./app:/app
      - firebase-lib:/app/functions/lib
      - firebase-node_modules:/app/functions/node_modules
    environment:
      - FIREBASE_PROJECT
      - FIREBASE_TOKEN

node_modulesはホストと共有したくないので、別にvolumesを作ってそこに保持するようにしています。TSのトランスパイル後のコードもホスト側と共有するとホットリロードを妨げるので、同様にしています。
FIREBASE_TOKENはログイン不要でFirebase CLIを叩くためのものです。取得方法は https://firebase.google.com/docs/cli?hl=ja#cli-ci-systems にあります。

Dockerfile
FROM node:10

RUN apt-get update && \
  npm install -g firebase-tools

WORKDIR /app/functions

COPY package*.json ./

CMD npm install \
  && firebase use ${FIREBASE_PROJECT} --token ${FIREBASE_TOKEN} \
  && npm run emulators

EXPOSE 4000 5000 5001
  1. firebase-toolsのインストール
  2. npmパッケージのインストール
  3. Firebaseプロジェクトの設定
  4. エミュレーター(ホットリロード有)の起動

を行っています。ここでpackage*.jsonをコピーしているのは、docker-compose.ymlで書いたvolumesのマウントがDockerfileの内容の処理の後になるので、まだDocker内に無いからです。

.dockerignore
node_modules

ホストのnode_modulesは不要なので、.dockerignoreに書いておきます。

copy-node_modules.sh
#! /bin/bash

SCRIPT_DIR=$(cd $(dirname $0); pwd)

docker cp -a -L firebase:/app/functions/node_modules $SCRIPT_DIR

ホストのVSCodeで開発をするために、Dockerコンテナ内でインストールした.d.tsファイルをホスト側にコピーしてくるスクリプトです。docker cpコマンドで拡張子指定とかできると良いんですが、出来ないのでnode_modulesをまるっと持ってきてます。時間かかります。さらにシンボリックリンク関係と思いますが、管理者権限での実行が必要です。

本当はVSCodeのRemote WSLプラグインでDockerコンテナ内に接続して開発したいんですが、まだPreview版で動作が安定しないのか、私の環境では頻繁にフリーズしてしまいます…。正式版になったら、またトライしたいと思います。これがうまく使えれば、このスクリプトは不要になりますね。

firebaseコンテナを立ち上げると、OPEN IN BROWSERからエミュレーターのUIへアクセスできます。
image.png

swaggerコンテナ

docker-compose.yml
services:
  # 他の設定...
  swagger:
    image: swaggerapi/swagger-ui
    container_name: swagger
    ports:
      - 8000:8080
    volumes:
      - ./swagger:/var/www
    environment:
      SWAGGER_JSON: /var/www/index.yml

./swagger/index.ymlファイルを、ホスト側8000ポートで見れるようにします。

swaggerコンテナを立ち上げると、OPEN IN BROWSERからSwagger UIへアクセスできます。
image.png
このコンテナは単純にindex.ymlを公開しているだけなんで、シンプルですね。

vuejsコンテナ

docker-compose.yml
volumes:
  # 他の設定...
  vuejs-node_modules:

services:
  # 他の設定...
  vuejs:
    build: ./app/vuejs
    image: vuejs
    container_name: vuejs
    ports:
      - 3000:3000
      - 3001:3001
    volumes:
      - ./app:/app
      - vuejs-node_modules:/app/vuejs/node_modules
    environment:
      - CHOKIDAR_USEPOLLING=true

3000ポートをVue CLI UI用、3001ポートをserve用にします。
こちらでもはやりnode_modulesはホストと共有したくないので別volumesで回避します。
環境変数のCHOKIDAR_USEPOLLINGはserveでホットリロードするために必要になるもののようです。

Dofkerfile
FROM node:10

RUN apt-get update && \
    npm install -g @vue/cli

WORKDIR /app/vuejs

COPY package*.json ./

CMD npm install \
    && vue ui --host 0.0.0.0 --port 3000

EXPOSE 3000 3001

Vue CLIをインストールし、vue uiコマンドのオプションで以下を指定しています

  • --host 0.0.0.0 Dockerコンテナの外からでもWebUIにアクセスできるようにする
  • --port 3000 3000ポートでWebUIを立ち上げる
.dockerignore
node_modules

こちらもホストのnode_modulesは不要なので、.dockerignoreに書いておきます。

vue.config.js
module.exports = {
    devServer: {
        port: 3001,
        host: '0.0.0.0'
    }
}

serveで立ち上げるサーバーのオプションをvue uiと同様な感じで指定します。

copy-node_modules.sh
#! /bin/bash

SCRIPT_DIR=$(cd $(dirname $0); pwd)

docker cp -a -L vuejs:/app/vuejs/node_modules $SCRIPT_DIR

firebaseコンテナと同じくホストのVSCodeで開発をするために、Dockerコンテナ内でインストールした.d.tsファイルをホスト側にコピーしてくるスクリプトです。時間かかります。管理者権限での実行が必要です。

vuejsコンテナを立ち上げると、OPEN IN BROWSERからVue CLI UIへアクセスできます。
image.png

以上、Dockerを使ったFirebase+Vue.js+TSアプリの開発環境構築でした。今後の各ツールのバージョンアップによってここの内容は変わりそうですが、2020/12時点ではこんな感じになりましたという記事でした。Docker便利ですね。

17
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?