はじめに
本記事はプログラミング初学者が学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。
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の中身を表示させる方法があります。
こちらについては以下にまとめましたのでご参照ください。