箱のプログラミング日記。

えんじにあ奮闘記

Docker for Mac が遅い(怒)

f:id:y_hakoiri:20191102134313j:plain

Docker for Mac が遅くて遅くてもう仕事にならないレベルになってきたのでどうにかならないかなと思い調べた。

Docker version 19.03.12
Docker Desktop 2.3.4.0

メモリを引き上げる

これまでの対策としてはDockerに割り当てるメモリの上限をデフォルトの2GB→8GBくらいまで引き上げることでひとまず速くなり満足していた

Memory: By default, Docker Desktop is set to use 2 GB runtime memory, allocated from the total available memory on your Mac. To increase the RAM, set this to a higher number. To decrease it, lower the number.

Docker Desktop for Mac user manual | Docker Documentation

f:id:y_hakoiri:20210711172601p:plain

のだけど、だんだんこれでも遅くなってきた。

delegetedオプションを使用

調べたところDocker for Macが重くて困っている人がいっぱいいた。

こちらの記事によると、

端的にまとめるとv17.04からcachedとdelegatedというオプションが追加され、書き込み読み込みの一貫性を担保しない(※)代わりにパフォーマンスが向上されるものです。

とのこと。

Linux 上ではホストとコンテナ間で VFS を基盤に共有しているので、オーバーヘッドのない反映を保証します。しかしながら、 macOS (および他の Linux 以外のプラットフォーム)では、完全な一貫性を保つために著しいオーバーヘッドがあります。

ボリューム・マウント(共有ファイルシステム)のためのパフォーマンス・チューニング — Docker-docs-ja 19.03 ドキュメント

だそうです。

どうやらDocker for Macが重いのはホスト側の変更をコンテナに同期するのに時間がかかっていることが原因で、同期の速度や正確性を緩める代わりにパフォーマンスの向上を優先できるのがdelegatedオプションの模様。

ということで

docker-compose.yml

app:
  build:
    context: .
    dockerfile: docker/dockerfiles/app/Dockerfile
  command: >
    bash -c "rm -f tmp/pids/* &&
    rails s -p 3000 -b '0.0.0.0'"
  environment:
    TZ: Asia/Tokyo
  volumes:
    - ./:/app_name:delegated # delegatedオプションを追加
$ docker-compose build --no-cache app
$ docker-compose up -d

で、だいぶ速くなった。

レスポンスが返ってきてViewがレンダリングされるまで酷い時は10秒以上かかっていたものが長くても2秒前後になりました。快適...!

ただ同期の遅延に関してはまだ検証できていないので様子見したい。

gRPC-FUSE

delegatedについてちゃんと公式読みたいなと思って漁ったところ見当たらない。 →見つけました。追記参照

どうやらDocker Desktop2.4.0以降はこのオプションに代わりgRPC-FUSEがデフォルトでオンになっているとのこと。

What happened to :delegated, :cached, :ro and other flags? - Compose - Docker Community Forums

What happened to :delegated, :cached and :ro? · Issue #5402 · docker/for-mac · GitHub

リリースノートには

Docker Desktop now uses gRPC-FUSE for file sharing by default. This uses much less CPU than osxfs, especially when there are lots of file events on the host. To switch back to osxfs, go to Preferences > General and disable gRPC-FUSE.

https://docs.docker.com/docker-for-mac/previous-versions/#new-1

とある。

osxfsよりもCPU使用率が遥かに少ないとのことなので、Docker Desktopのバージョンを上げてこちらで対応しようかなと思い少し調べたら、gRPC-FUSEのフラグがonになっているとMySQLコンテナ初期化でエラーが起こった人がいるらしい。

Docker for MacのgRPC FUSEが有効だとMySQLの/entrypoint.shでエラーになる

Mysql not starting in a docker container on MacOS after docker update - Stack Overflow

うーん。悩ましい

今回はあまり不用意に試してハマりたくないので、とりあえず今の状態(delegated)で様子を見てみることにする。

同期の遅延が致命的なようであればまた次のステップを検証したい。

追記:マウント時のオプションの種類

ここにdelegated以外のオプションの種類や詳細が載っていました。

  • consistent...完全な一貫性(常にホストとコンテナが完全に同じ表示)
  • cached...ホストの表示が信頼できる(ホスト上の更新がコンテナ上に反映するまで、遅延が発生するのを許容)
  • delegated...コンテナの表示が信頼できる(コンテナ上の更新がホスト上に反映するまで、遅延が発生するのを許容)

なるほど。

デフォルトではconsistentになっている。

今回は双方向に同期が必要な開発ではなく、基本的にホスト側の更新がコンテナ内に同期されれば問題ないので、delegatedが適しているという結論。

参考

Release notes for previous versions | Docker Documentation

ボリューム・マウント(共有ファイルシステム)のためのパフォーマンス・チューニング — Docker-docs-ja 19.03 ドキュメント

Macのdockerが遅いストレスから解放されよう - Qiita

Docker for MacのgRPC FUSEが有効だとMySQLの/entrypoint.shでエラーになる

Mysql not starting in a docker container on MacOS after docker update - Stack Overflow