Laravel 向け開発環境 Laradock のマウント方法によるベンチマーク結果(2018-03-31現在)

# 最初に

Docker for Mac の新機能として、18.03.0-ce から「NFS Volume sharing」というのが追加されたので、ベンチマークした結果を既に以下の記事として書いた。

- [Docker for Mac の NFS Volume sharing のベンチマーク結果(2018-03-29現在)](https://qiita.com/kunit/items/36d9e5fa710ad26f8010)

Docker for Mac のマウント方法は以下の４種類あるが、新しい NFS Volume sharing により結構ローカルファイルシステムへのread/write速度が改善されていることがわかった。

- 通常マウント(volumes に記述する際に、普通に記述する、もしくは `:consistent` を指定する)
- cached マウント(volumes に記述する際に `:cached` を指定する)
- delegated マウント(volumes に記述する際に `: delegated` を指定する)
- NFS Volume sharing を使う

cached/delegated のマウント方式の違いについての詳しいことは以下のドキュメントに書かれている。

- [Performance tuning for volume mounts (shared filesystems)](https://docs.docker.com/docker-for-mac/osxfs-caching/)

マウント方法の違いにより、もっと違いが出そうな環境がないかということで、Laravel 向けの開発環境である Laradock を使って、ベンチマークを再度取ってみた。

- [http://laradock.io/](http://laradock.io/)
- [https://github.com/laradock/laradock](https://github.com/laradock/laradock)

# Laradock のセットアップについて

私は普段 Laravel での開発をしていないので、以下のサイトでの Laradock のセットアップ方法を参考にさせてもらった。

- [LIG - PHPフレームワーク「Laradock」で、手軽にLaravel+Dockerな開発環境を構築する](https://liginc.co.jp/364089)

上記のサイトの手順そのままではなかったので、一応手順を簡単に書いておく

## Laradockを取得

以下のコマンドを使って Laradock を取得する。

```sh
mkdir ~/laravel_bench
cd ~/laravel_bench
git clone https://github.com/LaraDock/laradock.git
```

## Laradock の設定ファイルをカスタマイズ

Laradock の設定ファイル `.env` をサンプルファイルから作成し、カスタマイズする。

```sh
cd ~/laravel_bench/laradock
cp env-example .env
vi .env
```

`.env` ファイルでは以下の項目をもともとの設定から変更した。

```
APPLICATION=/Users/kunit/laravel_bench/laravel_app/
PHP_VERSION=71
WORKSPACE_INSTALL_XDEBUG=true
PHP_FPM_INSTALL_XDEBUG=true
```

`APPLICATION`は通常は相対パスで指定するのだが、NFSマウントの設定ファイルで使う際に絶対パスである必要があるため、上記のようにした。

`PHP_VERSION` は、最新の Laradock は PHP7.2 を使用するようになっていたので、今現在おそらく現実的に使われているのはPHP7.1であろうということで、7.1に下げ、合わせて xdebug を使う設定にしておいた。

## アプリケーションの作成

以下の手順でアプリケーションの作成を行う。

```sh
docker-compose up -d nginx mysql
docker-compose exec workspace bash
composer create-project --prefer-dist laravel/laravel ./
vi .env
```

上記の最後に .env を編集しているが、以下のように DB 接続設定だけ変更しておく


```.env
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=default
DB_USERNAME=default
DB_PASSWORD=secret
```

ここまでは共通の設定で、ここ以降はそれぞれのマウント方式によって異なる。
それぞれの設定ファイルを反映するために、毎回以下の流れで作業した。

- `docker-compose down` でコンテナ終了及び破棄
- `docker volume prune -f` でデータボリューム削除
- 設定変更
    - それぞれのマウント方法での設定変更方法は後述
- `docker-compose up -d nginx mysql` でコンテナ起動
    - 後述する docker-sync を使う場合のみ、コンテナ起動で使うコマンドが変わる

### 通常マウント/ cachedマウント/ delegatedマウントの場合

`docker-compose.dev.yml` の指定方法を変更する。

```docker-compose.dev.yml
version: "2"

services:

### Applications Code Container #############################

    applications:
      volumes:
        - ${APPLICATION}:/var/www
```

- 通常マウントは、上記の設定のまましようする
- cached マウントは、最後の行を以下のように変更

```
        - ${APPLICATION}:/var/www:cached
```

- delegated マウントは、最後の行を以下のように変更

```
        - ${APPLICATION}:/var/www:delegated
```

### NFS Volume sharingの場合

NFS Volume sharing の場合は３つやることがある。

- Mac上のNFSサーバーの設定を行う
    - 以前書いた記事「[Docker for Mac での ローカルファイルシステム NFS マウントのやり方](https://qiita.com/kunit/items/36d9e5fa710ad26f8010#docker-for-mac-%E3%81%A7%E3%81%AE-%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0-nfs-%E3%83%9E%E3%82%A6%E3%83%B3%E3%83%88%E3%81%AE%E3%82%84%E3%82%8A%E6%96%B9)」の以下の３つの手順を行う
        - /etc/exports に共有するディレクトリの設定をする
        - /etc/nfs.conf に NFS の設定を追加する
        - sudo nfsd restart で設定反映
- `docker-compose.nfs.yml` を作成する
- `.env` の `COMPOSE_FILE` の設定を以下のようにする

```
COMPOSE_FILE=docker-compose.yml:docker-compose.nfs.yml
```

`docker-compose.nfs.yml` は 以下のようなファイルになる。

```docker-compose.nfs.yml
version: "2"

services:

### Applications Code Container #############################

    applications:
      volumes:
        - nfs-applications:/var/www

volumes:
  nfs-applications:
    driver: local
    driver_opts:
      type: nfs
      o: addr=host.docker.internal,actimeo=1
      device: ":${APPLICATION}"
```

### docker-sync の場合

通常のマウントとは違ったやり方にはなるが、Laradockでは最初から docker-sync を使ったローカルファイルシステムのファイル同期を提供している。

これを使うには、`.env` ファイルの `COMPOSE_FILE` を以下のように変更する必要がある

```
COMPOSE_FILE=docker-compose.yml:docker-compose.sync.yml
```

また、コンテナ起動のコマンドが、`docker-compose up -d nginx mysql` ではなく以下のものになる

```
sync.sh up nginx mysql
```

# ベンチマーク方法

create-project で作成しただけのWebアプリケーションのトップページに対して、`ab` コマンドを使ってベンチマークを取る。

`ab` コマンドは以下の引数で実行した。

```sh
ab -n 100 http://127.0.0.1/
```

## ベンチマーク結果

通常マウントに比べれば、cached/delegated マウントは少しだけ改善してるが、NFS Volume sharing や docker-sync とくらべてしまうと、大して改善してないと感じてしまう。

NFS Volume sharing はかなり改善しているが、docker-syncを使った方式が圧倒的すぎる。

| マウント方法 | 100回リクエストするのにかかった時間(秒) | 1秒あたりのリクエスト数 |
| --------- | ---------------------------: | ----------------: |
| 通常マウント | 73.706 | 1.36|
| cachedマウント | 53.825 | 1.86 |
| delegatedマウント | 63.484 | 1.58 |
| NFS Volume sharing | 15.750 | 6.35 |
| docker-sync | 5.838 | 17.13 |

# まとめ

既に書いたように普段 Laravel をつかった開発をしておらず、Laradock が普通どのように使われているかということもよく知らないのだが、Docker for Mac を使っていて、ローカルファイルシステムのマウント方式を特に変更せずに使っている方は、NFS Volume sharing をつかうか、docker-sync を使うやり方に変えたほうがいいと思う。

Laradock は、docker-sync を最初からサポートしてくれているので、これだけの差がでるようだったら、とくに問題が出ない限りは、 docker-sync を使うということで良いと思う。

docker-sync で問題がよく起きるといった場合は、18.03.0-ce の新機能である NFS Volume sharing を積極的に使うほうが良いと思う。

# ベンチマーク結果詳細

## 通常マウント の結果

```
ab -n 100 http://127.0.0.1/
This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:        nginx
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /
Document Length:        2321 bytes

Concurrency Level:      1
Time taken for tests:   73.706 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      329368 bytes
HTML transferred:       232100 bytes
Requests per second:    1.36 [#/sec] (mean)
Time per request:       737.061 [ms] (mean)
Time per request:       737.061 [ms] (mean, across all concurrent requests)
Transfer rate:          4.36 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:   508  737 483.9    619    3888
Waiting:      508  737 483.8    619    3888
Total:        509  737 483.9    619    3888

Percentage of the requests served within a certain time (ms)
  50%    619
  66%    660
  75%    768
  80%    791
  90%    918
  95%   1148
  98%   3089
  99%   3888
 100%   3888 (longest request)
```

## cached マウント の結果

```
ab -n 100 http://127.0.0.1/
This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:        nginx
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /
Document Length:        2321 bytes

Concurrency Level:      1
Time taken for tests:   53.825 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      329510 bytes
HTML transferred:       232100 bytes
Requests per second:    1.86 [#/sec] (mean)
Time per request:       538.254 [ms] (mean)
Time per request:       538.254 [ms] (mean, across all concurrent requests)
Transfer rate:          5.98 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:   464  538  88.1    501     822
Waiting:      464  538  88.1    501     821
Total:        464  538  88.1    501     822

Percentage of the requests served within a certain time (ms)
  50%    501
  66%    520
  75%    557
  80%    571
  90%    697
  95%    765
  98%    810
  99%    822
 100%    822 (longest request)
```

## delegated マウント の結果

```
ab -n 100 http://127.0.0.1/
This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:        nginx
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /
Document Length:        2321 bytes

Concurrency Level:      1
Time taken for tests:   63.484 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      329438 bytes
HTML transferred:       232100 bytes
Requests per second:    1.58 [#/sec] (mean)
Time per request:       634.837 [ms] (mean)
Time per request:       634.837 [ms] (mean, across all concurrent requests)
Transfer rate:          5.07 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:   423  635 398.0    532    3531
Waiting:      423  634 398.0    531    3531
Total:        423  635 398.0    532    3531

Percentage of the requests served within a certain time (ms)
  50%    532
  66%    583
  75%    637
  80%    690
  90%    846
  95%    976
  98%   2924
  99%   3531
 100%   3531 (longest request)
```

## NFS Volume sharing の結果

```
--- nfs
ab -n 100 http://127.0.0.1/
This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:        nginx
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /
Document Length:        2321 bytes

Concurrency Level:      1
Time taken for tests:   15.750 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      329416 bytes
HTML transferred:       232100 bytes
Requests per second:    6.35 [#/sec] (mean)
Time per request:       157.496 [ms] (mean)
Time per request:       157.496 [ms] (mean, across all concurrent requests)
Transfer rate:          20.43 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:   130  157  34.5    147     342
Waiting:      130  157  34.5    146     342
Total:        130  157  34.5    147     342

Percentage of the requests served within a certain time (ms)
  50%    147
  66%    157
  75%    163
  80%    168
  90%    206
  95%    230
  98%    285
  99%    342
 100%    342 (longest request)
```

## docker-sync の結果

```
ab -n 100 http://127.0.0.1/
This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient).....done


Server Software:        nginx
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /
Document Length:        2321 bytes

Concurrency Level:      1
Time taken for tests:   5.838 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      329358 bytes
HTML transferred:       232100 bytes
Requests per second:    17.13 [#/sec] (mean)
Time per request:       58.375 [ms] (mean)
Time per request:       58.375 [ms] (mean, across all concurrent requests)
Transfer rate:          55.10 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    44   58  22.1     50     176
Waiting:       43   58  22.1     49     176
Total:         44   58  22.1     50     176

Percentage of the requests served within a certain time (ms)
  50%     50
  66%     53
  75%     59
  80%     61
  90%     82
  95%    113
  98%    135
  99%    176
 100%    176 (longest request)
```