はじめに
本記事はプログラミング初学者が学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。
node_modules
の取り扱いには注意が必要
Dockerを利用して環境構築をする際にはnode_modules
の取り扱いに注意する必要があります。
ホスト側でyarn install
などをしてしまうと下の記事のようにエラーが発生することがあります。
またyarn install
などをDockerfile
で実行した際にnode_modules
が削除されたりします。
今回は、コンテナ内のnode_modules
が削除される問題の改善方法について記載します。
Next.js
の環境で試したのでNext.js
で記載しますが他でも応用可能と思います。
コンテナ内のnode_modules
が消える
前述したとおり、yarn install
などをDockerfile
で実行した際にnode_modules
が削除されてしまうことがあります。
これは、Dockerfile
とdocker-compose.yml
を以下のように記述している場合に起こります。
FROM node:16.14.2
ENV USER_NAME=myuser
ENV TZ=Asia/Tokyo
WORKDIR /myapp
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
RUN adduser ${USER_NAME} && \
chown -R ${USER_NAME} /myapp
USER ${USER_NAME}
EXPOSE 3000
CMD ["yarn", "dev"]
version: '3.9'
services:
front:
build: .
volumes:
- .:/myapp
environment:
NODE_ENV: development
ports:
- 3000:3000
docker compose up
すると以下のようなエラーが出ます。
$ docker compose up
[+] Running 2/2
⠿ Network next_default Creat... 0.0s
⠿ Container next-front-1 Cre... 0.1s
Attaching to next-front-1
next-front-1 | yarn run v1.22.18
next-front-1 | $ next dev
next-front-1 | /bin/sh: 1: next: not found
next-front-1 | error Command failed with exit code 127.
next-front-1 | info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
next-front-1 exited with code 127
原因はdocker-compose.yml
のvolumes
にあります。
ここではvolumes
で.:/myapp
と記述し、バインドマウントを設定しています。
バインドマウントはマウント時にホスト側の情報がそのまま反映され、そのあとコンテナ内で変更があればホスト側に反映されます。
よって、ホスト側にnode_modules
が存在しない状態でdocker compose up
するとホスト側の情報がそのまま反映されます。
するとコンテナ内のnode_modules
がなくなってしまいます。
確認のためにdocker-compose.yml
からvolumes
削除します。
version: '3.9'
services:
front:
build: .
# volumesを削除
environment:
NODE_ENV: development
ports:
- 3000:3000
変更後にdocker compose down
→ docker compose build
→ docker compose run front ls -a
するとnode_modules
があることが確認できます。
$ docker compose run front ls -a
[+] Running 1/0
⠿ Network myapp_default Created 0.0s
. .. node_modules package.json yarn.lock
これは、バインドマウントが設定されておらず、ホスト側の情報がコンテナ内に反映されないためです。
再度docker-compose.yml
のvolumes
を記述しdocker compose down
→ docker compose build
→ docker compose run front ls -a
します。
するとホスト側の情報がそのまま反映されnode_modules
は存在しません。
$ docker compose run front ls -a
[+] Running 1/0
⠿ Network myapp-_default Created 0.0s
. .editorconfig .gitignore Dockerfile
.. .env .husky docker-compose.yml
.DS_Store package.json yarn.lock .git
バインドマウントを設定したことでホスト側の情報がそのまま反映されていることがわかります。
改善方法
改善するためには、バインドマウントに加えてnode_modules
に対してボリュームを設定します。
Dockerfile
とdocker-compose.yml
を以下のようにします。
FROM node:16.14.2
ENV USER_NAME=myuser
ENV TZ=Asia/Tokyo
WORKDIR /myapp
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
RUN adduser ${USER_NAME} && \
chown -R ${USER_NAME} /myapp
USER ${USER_NAME}
EXPOSE 3000
CMD ["yarn", "dev"]
version: '3.9'
services:
front:
build: .
# 以下追記
volumes:
- .:/myapp
- node_modules:/myapp/node_modules
environment:
NODE_ENV: development
ports:
- 3000:3000
# 以下追記
volumes:
node_modules:
上記のようにするとエラーは出なくなります。
バインドマウントとボリュームを同時に設定した際に、ボリュームの方が優先されます。
そのため、node_modules
に関してはdocker compose up
した際にホスト側の影響を受けることがなくなります。
node_modules
が削除されないため、エラーが出ません。
なお名前つきボリュームを利用していますが、匿名ボリュームでも同様に機能します。
バインドマウントやボリュームの違いについては以下の記事をご参照ください。
ただし、この方法ではnode_modules
はバインドマウントから除かれるため、ホスト側のnode_modules
が空になってしまいます。
これはホスト側でもyarn install
することや(ホスト側が空になる状態であればホスト側の変更はコンテナ内に反映されません)、VSCodeで Remote - Containers
を利用することでも対処できます。
Remote - Containers
の使用方法については以下をご参照ください。
しかし、ホスト側でyarn install
せずにnode_modules
の中身を表示させる方法があります。
こちらについては以下にまとめましたのでご参照ください。