【Docker】ホスト側でyarn installおよびyarn addができないようにする

## `node_modules`の取り扱いには注意が必要
Dockerを利用して環境構築をする際には`node_modules`の取り扱いに注意する必要があります。  
何も意識していないとホスト側で`yarn install`などをしてしまうとエラーが発生することがあります。  

https://qiita.com/P-man_Brown/items/db1996bdee33ee667741

また`yarn install`などを`Dockerfile`で実行した際に`node_modules`が削除されたりします。  

以下の記事ではコンテナ内のnode_modulesが消える問題の改善方法について記載しています。

https://qiita.com/P-man_Brown/items/c2a69d943853cb381fbe

しかし、上記の記事に記載している方法ではホスト側の`node_modules`が空になってしまいます。
その改善方法については以下の記事にまとめました。

https://qiita.com/P-man_Brown/items/5a82ad98cb96206343b9

記事のように設定するとホスト側に`node_modules`の中身を表示できますが、ホスト側の変更がコンテナ内に反映されてしまいます。
ホスト側で`yarn install`などをするとエラーの原因となるため、今回はホスト側の`node_modules`が空になる問題の改善方法について記載します。
`Next.js`の環境で試したので`Next.js`で記載しますが他でも応用可能と思います。

### ホスト側で`yarn install`などを不可にする
ホスト側で`yarn install`や`yarn add`をするとエラーが出るようにすることで対応します。
まず、`.yarnrc`を作成します。
![スクリーンショット 2022-04-29 23.03.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/147234ee-1643-704c-42f6-1df49021817f.png)
そして以下のように記述します。

```.yarnrc
--modules-folder /myapp/node_modules
```

yarnを使用した際に`--modules-folder /myapp/node_modules`がつくようになります。

`--modules-folder`については以下をご参照ください。

https://classic.yarnpkg.com/en/docs/cli/install


次にDockerfileを以下のようにします。

```Dockerfile:Dockerfile
FROM node:16.14.2

ENV USER_NAME=myuser
ENV TZ=Asia/Tokyo
# PATH 追記
ENV PATH="/myapp/node_modules/.bin:$PATH"

WORKDIR /myapp

# .yarnrc 追記
COPY package.json yarn.lock .yarnrc ./
RUN yarn install --frozen-lockfile

RUN adduser ${USER_NAME} && \
  chown -R ${USER_NAME} /myapp
USER ${USER_NAME}

EXPOSE 3000
CMD ["yarn", "dev"]
```

これで、`yarn install`をホスト側で実行すると以下のようなエラーが出て`yarn install`できなくなります。

```:ターミナル
$ yarn install
yarn install v1.22.17
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
error An unexpected error occurred: "EROFS: read-only file system, mkdir '/myapp'".
info If you think this is a bug, please open a bug report with the information provided
in "/Users/user_name/Documents/sources/docker-next-test/Next/yarn-error.log".
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
```

`yarn add`も同様です。

```:ターミナル
$ yarn add <package>
yarn add v1.22.17
[1/5] 🔍  Validating package.json...
[2/5] 🔍  Resolving packages...
[3/5] 🚚  Fetching packages...
[4/5] 🔗  Linking dependencies...
error An unexpected error occurred: "EROFS: read-only file system, mkdir '/myapp'".
info If you think this is a bug, please open a bug report with the information provided
in "/Users/user_name/Documents/sources/docker-next-test/Next/yarn-error.log".
info Visit https://yarnpkg.com/en/docs/cli/add for documentation about this command.
```

また、これはホスト側で`yarn install`などを不可にする他にも、以下のような事象を改善します。

`node_modules`にボリュームを設定した状態で、以下を実行するとコンテナ側の`node_modules`が空になります。

```:ターミナル
$ docker compose run --rm front yarn create next-app --ts myapp_name && \
  cd $_ && mv * .* .. && rmdir ${PWD} && cd ../
```

ホスト側でプロジェクトのルートディレクトリに展開するためこのように実行しています。

しかしこれでは、コンテナ内の`/myapp/node_modules`に変更が反映されません。
コンテナ内の`node_modules`は空のままであるため、`docker compose up`するとエラーが出ます。
```:ターミナル
$ docker compose up
[+] Running 1/0
 ⠿ Container next-front-1  Created                                                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  | info Visit https://yarnpkg.com/en/docs/cli/run for documentation about
this command.
next-front-1  | error Command failed with exit code 127.
next-front-1 exited with code 127
```

`.yarnrc`を前述のとおり作成すると`/myapp/node_modules`にインストールされるようになるため、この問題も改善されます。


これで`yarn install`などはできなくなりましたが、まだ`npm install`はできてしまいます。
`node_modules`が存在しない状態でホスト側で`npm install`したり、ホスト側で`npm ci`を実行してしまうとエラーの原因となることがあります。
詳細は以下をご参照ください。

https://qiita.com/P-man_Brown/items/db1996bdee33ee667741#npm%E3%81%AE%E5%A0%B4%E5%90%88

また、yarnを使用しているのに`npm install`してしまうと`yarn.lock`の他に`package-lock.json`も作成されてしまいます。
そのため、次は`npm install`もできないようにします。
`npm install`をできないようにする方法は以下をご参照ください。

https://qiita.com/P-man_Brown/items/625f55f615fb97293d1f


### yarn V3の場合

:::note warn
警告
以降に記述した方法ではDependabotを使用した際に以下のようなエラーとなることがわかりました。

![スクリーンショット 2023-03-30 17.23.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/45bd7aea-842e-7976-195c-8c549ca01f77.png)

![スクリーンショット 2023-03-30 17.23.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/7f2c0f42-74d0-1fc9-7631-4c20779880a1.png)

ご注意ください
:::


yarn V3の場合には`.yarnrc`ではなく、`.yarnrc.yml`を使用する必要があります。
`.yarnrc.yml`に以下のように記述することで同じことができます。


```.yarnrc.yml
yarnPath: .yarn/releases/yarn-3.2.0.cjs
cacheFolder: "/myapp/.yarn/cache"
```
yarn V3は`node-modules`ではなく`cache`フォルダ経由で依存関係を解決しています。
そのため、`cache`フォルダのパスを指定することでホスト側で`yarn add`をするとエラーが出るようにできます。

```:ターミナル
$ yarn add  <package>
Internal Error: ENOENT: no such file or directory, mkdir '/myapp'
Error: ENOENT: no such file or directory, mkdir '/myapp'
```
`yarn install`でも同様です。
```:ターミナル
$ yarn install
Internal Error: ENOENT: no such file or directory, mkdir '/myapp'
Error: ENOENT: no such file or directory, mkdir '/myapp'
```