MacのDockerが遅い原因と対処方法(公式)

MacのDockerが遅い原因と対処方法(公式)

Macはシステム開発に適しているとよく聞きますが、

docker超遅いんですけど。

という方に向けて、解消方法を紹介したいと思います。

検索すると、docker-syncを使った方法などが多く出てきます。
環境に依存しない実行環境がdockerの利点ですが、開発環境だけサードパーティのrsyncやらを駆使して早くしては本末転倒です。

ここではdocker公式がリリースしているMacOSによる遅延の対応方法を説明していきます。

なぜMacのdockerは遅いのか

ボトルネックはマウントしているボリュームに対する読み書きの同期です。
通常、開発時にはMacOS(ホスト)のソースコードが保存されたディレクトリを、volume引数でdockerコンテナへマウントします。

dockerはマウントされたホスト側のディレクトリとコンテナを同期し、完全な一貫性を保証します。
その際、ファイルシステムがMacOSはosxfsのため、オーバーヘッドが発生して遅くなります。

仮にホストがLinuxOSでdockerコンテナにマウントしている場合は、共にファイルシステムはVFSのため直接共有されるのでオーバーヘッドは生じません。
ホストがWindowsOSの場合も同様にオーバーヘッドが生じますが、MacOSほど目に見えて遅くならないため、許容範囲内と思われます。

一貫性を妥協することでパフォーマンスを向上させる

volume引数に一貫性の厳密さをオプションで指定することで、完全な一貫性を犠牲にしてパフォーマンスを向上させることが出来ます。

オプション

オプション名 パフォーマンス 一貫性
consistent 完全
cached ホストの変更がコンテナに反映されるまでの遅延を許可
delegated ホストにコンテナの変更が反映されるまでの遅延を許可

つまりどういうこと?

consistendはデフォルトで指定されているため、何も設定していなければこれが用いられます。すごく遅い、でも完全な一貫性を保つので安心。
cachedは ボリュームの読み込みが高速化されます。読み出すだけの処理はこれで高速化されます。
delegatedは読み込みに加えて、書き込みも高速化されます。書き込みには、DBへの書き込み処理なども含みます。

余談

当初、私はcachedを指定していました。
しかし、1,000件ほどのテーブルのレコードに対してupdateする処理を実行したところ、30秒経っても応答が返らずにタイムアウトしました。
そして、delegatedに変更したところ3,4秒で処理が完了しました。
一貫性が損なわれることによる影響について、今のところ実感することはありませんが、何か一貫性が関わりそうな問題が起きた際にはすぐに気が付けるように、オプションのことを覚えておくことをお勧めします。

設定方法 docker run

-v (-volume)の末尾にセミコロンを付けてオプションを指定します。
cachedの例

docker run -v /Users/yallop/project:/project:cached alpine

設定方法 docker-compose.yml

docker-composeのymlで設定する場合も同様にvolumeの末尾にセミコロンを付けてオプションを指定します。
delegatedの例

volume: /Users/yallop/project:/project:delegated

開発環境だけ有効にするには

MacOSで実行する開発時だけ有効にしたい為、docker-compose.ymlに記述するとproduction環境まで適用されてしまいます。
この問題を防ぐには、docker-compose-dev.ymlを作りましょう。
docker-compose.ymlには、オプションを付けずに定義し、docker-compose-dev.ymlにはオプションを付けます。

services:
  app:
    volumes:
      - /Users/yallop/project:/project:delegated

その後、docker-compose upで起動する際に以下のコマンドでdocker-compose-dev.ymlを読み込むことで、重複する定義はdevの内容でオーバーライドされます。

docker-compose -f docker-compose.yml -f docker-compose-dev.yml up

参考リンク

プログラミングカテゴリの最新記事