GAミント至上主義

Web Monomaniacal Developer.

開発用Dockerコンテナ内でVueアプリケーションをFirebase Hosting に1コマンドでdeployする

Vue + Webpackでの開発は社内サーバーのDockerコンテナで行っているが、ビルドしたファイルはFirebase Hositingを使って配信したくなった。

どうせならfireabase CLIもホストには入れずDockerコンテナ上にインストールしてやってしまいたいと思い、やってみたら出来たのでメモ。

Vue + Webpackは下記テンプレートではじめて大きく変更はしていない。

1、 開発用Dockerコンテナ
まず下記のようなnodeと最低限のDockerから始める。gitとbzip2はnpm installで必要だった気がする。
shanyangはプロジェクト名なのでなんでもいい(ヤギの中国語ピンイン)。appも特に意味はない。

FROM node:9-slim
RUN mkdir /shanyang/
RUN apt-get update --fix-missing && apt-get -y upgrade

RUN apt-get install -y \
    git \
    bzip2

RUN npm install -g vue-cli firebase-tools

COPY app /shanyang/app
WORKDIR /shanyang/app/
EXPOSE 8080
CMD ["bash"]

npmでいれるものはDockerfileでやっていると開発中は頻繁にビルドが必要になって面倒なので、appディレクトリをマウントしておき、そこでインストールしてその状態を保存する。

Dockerfileにまとめたいところだけど、npmはpakage.jsonがあるのでnpm install時に--saveを付けてそちらで管理することにした。


頻繁にいちいちdockerコマンドをたくさんオプション付けるのは面倒なので、コンテナごとに下記のようにshを作って実行している。当たり前だけどchmod 700等で実行権限を付ける。
build.sh

sudo docker build -t varuna-shanyang:latest .

こっちもshで実行。
run.sh

sudo docker run -it --rm \
        -v `pwd`/app:/shanyang/app \
        -v `pwd`/home:/root \
        -p 8080:8080 \
        --name varuna-shanyang \
        varuna-shanyang:latest

/homeのマウントは認証情報のためなので後述する。

runするとbashが立ち上がるのでvue-cliを使ってプロジェクトを生成する。
GitHub - vuejs-templates/pwa: PWA template for vue-cli based on the webpack template

あとはnpm run devで開発中サーバーを起動したり、Vueの開発をホストのappディレクトリ内で行う。開発サーバーはファイルの変更があると自動でリロードしてくれるので便利。


2、Firebase CLIをコンテナ上でインストール

で、アプリができてnpm run buildするとapp/dist配下にproductionのファイルが書き出されると思う。

そうしたらようやく、Firebase Hostingにデプロイ。

Hosting を使ってみる  |  Firebase

コンテナを上記のrun.sh(起動中だったらexec)でbashを起動し、その中でfirebase CLIのセットアップを始める。

まずはログインだが、デフォだとWEBサーバーが起動してブラウザ経由になるが、ホストにそのためだけにポートを通すのが面倒なので端末上で完結できるように--no-localhostを使う

% ./run.sh
root@9e9b076ba98b:/shanyang/app# firebase login --no-localhost

URLが出るのでブラウザで開くとコードがもらえるので貼れば認証完了。

次にinitする

root@c28d3a32cb7b:/shanyang/app# firebase init

     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

You're about to initialize a Firebase project in this directory:

  /shanyang/app

Before we get started, keep in mind:

  * You are currently outside your home directory
  * You are initializing in an existing Firebase project directory

? Which Firebase CLI features do you want to setup for this folder? Press Space to select features, then Enter to confirm your choices.
 ◯ Database: Deploy Firebase Realtime Database Rules
 ◯ Firestore: Deploy rules and create indexes for Firestore
 ◯ Functions: Configure and deploy Cloud Functions
❯◯ Hosting: Configure and deploy Firebase Hosting sites
 ◯ Storage: Deploy Cloud Storage security rules

とりあえず今回はHostingだけチェックして進む。

公開ディレクトリを聞かれるので、今回はdistディレクトリなのでdistと入力。もちろんwebpackの設定で変更しても良い。
vue-routerを使ったSPAなのでyes、
index.htmlは上書きされたくないのでNo

? What do you want to use as your public directory? dist
? Configure as a single-page app (rewrite all urls to /index.html)? Yes
? File dist/index.html already exists. Overwrite? No
i  Skipping write of dist/index.html

i  Writing configuration info to firebase.json...
i  Writing project information to .firebaserc...

✔  Firebase initialization complete!

これでfirebase deployを叩き、正常にデプロイできるか確認する。

完了かと思ったが、コンテナを起動し直すと認証情報が消えてしまい再度ログインが必要になってしまった。
書き出されたfirebase.json、.firebasercにはそれらしい情報は含まれていなかった。

おそらく、ユーザーディレクトリに入っていると思い、/rootを見に行くと.configディレクトリがあり、そこに格納されていたので、これもマウントしてホストマシンで持ってしまえばいい。
ということで上記のrun.shに含まれている。

これで認証情報も保持されるようになったので、あとはデプロイ用にコマンドを書く。
開発サーバーは起動している前提なのでexecを使う。


firebase_deploy.sh

sudo docker exec -it \
    $(sudo docker ps -a -q --filter="name=varuna-shanyang") \
    npm run build

sudo docker exec -it \
    $(sudo docker ps -a -q --filter="name=varuna-shanyang") \
    firebase deploy

不格好だけどnpm run build && firebase deployだとダメだったので2行書いた。

$(sudo docker ps -a -q --filter="name=varuna-shanyang") はよく使う。毎回docker psで手でIDをコピペするのが面倒なのでnameを元に取得するようになっている。

これでDockerコンテナ内でビルドしてデプロイが一発でできるようになった。