VSCode&Docker Volumeにおけるnode_modules問題を解決する
Dockerでnodejs環境を構築するとき、node_modulesの扱いにはいくつかの嵌りポイントがあったので、それらの対抗策を考えてみました🐚
- .dockerignoreでnode_modulesがイメージにコピーされないようにする
- Volume Trickでnode_modulesがバインドマウントされるのを回避する
- VSCodeでnode_modulesを参照できない問題を解決する
今回は例として、nest.jsを使っていますが、他のプロジェクトでも基本は同じです!
.dockerignoreでnode_modulesがイメージにコピーされないようにする
まず、node_modulesはDockerイメージにホストからコピーしてはいけません。node_modulesはgitでも無視するはずなので、新しく環境構築する人のディレクトリにはそもそも入ってませんし、イメージをリビルドするときにホストのnode_modulesからイメージ内のnode_modulesが上書きされることも避ける必要があるからです。
なので、Dockerfileと.dockerignoreは例えば以下のようになるでしょう。
FROM node:14-alpine
WORKDIR /workspace
COPY package*.json ./
COPY yarn.lock ./
RUN yarn install
COPY . .
node_modules
npm-debug.log
yarn-error.log
dist
Volume Trickでnode_modulesがバインドマウントされるのを回避する
開発環境におけるコンテナの起動はdocker-compose.ymlで管理するのが便利なので、まずは一通り書いてみましょう。先程のイメージと、mysqlのイメージを利用することを考えます。
version: '3'
services:
nestjs:
build: .
tty: true
restart: always
command: yarn start:dev
ports:
- '3000:3000'
+ volumes:
+ - .:/workspace
このときハイライト部分に注目してください。これはホスト(.):コンテナ(/workspace)でバインドマウントがなされており、互いの変更が反映されるようになります。しかし、これでは、node_modulesもホストとコンテナで同期されてしまうことになります。せっかくnodejsのバージョンを14で固定したのに、ホスト側のnode_modulesがバインドマウントされてしまっては環境破壊🔥になってしまいます。
そのため、以下のように名前付きボリュームをnode_modulesに適用してください。このようにすることでnode_modulesをホストから切り離しつつ、コンテナが破棄されてもvolumeとして保持することができるようです。この記事によればVolume Trickと言うようです。
version: '3'
+ volumes:
+ nestjs-node-modules:
services:
nestjs:
build: .
tty: true
restart: always
command: yarn start:dev
ports:
- '3000:3000'
+ volumes:
+ - .:/workspace
+ - nestjs-node-modules:/workspace/node_modules
VSCodeでnode_modulesを参照できない問題を解決する
これで問題は全て解決と思いきや、(当然ですが、)ホスト側のnode_modulesは空っぽです。その結果、「モジュールが見つからないよ〜」的なエラーがvscodeから吐かれることとなります。
解決方法として以下のような方法が挙げられる(記事などあった)んですが、
- コンテナの中でvimとかで開発する ← VSCodeで開発したいんじゃ
- ホストでもyarn installする ← Dockerでせっかく開発環境整えた意味なくなるんじゃ
ということで
Remote ContainersというVSCode拡張機能を使うことで、もうコンテナ内でVSCode使っちゃおうぜ
という方法がベストではないかと思います。Remote Containersとは、Dockerfileもしくはdocker-compose.ymlを読み取って、コンテナを起動して、その中で作業しちゃうことができる代物です。Microsoft製なので動作も信用できます。
そして、用意するのはこれまでに作成したものと、.devcontainer.jsonという設定ファイルのみです。Dockerfileで動作させることもできますが、今回はdocker-compose.ymlを用いる方法を紹介します。
{
"name": "NestJS",
"dockerComposeFile": "./docker-compose.yml",
"service": "nestjs",
"workspaceFolder": "/workspace",
"extensions": [
...
],
"shutdownAction": "stopCompose"
}
詳しい説明は省きますが、extentionsでVSCodeの拡張機能をセットしたり、shutDownActionでVSCode終了時のアクションを設定できます。
では、一番左下の緑色のボタンをクリックして、Open Folder In Containerから.devcontainer.jsonのあるディレクトリを選択すると起動してくれます。無事起動できれば完了です。
また、コンテナ→ホストへの反映を早くするために、docker-compose.ymlのバインドマウント部分を以下のようにしておくのもおすすめです。
volumes:
- - .:/workspace
+ - .:/workspace:cached
- /workspace/node_modules
私の環境で再度検証しましたが、もし、うまくいかないなどあればコメントで教えてくださいませ!
Discussion