質問: 実現したいこと ------- VSCodeを使用してexpress.jsアプリの開発を行っています。 コンテナ内のみにnode_modulesが存在する場合、VSCodeがライブラリを発見できなくて インテリセンスが動かない(下記画像のように`Cannot find module 'xxx'`となる)ため、 `docker-compose build` した際に出来上がるコンテナ内のnode_modulesをホスト側に同期し、 コンテナ内で`npm install`をするたびにホスト側にも反映されるようにしたいです。 ![ライブラリが発見できない](https://teratail-v2.storage.googleapis.com/uploads/contributed_images/b5b25b578da67d6555d93025949a7cae.png) 手っ取り早い方法としてはホスト側でも`npm install`するという方法もあるかと思いますが、 ライブラリ更新のたびにホストとコンテナで二重に実行する必要があるのでできれば避けたいです。 また、ホスト側のNode.jsバージョン等の影響をコンテナ側に持ち込みたくないため、同期の方向は ホスト→コンテナではなくコンテナ→ホストとしたいです。 現状のDockerfileとdocker−composeファイル -------------------------------- ### Dockerfile npm installコマンドはキャッシュが効くようにアプリコードより先に単体でコピーしています。 ``` FROM node:10.11.0-alpine ENV APP_ROOT /app/ WORKDIR $APP_ROOT # アプリコードの変更の影響を受けないように先にコピー COPY package*.json $APP_ROOT RUN npm install COPY . $APP_ROOT ``` ### docker-compose.yml 掲題の問題とは別に、`docker-compose up`時にappディレクトリをマウントすると、 ホスト側に`node_modules`が無いのでコンテナ内のnode_modulesが消失してしまう という問題があるため、それを回避するために以下のように作成しました。 ``` version: '3.4' services: web: build: context: . command: "npm run dev" # 詳細省きますがexpressサーバーを起動してるだけです ports: - '3000:3000' volumes: - .:/app - /app/node_modules # 消失対策 ``` 上記のDockerfile、docker-composeをベースに、コンテナ内で実行したnpm installをホスト側(のアプリディレクトリ内)にも 反映する設定方法があればご教授いただきたいです。
回答: もうこんな風にローカルは生のalpine使って、 DroneみたいなCIツールにDockerBuildさせるような構成にしたほうがいいです。 docker-compose.yml ``` version: '3.4' services: web: image: node:10.11.0-alpine command: "npm run dev" ports: - '3000:3000' volumes: - .:/app ``` ローカルにVSCodeとNode.jsをインストールしている時点で 環境を汚さないとか言ってても理想と現実がもう相当剥離してるんですが???状態になってます。 なので、ローカルにnode_modulesを作るという運用は避けられないでしょう。 質問文の要件はみたせませんが、今の所これが自然かつモアベターな方法です。 ``` $ cd app $ npm install ``` もし何か完璧な案を思いついたら試してみて下さい。 > > ライブラリ更新のたびにホストとコンテナで二重に実行する必要があるのでできれば避けたいです。 > > > これはおっしゃる通り。 実はモダンなプロジェクトではエンジニアが手作業でビルドすることは避けています。 (何が混入するかわからんし) 簡易的にやるならDockerHubとGitHubを連携させて、masterブランチが更新されたら自動的にdocker buildが走ってイメージが更新されるということが可能ですし、 凝ったことがしたければWebhookからDrone等のCIツールを発火させて自動ビルドするような仕組みを構築しましょう。 その場合はnode_modulesディレクトリは`.gitignore`配下に含まれるはずで、 `.dockerignore`で指定する必要すらなくなります。 GitHubなんかのmasterブランチが更新されたら、 CIツールが実行されて自動的にDockerImageが更新される。 これが勝ちパターンなので是非DroneやDockerHubの機能を覚えてみてください。