tag:crieit.net,2005:https://crieit.net/users/dorakueyon/feed dorakueyonの投稿 - Crieit Crieitでユーザーdorakueyonによる最近の投稿 2019-12-30T14:15:44+09:00 https://crieit.net/users/dorakueyon/feed tag:crieit.net,2005:PublicArticle/15658 2019-12-30T14:15:44+09:00 2019-12-30T14:15:44+09:00 https://crieit.net/posts/Firebase-Vue-js-Cloud-Functions-docker-compose Firebase フロントエンド(Vue.js)/Cloud Functions を同一docker-composeで実行する際に感じたこと <h2 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h2> <p>2019/12/30現在において、Firebaseを開発する際に生じる不都合の一つとして、node version管理があると思います.</p> <p>Cloud Functionsの開発において、nodeのバージョンはversion8、あるいは10がサポートされています.</p> <blockquote> <p>Cloud Functions ランタイムに関数をデプロイするには Firebase CLI が必要です。Node.js バージョン 8 と 10 がサポートされています。Node.js と npm をインストールする場合は、Node Version Manager をおすすめします。<br /> <a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/functions/get-started?hl=ja">https://firebase.google.com/docs/functions/get-started?hl=ja</a></p> </blockquote> <p>つまり、こんなことが頻発します.</p> <pre><code class="bash">[dorakueyon]% yarn build yarn run v1.19.2 error functions@: The engine "node" is incompatible with this module. Expected version "8". Got "10.15.3" error Commands cannot run with an incompatible environment. info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command. </code></pre> <p>このように、異なるversionが依存する開発では、その依存性をDockerに閉じ込めることで幸せになれます.</p> <p>参考として、githubにcodeを置かせていただきました.<br /> - <a target="_blank" rel="nofollow noopener" href="https://github.com/dorakueyon/vue-firebase-cloud-function-docker-starter">github.com/dorakueyon/vue-firebase-cloud-function-docker-starter</a></p> <h2 id="Vue.js + Cloud Functionsのフォルダ構成"><a href="#Vue.js+%2B+Cloud+Functions%E3%81%AE%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E6%A7%8B%E6%88%90">Vue.js + Cloud Functionsのフォルダ構成</a></h2> <p>Docker化する前に、プロジェクトを作成した上でフォルダ構成をみてみます.</p> <ul> <li>Vue.js + Firebaseプロジェクト作成</li> </ul> <pre><code class="bash">$ vue create project-name $ firebase init </code></pre> <ul> <li>フォルダ構成 (node_modules配下を除いています)</li> </ul> <pre><code class="bash">. ├── README.md ├── babel.config.js ├── firebase.json ├── functions │   ├── node_modules │   ├── package-lock.json │   ├── package.json │   ├── src │   └── tsconfig.json ├── node_modules ├── package.json ├── public │   ├── favicon.ico │   └── index.html ├── src │   ├── App.vue │   ├── assets │   ├── components │   ├── main.ts │   ├── router │   ├── shims-tsx.d.ts │   ├── shims-vue.d.ts │   └── views ├── tsconfig.json └── yarn.lock </code></pre> <p>FrontとCloud Functionsを開発する場合、プロジェクト直下と./funcions直下とで開発環境が分かれます.</p> <p>それぞれにDockerfileを配置した上で、プロジェクト直下にdocker-compose.ymlを配置します.</p> <ul> <li>Dockerファイルを追加したフォルダ構成 (node_modules配下を除いています)</li> </ul> <pre><code class="bash">. ├── Dockerfile <- ├── README.md ├── babel.config.js ├── docker-compose.yml <- ├── firebase.json ├── functions │   ├── Dockerfile <- │   ├── node_modules │   ├── package-lock.json │   ├── package.json │   ├── src │ │ ├── index.ts │ │ └── services │ │ └── project-name -> ../../../src/services/project-name <- シンボリックリンク │   └── tsconfig.json ├── node_modules ├── package.json ├── public │   ├── favicon.ico │   └── index.html ├── src │   ├── App.vue │   ├── assets │   ├── components │   ├── main.ts │   ├── router │ ├── services │ │   └── project-name <- シンボリックリンク先 │ │   └── constants.ts │   ├── shims-tsx.d.ts │   ├── shims-vue.d.ts │   └── views ├── tsconfig.json └── yarn.lock </code></pre> <h2 id="Docker化"><a href="#Docker%E5%8C%96">Docker化</a></h2> <p>Docker化にむけて、下記の要件があります.</p> <ul> <li>プロジェクト直下のfirebase関連ファイル(firebase.json, .firebaserc)を、./functions側でも参照したい</li> <li>./functions側からプロジェクト直下の定数やtypeをシンボリックリンクで参照する場合がある</li> </ul> <p>上記を念頭に、<code>Dockerfile/docker-compose.yml</code>を作成します.</p> <h3 id="プロジェクト直下のDockerfile"><a href="#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E7%9B%B4%E4%B8%8B%E3%81%AEDockerfile">プロジェクト直下のDockerfile</a></h3> <ul> <li>こちらは特に考えることはありません</li> </ul> <pre><code class="Docker">FROM node:12-alpine ENV WORKDIR /work WORKDIR $WORKDIR COPY package.json $WORKDIR RUN yarn COPY tsconfig.json $WORKDIR COPY *.config.js $WORKDIR/ COPY public $WORKDIR/ COPY src $WORKDIR/src EXPOSE 8080 CMD yarn serve </code></pre> <h3 id="./functionsのDockerfile"><a href="#.%2Ffunctions%E3%81%AEDockerfile">./functionsのDockerfile</a></h3> <p>./functions/Dockerfileと、./docker-comose.ymlを比較しながらご確認ください.</p> <ul> <li>WORKDIRを<code>/work/functions</code>とする</li> <li>./functions直下のファイルCOPYは、コピー元をプロジェクト直下からの相対パスで指定する</li> <li>プロジェクト直下のファイルCOPYは、コンテナの<code>/work</code>配下に設置する</li> </ul> <pre><code class="Docker">FROM node:8-alpine ENV WORKDIR /work/functions WORKDIR $WORKDIR COPY ./functions/package.json $WORKDIR RUN yarn # firebase RUN yarn global add firebase-tools COPY ./functions/tsconfig.json $WORKDIR COPY ./functions/lib $WORKDIR/lib COPY ./functions/src $WORKDIR/src # # for symbolic link (./functions/src/services/project-name) # COPY ./src/services/project-name /work/src/services/project-name # firebase COPY firebase.json /work COPY .firebaserc /work # COPY ./functions/.runtimeconfig.json $WORKDIR # if needed # COPY ./functions/credentials $WORKDIR/credentials # if needed # settings for runtime emulator ENV HOST 0.0.0.0 EXPOSE 5000 EXPOSE 9005 </code></pre> <h3 id="プロジェクト直下のdocker-compose.yml"><a href="#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E7%9B%B4%E4%B8%8B%E3%81%AEdocker-compose.yml">プロジェクト直下のdocker-compose.yml</a></h3> <ul> <li>上記Cloud FunctionsのDockerfileにあわせるため<code>build:</code>のcontext, dockerfileを別に指定する</li> <li>symbolic linkされている(プロジェクト直下にある)実体ファイルの変更もfunctions側のdockerに反映させるため、<code>./src:/work/src</code>を追加</li> </ul> <pre><code class="Docker">version: '3' services: main: build: . container_name: front volumes: - ./public:/work/public - ./src:/work/src ports: - 8080:8080 tty: true command: yarn serve functions: build: context: ./ dockerfile: ./functions/Dockerfile container_name: functions volumes: - ./functions/lib:/work/functions/lib - ./functions/src:/work/functions/src - ./src:/work/src # for symbolic link # environment: # - GOOGLE_APPLICATION_CREDENTIALS=./credentials/firebase-adminsdk.json ports: - 5000:5000 - 9005:9005 tty: true </code></pre> <h2 id="開発の場合"><a href="#%E9%96%8B%E7%99%BA%E3%81%AE%E5%A0%B4%E5%90%88">開発の場合</a></h2> <p>開発環境立ち上げます</p> <pre><code class="bash">$ docker-compose build && docker-compose up </code></pre> <p>その後の開発は下記のようにすすめます</p> <h3 id="front"><a href="#front">front</a></h3> <p><code>http://localhost:8080</code>にVue.jsプロジェクトがホットリロードされます</p> <h3 id="Cloud Functions"><a href="#Cloud+Functions">Cloud Functions</a></h3> <p>こちらは多少面倒ではあります</p> <ol> <li>dockerコンテナに入る</li> <li>firebase loginしていなければfirebase loginを実施</li> <li>firebase serveやfirebase functions:shellなどでdebugging</li> </ol> <p>以下 <code>docker exec functions -it sh</code> してコンテナ内で</p> <pre><code>$ firebase login # if you are not logged in. $ firebase serve $ firebase functions:shell </code></pre> <p>Cloud Functionsのデバッグについてはまだペインが多いです..</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://firebase.google.com/docs/functions/local-shell?hl=ja">関数をインタラクティブにテストする(Firebase official)</a></li> </ul> <p>firebase loginの認証情報を永続化(都度<code>fireabase login</code>したくない)人は下記のサイトが参考になるかもしれません(試していません..)</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/pannpers/items/244a7e3c18d8c8422e4f">[Firebase] Cloud Functionsで消耗したくない人のために、開発環境のベストプラクティスをまとめていったらDockerに行き着いた話</a></li> </ul> <h2 id="deploy"><a href="#deploy">deploy</a></h2> <ul> <li>github actions/ circleCIなど利用したほうがよいでしょう.</li> </ul> <h2 id="おわりに"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a></h2> <p>少し強引な形となってしまいましたが、Dockerの恩恵をうけることができる状態までできました.<br /> ただし、<code>./functions/Dockerfile</code>のフォルダのコンテキストが親階層直下にある点に気持ち悪さがあります.</p> <p>ここの気持ちわるさの解消は今後の課題とします.</p> dorakueyon