ようやく Docker を使い始めたところ、Docker for Mac でホストのディレクトリをコンテナでマウントした時の遅さに驚きました。
バージョン
$ docker --version
Docker version 17.04.0-ce, build 4845c56
状況
とある Rails アプリについて、ホスト(macOS)にあるソースコードをホストで編集しつつ Docker コンテナで動かす事を考えます。
FROM ruby:2.4.1
WORKDIR /app
ENV BUNDLE_PATH /bundle
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev
version: '3'
services:
...
job: &job
image: ...
build: .
volumes:
- ./:/app
- gems:/bundle
...
depends_on:
- postgres
- redis
- fluentd
command: bundle exec rails jobs:work
environment:
...
api:
<<: *job
command: bundle exec rails s -p 3333 -b 0.0.0.0
ports:
- "3333:3333"
volumes:
gems:
...
macOS 上で動かしたときと比べ、とある単純な Web API の応答時間が10倍くらいになりました(25ms/req → 250ms/req)。
対策
最近追加されたマウントオプション(consistency オプション)を利用することで、ボリュームのI/O性能(?)を向上させられる様です。
デフォルトは consistent
で、一貫性のために性能が犠牲になっている、ということでしょうか。それなりの性能を求めつつ、ホスト側の変更をコンテナに反映したい場合は cached
オプションを使えば良さそうです。
The consistency requirements for the mount; one of
- default: Equivalent to consistent.
- consistent: Full consistency. The container runtime and the host maintain an identical view of the mount at all times.
- cached: The host's view of the mount is authoritative. There may be delays before updates made on the host are visible within a container.
- delegated: The container runtime's view of the mount is authoritative. There may be delays before updates made in a container are are visible on the host.
version: '3'
services:
...
job: &job
image: ...
build: .
volumes:
- ./:/app:cached
- gems:/bundle
...
depends_on:
- postgres
- redis
- fluentd
command: bundle exec rails jobs:work
environment:
...
api:
<<: *job
command: bundle exec rails s -p 3333 -b 0.0.0.0
ports:
- "3333:3333"
volumes:
gems:
...
雑に比較した(ab -n100
)限り、 consistent
で平均 250 ms/req 程度だった応答時間が、 cached
では平均 85 ms/req 程度に改善出来ました。
まだ使い始めたばかりなので、ホスト側での変更がコンテナに反映されるまでの遅延については、要観察です。
まとめ
だいぶましにはなりましたが、macOS で動かした時は平均 25ms 程度なので、まだ体感的にも遅さを感じています…。Docker 慣れしてなさすぎて、そもそもの考え方を間違えているかもしれません。
今回例示した様な構成(ユースケース)では、現時点では docker-sync を使っておくのが無難だったりするでしょうか。
追記: 2017/04/13
docker-sync
最低限の設定で unison を使った同期を試したところ、cached の半分以下の応答時間(計測環境が違うので正確ではない)で、macOS 上で development で動かした時と同程度でした。