Rails on Dockerでyarn addとかyarn updateの"Linking dependencies..."に時間がかかるので、半分まで短縮してみた



## はじめに

Docker上で`yarn add`とか`yarn update`を走らせると
主に、`Linking dependencies...`のところにものすごく時間がかかっていて
調べてみたところ、私の環境固有ではないようで
幾つか対策を試み実際に効果を調べた

## 結論
- セキュリティソフトのリアルタイム監視が影響している可能性あり（win & mac）
- mac環境ではosxfsというファイル共有システム？のパフォーマンスにより遅延が生じる(mac)
- mac環境での対策として、以下の方法が有効でした
 1. volumesの`:cached` optionを使用する(同期の遅延を許容する)
 2. 読み書きが頻繁に行われるディレクトリに対しては、**anonymous volumeや、named volumeとして指定することでhost側と同期しないようにする**（そもそもhost側と同期しないようにする）
 3. **頻繁に読み書きするディレクトリを知っている、調べる**（ここが重要な気がします、幾つか例を残していますので参考になれば）

> **追記(2020.10.1)**
`docker-compose.yml`で`./node_modules`をnamed volumeとして設定している部分のpathに誤りがありこれを訂正すると、体感でわかるほど高速化されました
>
当初よりだいぶvolumeの仕組みを理解して`docker-compose.yml`を書けるようになりました
Dockerのversionも変えてしまったので再計測は行なえませんが（今思うともともとの計測手順にも問題あり）、**読み書きが頻繁に行われるディレクトリはhost側と同期しないようにする**、が重要な気がします
>
>ということで計測結果はそこそこに（笑）
>セキュリティソフトの設定変更はリスクもありそうなので、参考程度に留めていただき、**読み書き頻回なディレクトリのパスを調べる**、**可能であればそのパスをhostマウントから除外する**、**難しいようであれば`:cached`オプションを試みる**がいいように思います
>
```yml
# 誤）
      - node_modules:/mysrc/node_modules:cached
# 正)
      - node_modules:/myapp/node_modules:cached
```

> 以下修正済みです

##  環境・計測方法

環境

- Mac OS Mojave 10.14.6
- Docker on mac 2.3.0.4
- Rails 6.03
- Ruby 2.7.1

```
$ docker-compose run app yarn --version
1.22.4
```

計測条件

- Avast （on or off） = セキュリティソフトのリアルタイム監視をon or off
- cached(あり or なし) = volumesの`:cached`オプションの有無
- volume mount (host or named) = hostのディレクトリをマウントする(=host、default), named volumeでhost mountから除外(=named)



上記環境にて以下のコマンドに要する時間を計測しました

```
docker-compose exec app yarn upgrade
```

## 結果



セキュリティソフトの設定変更
 
```
# Avast: on + cached: なし + volume: host (Default)
Done in 420.56s.

# Avast: off + cached: なし + volume: host
Done in 290.60s.
```

さらにnamed volumeを使用する

```
# Avast: off + cached: なし + volume: named
Done in 219.31s.
```
さらにcachedオプションを追加

```
# Avast: off + cached: あり + volume: named
Done in 204.73s.
```

まだ遅いけど、半分以下に短縮できました
一番影響したのはセキュリティソフトの設定かな




## Appendix

### Dockerのvolume3種類

以下にまとめました
[目的から考えるDockerのvolume3種 - Qiita](https://qiita.com/naokit-dev/items/2dcedc40548d3b802792)

### 上記を反映させたdocker-compose.yml


```yml
version: '3'

services:
  app:
    build: .
    command: ash -c "rm -f tmp/pids/server.pid && ./bin/rails s -p 3000 -b '0.0.0.0'"
    volumes: # 重要
      - .:/myapp:cached
      - rails_cache:/myapp/tmp/cache:cached # named volume化 + cached option
      - node_modules:/myapp/node_modules:cached # named volume化 + cached option
      - yarn_cache:/usr/local/share/.cache/yarn/v6:cached # named volume化 + cached option
      - bundle:/bundle:cached # named volume化 + cached option
    tmpfs:
      - /tmp
    tty: true
    stdin_open: true
    ports:
      - "3000:3000"
    environment:

      DATABASE_HOST: db
      DATABASE_PORT: 5432
      DATABASE_USER: postgres
      DATABASE_PASSWORD: password
      WEBPACKER_DEV_SERVER_HOST: webpacker
    depends_on:
      - db
      - webpacker
      - 
  webpacker:
    build: .
    command: ./bin/webpack-dev-server
    volumes:
      - .:/myapp:cached # これだけではダメで
      - node_modules:/myapp/node_modules:cached # こうしないと他のコンテナとnode_modulesが共有されない
    environment:
      RAILS_ENV: development
      NODE_ENV: development
      WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
    tty: false
    stdin_open: false
    ports:
      - '3035:3035'

  db:
    image: postgres:11.0-alpine
    volumes:
      - postgres:/var/lib/postgresql/data:cached
    environment:
      - TZ=Asia/Tokyo
    ports:
      - '5432:5432'
    environment:
      PGDATA: /var/lib/postgresql/data/pgdata
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_INITDB_ARGS: '--encoding=UTF-8 --locale=ja_JP.UTF-8'
      TZ: Asia/Tokyo

volumes: # named volumeを使用する場合は記述必須
  rails_cache:
  node_modules:
  yarn_cache:
  postgres:
  bundle:

```



## yarnのキャシュディレクトリを調べる方法

```
docker-compose run app yarn cache dir
```



# 参考

当初windowns環境のセキュリティソフトが影響しているとのことでしたが、mac環境でも同様の現象が起きることが報告されています
[Linking dependencies is taking a long time · Issue #1496 · yarnpkg/yarn](https://github.com/yarnpkg/yarn/issues/1496)

セキュリティソフトの関与について気づきをいただけました
[Yarn ver1.9.2で「Linking dependencies...」で時間がかかる方へ - Qiita](https://qiita.com/oedkty/items/0179a8729e8ed7d9da9b)

キャシュディレクトリを調べかた
[dockerでyarn addすると遅い問題を改善する - Qiita](https://qiita.com/lisp719/items/432be06fb333d6158eb1)