Docker for Mac 遅い問題
- Macのdockerが遅いストレスから解放されよう
- DXを大幅に低下させるDocker for Macを捨ててMac最速のDocker環境を手に入れる
- MacのDockerが遅い原因と対処方法(公式)
- Docker For Macが遅い:対策の実験
- Docker for Mac遅すぎる問題の解決
- Docker for Macでマウントしたvolumeの遅さに対処する
- 【JavaScript】Docker上でのnpm/yarnの操作を10倍早くする方法
- Docker-compose: node_modules not present in a volume after npm install succeeds
たくさんの記事が出ている通り、Docker for Macが遅いというのはみんなが思うところ...
Dockerの勉強を始めて1年が経ち、今まで目を逸らしていた問題にようやく重い腰をあげてこの問題に取り組む時が来た...!
Docker for Mac 遅い原因
大量のファイルが変更され、ホストとコンテナ間でファイル同期処理が行われるため。
(Docker for Macの速度がアップデートで勝手に改善してくれればいいな...と願って待ってました...。)
Docker for Mac 遅い問題の解決策
- 案1. docker-syncを使う
- 案2. 仮想マシンにLinuxを入れて、docker-composeを使う
- 案3. バインドマウントオプションのcached, delegatedを使う
- 案4. ボリュームマウントを使う
上記の参考記事は大体この4つの案のどれかで対応してました。
すべて試した訳じゃないのでハッキリしたことは言えないですが、どの方法もメリットデメリットはあるので許容できる方法を使うのが良いかと思います。おそらくどの方法も高速化は見込めると思います。
案1. docker-syncを使う
docker-syncの仕組みとしては、
通常のバインドマウントでホスト側のディレクトリをコンテナ側へマウントするのではなく、rsyncやunisonといった仕組みでホスト側のファイルをコンテナ側に転送するようです。
デメリットとしては、docker-syncを導入しなくてはいけないというそのもの。
構成が大きく変わるし、学習コストが跳ね上がる気がする。
案2. 仮想マシンにLinuxを入れて、docker-composeを使う
Docker for Macが遅いんだから、Linuxを通して使っちゃえという案。
既存のdocker-compose.yml等の変更が一番抑えられるし、本番により近い構成でとても良い方法に思える。
デメリットとしては、私はMacで開発したいんだ。
案3. バインドマウントオプションのcached, delegatedを使う
Dockerの17.04以降に追加されたオプション cached, delegated は読み込みや書き込みの一貫性を担保しない代わりにパフォーマンスが向上されるというものです。
デメリットとしては、あれれー?コードの変更が反映されないんだけど?みたいなことが多発しそう。。
案4. ボリュームマウントを使う
- 【JavaScript】Docker上でのnpm/yarnの操作を10倍早くする方法
- Docker-compose: node_modules not present in a volume after npm install succeeds
vendorやnode_modulesのデータを名前付きボリュームに格納して、ホスト側とコンテナ側と分離して管理する案。
同期処理が発生しないので、その分速くなる。
デメリットとしてはホスト側でもcomposer install
しなければIDEの自動補完等の恩恵が受けられなくなる。
どの案にするか?
個人的には案2と案4で迷うところですが、今回は案4を試したいと思います。
Laravelで大量のファイルの読み書きが多く発生するディレクトリは?
下記の3つです。(他にもあったら教えてください)
- vendor (composer installで生成されるディレクトリ)
- node_modules (npm, yarn installで生成されるディレクトリ)
- storage (フレームワークのキャッシュファイル等が生成されるディレクトリ)
今回は、vendorとnode_modulesに高速化対策したいと思います。
storageは別の話になるので別記事で対応します。
案4を採用した結果、当社比20倍の高速化に成功!
結果から言うと大満足です!
(まだ実際にこの案で業務利用したことないので要検証ですが...)
$ time composer install
real 2m40.358s => 0m8.383s
user 0m4.003s => 0m1.849s
sys 0m8.209s => 0m2.526s
Composerのインストールは152秒の短縮、20倍の高速化に成功!!!
$ time npm install
real 2m 35.33s => 0m 20.54s
user 0m 44.96s => 0m 19.64s
sys 0m 19.44s => 0m 7.56s
npmのインストールは135秒の短縮、7倍の高速化に成功!!!
案4. ボリュームマウントを使う 手順
本題のDocker高速化の手順です。
環境
-
docker-laravel🐳 | GitHub
- PHP 7.4.4
- Laravel 8.8.0
- 最強のLaravel開発環境をDockerを使って構築する【新編集版】
上記の環境を使用してます。
StarやLGTMもらえると記事を書くモチベになるので良い記事だなと思っていただければぜひよろしくお願いします!
前提
Laravelのインストールまで完了している状態
docker-compose.yml を編集
下記、コメントした4行を追記してください。
version: "3.8"
volumes:
php-fpm-socket:
db-store:
vendor-store: # add
node_modules-store: # add
services:
app:
build: ./infra/docker/php
volumes:
- php-fpm-socket:/var/run/php-fpm
- ./backend:/work/backend
- vendor-store:/work/backend/vendor # add
web:
build: ./infra/docker/nginx
ports:
- 80:80
volumes:
- php-fpm-socket:/var/run/php-fpm
- ./backend:/work/backend
- node_modules-store:/work/backend/node_modules # add
db:
build: ./infra/docker/mysql
ports:
- 3306:3306
volumes:
- db-store:/var/lib/mysql
設定内容を反映させます。
$ docker-compose up -d
設定内容を反映させるとコンテナ側の vendor
ディレクトリの中身はなくなってるはずです。
ホスト側の vendor
の中身はあってもいいし、中身を削除しちゃってもいいです。
それぞれ独立したのでホスト側の vendor
の中身がなくなっても動きます。
あと若干のコンテナの起動が遅くなってる気はします。(私だけかもしれない)
一応、下記のコマンドでファイルがどうなってるか確認しましょう。
node_modulesは最初は元々ファイルないのでホスト側もコンテナ側も空ですけど...
$ ls -l ./backend/vendor
$ docker-compose exec app ls -l ./vendor
$ ls -l ./backend/node_modules
$ docker-compose exec web ls -l ./node_modules
下記のコマンドを実行して依存パッケージをインストールします。
(爆速になってるはずです)
$ docker-compose exec app composer install
Nodeの場合は下記のコマンドになります。
$ docker-compose exec web npm install
このままだと新しくライブラリを追加してもホスト側の vendor
ディレクトリは更新されないので、下記のコマンドを使用して更新します。
$ docker-compose run --rm -v $(pwd)/backend:/code -w /code app composer install
$ docker-compose run --rm -v $(pwd)/backend:/code -w /code web npm install
-
docker-compose run
サービスに対して1回限りのコマンドを実行します -
--rm
コンテナ実行後に削除 -
-v
バインドボリュームを指定 -
-w
コンテナ内のワーキング・ディレクトリを指定
バインドボリュームでホスト側のディレクトリに依存ライブラリをインストールしています。
(これはちょっと時間かかります)
ホスト側、コンテナ側のそれぞれに依存ライブラリのインストールする必要があるので、総合的な所要時間は増えてしまったように思う。
ホスト側はIDEの自動補完ができればいいので、そう頻度高く更新しなくても良いのかなと思って妥協してます。
Makefile を作る
長いのでMakefileにすると便利です。
composer-install:
@make composer-install-for-container
@make composer-install-for-host
composer-install-for-container:
docker-compose exec app composer install
composer-install-for-host:
docker-compose run --rm -v $$(pwd)/backend:/code -w /code app composer install
Makefileでは変数展開は実行前に行われてしまうので $$(pwd)
のように $$
2個付けると良いです。
最後に
記事中にも言いましたが、あまり検証していないのでこの記事を参考にお試しいただけた方はコメントいただけると嬉しいです!