Docker for Macが遅い問題をdocker-syncで解決する
こんにちは。エンジニアの志村です。 Docker for Mac便利ですね!
日本語でも様々な記事が出てきています。
私もVagrant + Dockerをメインに使用しておりましたが、ついにDocker for Macに乗り換えました。
弊社では、dev環境をDockerにしているのですが、Vagrant + Dockerの時は快適に開発が出来ました。
ただ、VMを使わなくなった途端にめちゃくちゃ動作が重くなりました。
docker-compose --service-port ●●
という感じで、rails serverとwebpack-dev-serverを立ち上げるのですが、ブラウザからの読込が劇的に遅い…。seedデータ突っ込むのもめちゃくちゃ遅い…
フォーラムでも話題になっていますね。
私の環境でいうと、Vagrant + Dockerの時よりも、体感10倍近く速度が落ちました…。
なぜ遅いのか
このDockerの中の人の回答を見ると、osxfsを用いてファイルシステムイベントを検知・監視していることが主な原因っぽいですね。 勿論、その他環境により差異はありますが、ファイルシステムを監視する方法を替えれば解決できそうです。
docker-sync
ファイル同期で速度早いと良く言われているのがrsyncですね。 docker-dev-osxという選択肢もありますが、これはDocker for Mac未対応… どうしようかなーとフォーラムを眺めているとdocker-syncなるものがありました。 フォーラムの中でも評価が良く、結構な人が使ってそうなのでdocker-syncを使用したいと思います。
docker-syncはRubyベースで書かれています。
docker-syncの使い方
- docker-sync, fswatchをインストールします。
$ gem install docker-sync $ brew install fswatch
ファイルの同期に関してはrsync, unisonが選択出来ます。 rsyncがホスト→ゲストの一方向の通信なのに対し、unisonはNFSのように双方向の通信が可能なようです。 今回はrsyncを使用します。 unisonに関してはまた記事を書ければと思います。
$ brew tap homebrew/dupes $ brew install rsync
※ schema.rb, Gemfile.lock等、ゲスト(Docker)側で生成されるファイルに関してはdocker cp
コマンドを使用するとホスト側に持ってくることが出来ます。
# Docker内のschema.rbをPC側に持ってくる
$ docker cp コンテナ:/var/www/db/schema.rb ./db/schema.rb
- docker-syncの設定 docker-syncはymlファイルに設定を記述します。 Railsを触っている身としては普段から使用しているのでありがたいです。
docker-syncはDocker Composeを使用します。 production環境やstaging環境でもDockerを使用している方は、docker-compose.ymlの他に、開発環境用のymlファイルを用意する必要があります。 私は開発環境のみなので、docker-compose.ymlを直接編集してしまいます。
公式のwikiに載っているので参考下さい。
docker-sync.yml
syncs: # docker-syncで使用するvolume名を記載 web-sync: notify_terminal: true # ホスト側(PC)のパスを記載 今回はRailsのルートディレクトリを指定 src: './' # ゲスト側(Docker)にマウントするパスを記載 Docker内の/var/wwwにマウントされる dest: '/var/www' # IPの設定 sync_host_ip: '127.0.0.1' # rsyncのポート設定 sync_host_port: 10871 # rsyncさせないファイル類を記載 sync_excludes: ['Gemfile.lock', 'Gemfile', 'config.rb', '.sass-cache/', 'sass/', 'sass-cache/', 'composer.json' , 'bower.json', 'package.json', 'Gruntfile*', 'bower_components/', 'node_modules/', '.gitignore', '.git/', '*.coffee', '*.scss', '*.sass'] sync_excludes_type: 'Path' sync_args: '-v' # ファイル同期方法の選択 rsync or unison sync_strategy: 'rsync' # ゲスト側でのユーザー名の指定 sync_user: 'test' sync_userid: '5000' # ゲスト側でのgroupの指定 sync_group: 'testgroup' sync_groupid: '6000' # fswatchで変更を検知させないファイルやディレクトリ sync_excludesとかぶせとけばよいかと watch_excludes: ['.*/.git', '.*/node_modules', '.*/bower_components', '.*/sass-cache', '.*/.sass-cache', '.*/.sass-cache', '.coffee', '.scss', '.sass', '.gitignore'] watch_args: '-v' watch_strategy: 'fswatch'
docker-compose.yml
docker-compose.ymlにはversion1, version2と2種類の記述方法があります。 ここではversion2を使用します。
version: '2' services: database: image: postgres:latest volumes_from: - datastore expose: - '5432' elasticsearch: image: elasticsearch:latest volumes_from: - datastore ports: - '9200:9200' redis: image: redis:latest ports: - '6379:6379' volumes_from: - datastore memcached: image: memcached:latest ports: - '11211:11211' volumes_from: - datastore datastore: build: docker/datastore web: build: . command: bash -c 'rm -f tmp/pids/server.pid && bundle exec foreman start && bundle exec sidekiq -C config/sidekiq.yml -L tmp/sidekiq.log -d' volumes: # 下記で宣言したvolume名を指定 - web-sync:/var/www:rw - /var/www/client/node_modules ports: - '3000:3000' - '8080:8080' links: - database - elasticsearch - redis - memcached # docker-syncで使用するvolume ここで宣言した名前がdocker-sync.ymlで使用される volumes: web-sync: external: true
このような感じです。 環境によって差異があると思いますので、適宜調整をお願いします。 一番重要なのは、volumesのsync volumeの設定と、アプリケーション(Rails)側のコンテナでvolumesを指定する部分です。
docker-syncの起動
$ docker-sync start
もしくは
$ docker-sync-stack start
で起動します!
docker-sync-stack start
の場合は、docker-sync start
と同時にdocker-compose up
も行われます。
私はpry-byebugを使用したいので、普段docker-compose run --service-port web
で起動しているため、ターミナルを一枚docker-sync startに使用し、さらにdocker-compose run --service-port web
を起動させるようにしています。
ベンチマークはとっていないのですが、Vagrant + DockerをNFSで同期させたのと同じ、もしくはそれ以上に早くなりました! GUIで様々な設定が出来、VMとかも必要ないのでDocker for Macは便利ですね。 是非docker-syncを使って快適な開発環境を構築してみては如何でしょうか?
We’re hiring!
Cluexではビジネスサイド、エンジニアサイド共にメンバーを募集しています! お気軽にご連絡下さいませ!