KUSANAGI for Laravel 【 Laravel爆速実行環境 】

この記事は[KUSANAGI Advent Calendar 2016](http://qiita.com/advent-calendar/2016/kusanagi) 14日目のエントリーです。

KUSANAGIの開発元である、[プライム・ストラテジー株式会社](https://www.prime-strategy.co.jp/)で~~エンジニアをしておりました~~。@tajima_tasoと申します。
__※2017年9月に戻ってきており、KUSANAGIの開発をしております。__

私からはKUSANAGI環境上で、近年人気が高まっているPHPフレームワーク、[Laravel](http://laravel.jp/)を構築する方法について、ご紹介いたします。

## どのくらい爆速なのか? 

まずはKUSANAGIの速さを数字で確認して頂きます。KUSANAGIを載せた結果、大して性能が出てないという結果であれば、この記事を読んだ時間が無駄になってしまいますので、最初に持ってきました。

断っておきますと、今回、キャッシュやロードバランシングといった類の話は__一切関与しません__。単純に載る土台(OS、ミドルウェア)によって同一のアプリケーションがどれだけ速く動くか？ということに焦点をあてたお話です。

通常のLAMP環境と　KUSANAGI環境のベンチマークの結果で、その速さを確認して頂きます。両方とも下記の__同一のパブリッククラウドの同一のリージョンの同一のサーバリソース__のもとで動作しています。端的に言うと、異なるのはソフトウェアをチューニングしているかしていないかの違いのみです。

|　パブリックプラウド | リージョン| サーバプラン | ディスクプラン| 
|:--|---|-----------|------------:|
|さくらのクラウド| 石狩第2ゾーン|2 GB / 2 仮想コア      | 20 GB SSDプラン | 

abを叩くクライアントとなるサーバはさくらのVPS(石狩)です。

まずは通常のLAMP環境のベンチマークです。 

### LAMP環境でのベンチマーク

```bash:
$ ab -n 1000  -c 100 http://kusanagi-lamp.jp/
Completed 1000 requests
Finished 1000 requests


Server Software:        Apache/2.4.6
Server Hostname:        kusanagi-lamp.jp
Server Port:            80

Document Path:          /
Document Length:        1023 bytes

Concurrency Level:      100
Time taken for tests:   26.929 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      2045156 bytes
HTML transferred:       1023000 bytes
Requests per second:    37.13 [#/sec] (mean)
Time per request:       2692.880 [ms] (mean)
Time per request:       26.929 [ms] (mean, across all concurrent requests)
Transfer rate:          74.17 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   1.3      0      19
Processing:   479 2647 708.4   2690    4582
Waiting:      473 2618 701.1   2664    4582
Total:        484 2648 707.9   2690    4582

Percentage of the requests served within a certain time (ms)
  50%   2690
  66%   2892
  75%   3065
  80%   3218
  90%   3561
  95%   3886
  98%   4063
  99%   4157
 100%   4582 (longest request)

```

Requests per second(1秒間に処理されたリクエスト数)が__37.13__となっています。

続いてKUSANAGI環境で比べてみましょう。

### KUSANAGI環境でのベンチマーク

```bash:
$ ab -n 1000  -c 100 http://kusanagi-laravel.jp/
Server Software:        nginx
Server Hostname:        kusanagi-laravel.jp
Server Port:            80

Document Path:          /
Document Length:        1023 bytes

Concurrency Level:      100
Time taken for tests:   2.474 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      2011992 bytes
HTML transferred:       1023000 bytes
Requests per second:    404.25 [#/sec] (mean)
Time per request:       247.371 [ms] (mean)
Time per request:       2.474 [ms] (mean, across all concurrent requests)
Transfer rate:          794.29 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   1.3      0       9
Processing:    61  236  54.1    230     662
Waiting:       61  236  54.3    230     662
Total:         66  237  53.8    230     663

Percentage of the requests served within a certain time (ms)
  50%    230
  66%    238
  75%    244
  80%    249
  90%    267
  95%    283
  98%    322
  99%    591
 100%    663 (longest request)
```

Requests per secondが__404.25__となっています。

なんと単純比較で__約11倍__の性能が出ることになりました。くどいようですが、キャッシュは一切使っておりません。
両者の違いは__ソフトウェア(ミドルウェア)的なチューニングの有無の違いのみで、ハードウェアやサーバ構成__などその他外的な要因はまったく同じです。

KUSANAGIのことをご存知だった方も、そうでない方も、記事を読む前よりも興味を抱いて頂けていたら幸いです。

ではKUSANAGIとは一体何なのでしょうか？

## KUSANAGIとは

プライム・ストラテジー社が開発した[超高速WordPressマシン](https://kusanagi.tokyo/)です。

その実体は徹底的にチューニングされたLEMP、LAMPのサーバ環境に他なりません。
CentOS7をベースとして、PHP、Apache、nginx、MySQL(MariaDB)上で動作するアプリケーションに超高速な実行環境を提供します。

それはつまり、KUSANAGIはWordPressだけを高速に動作させる環境ではないということを意味します。

実際、私はプライム・ストラテジー株式会社在籍時、WordPress以外のアプリケーションをKUSANAGI環境へ移行する案件を多数行いましたが、例外なく移行前よりパフォーマンスの向上を確認しておりました。

そこで今回はKUSANAGI上で、近年のPHPフレームワークの主流となりつつあるLaravelを動作させてみました。

Laravelはとても便利なフレームワークで、開発者が幸せになれる機能が満載ですが、一点動作が遅いというデメリットがあります。これをKUSANAGIでカバーできないか？という試みでしたが、結果は冒頭の通りです。

つきましては、皆さんにも是非その性能を確認して頂きたいので、続いて導入方法について紹介していきます。

## どうやって利用するのか？

最初に申し上げておくと、KUSANAGI自体は__例外なく無料__で使えます。

国内外の主要なパブリッククラウドで展開していて、AWS、Microsoft Azure、さくらのクラウドなど皆さんが利用しているパブリッククラウドにはまず間違いなく導入されておりますので、使用するパブリッククラウドの選定が終わってコンパネにログインしたらポチポチと選んで、KUSANAGIのサーバを立てるという流れになります。

また、最近では[Docker](https://kusanagi.tokyo/cloud/kusanagi-runs-on-docker/)や[さくらのVPS](https://kusanagi.tokyo/cloud/kusanagi-for-sakuravps/)でも利用可能です。

どういった環境で使えるのかは、[公式サイト](https://kusanagi.tokyo/cloud/)で紹介されています。今後も続々と増えていくでしょう。

面倒なサーバのプロビジョニングやミドルウェアの変更が、kusanagiコマンドとそのサブコマンド群で簡単に管理できることも大きな特徴の１つです。詳しくは[公式ドキュメント](https://kusanagi.tokyo/document/)をご覧下さい。

## KUSANAGIの導入

では、KUSANAGIを実際に導入します。
といっても何も難しいことはありません。先程申し上げた通り、任意のパブリッククラウドでサーバを立てる時にKUSANAGIを選ぶだけです。

今回私は、[KUSANAGI for さくらのクラウド](https://kusanagi.tokyo/cloud/kusanagi-for-sakuracloud/)を利用しました。
導入手順は公式サイトの通りです。サーバを立ててログインするところまで、サクッとできると思います。

## KUSANAGIの初期設定

続いて、初期設定です。こちらも基本[公式ドキュメント](https://kusanagi.tokyo/document/kusanagi-init/)の通りのコピペでいけます。本当にこの通りなので迷わないと思います。

## Laravelの為のプロビジョニング

初期設定が終わりましたら、Laravelを導入する為のKUSANAGIのプロビジョニングを行っていきます。[公式ドキュメント](https://kusanagi.tokyo/document/kusanagi-provision/)では、WordPressの導入にそって進めていくものの、WordPress以外のアプリケーションのプロビジョニングについてもちゃんと書かれています。
2.プロビジョンタイプの選択の選択のところを参考にしてみると

```
オプション --WordPress を指定すると、WordPress をプロビジョニングします。
オプション --concrete5 を指定すると、Concrete5 をプロビジョニングします。
オプション --drupal8 を指定すると、Drupal8 をプロビジョニングします。
オプション --lamp を指定すると、LAMP(Linux+Apache+MySQL+PHP) もしくは LEMP(Linux+NGINX+MySQL+PHP)で使用するための設定のみをプロビジョニングします。
```

とありますので、` --lamp`オプションを指定してプロビジョニングを進めていきます。

```bash:
$ kusanagi provision  --lamp kusanagi_html
```

その後、データベースの設定、Webサーバソフトウェアは? PHPのバージョンは? などの指定をインタラクティブに行っていきます。聞かれるままに入力していけばいいので、迷わないと思います。

私はPHP7とnginxを選択しました。なお、この指定はプロビジョニング後も任意のタイミングで、変更することができるので、後からPHP7とApacheの構成にすることも簡単にできます。

プロビジョニングが終了すると、適切にミドルウェアの設定が行われた後に、ソフトウェアが起動します。

これでLaraveが載るべき土台となる準備はできました。

## Laravelの導入

いよいよ、Laravelを導入していきます。
今回はLTS(長期間サポート)であるLaravel5.1を導入します。5.2や5.3でもKUSANAGI上で十分導入可能なので、そちらを入れて頂いても問題ありません。

まずは[Laravelの公式サイト](https://readouble.com/laravel/5.1/ja/installation.html)を確認して、必要な要件を確認します。

```
PHP >= 5.5.9    PDO PHP拡張    Tokenizer PHP拡張
OpenSSL PHP拡張    Mbstring PHP拡張
```

上記が必要な要件なので、確認してみます。
KUSANAGIはPHP5.6と7系、HHVMの3つを選べます。

### PHPのバージョンを確認
```bash:
$ php -v
PHP 5.6.28 (cli) (built: Nov  9 2016 07:14:50)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies

$ php7 -v
PHP 7.0.13 (cli) (built: Nov 11 2016 10:16:41) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies

$ hhvm --version
HipHop VM 3.15.0 (rel)
Compiler: 1473300163_047790084
Repo schema: 2df110c6a6400fbcf88ff266f2b6f345e7d1b6a8

```
PHP5.6と7は問題ないとして、hhvmも3.11.0からはPHP7の機能をサポートしだしたのでどれを選んでも基本的には問題ないでしょう。
今回はPHP7を選択しています。

必要なPHPのモジュールを確認してみましょう。

```bash:
$ php7 -i | grep enabled | grep -iE '(openssl|pdo|tokenizer|mbstring)'
OpenSSL support => enabled
PDO support => enabled
PDO Driver for MySQL => enabled
PDO Driver for SQLite 3.x => enabled
Native OpenSSL support => enabled
Tokenizer Support => enabled
```

こちらもKUSANAGIをインストール時に最初から有効化されているので、問題なさそうです。楽ですね。

PHPのバージョンや必要なモジュールは揃ってしましたが、KUSANAGIは現状、PHPの事実上のパッケージ管理ツールである~~Composerが初期設定時には導入されていません。~~ kusanagi-8.3.1以降はcomposerが導入ずみですので、それ以前の環境では下記手順で導入します。

Laravelを導入するにはComposerが必要なので、インストールを行います。下記の操作はsudoなどでrootユーザーの権限で行うと良いでしょう。

```bash:
$ curl -sS https://getcomposer.org/installer | sudo php
$ sudo mv composer.phar /usr/local/bin/composer
tokenizer
```

/usr/local/bin/にパスが通っていることを確認して、必要に応じて環境変数PATHを変更しましょう。

```bash:
$ echo $PATH
## OK!
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/kusanagi/.local/bin:/home/kusanagi/bin
```

composerコマンドが利用できるか確認します。

```bash:
$ composer -V
Composer version 1.2.3 2016-12-01 14:33:53
```

composerコマンドが使えるようになったので、Laravelのプロジェクトを作ります。
まずはkusanagi_htmlへ移動します。このディレクトリ名はプロビジョニングの時に指定したディレクトリ名です。

```bash:
$ cd /home/kusanagi/kusanagi_html
$ ll
drwxrwxrwx 5 kusanagi kusanagi 4096 11月 23 16:50 DocumentRoot
drwxr-xr-x 4 kusanagi kusanagi 4096 11月 23 16:50 log
```

kusanagi_htmlに移動すると初期では上記のようなディレクトリ構成になっていることが確認できると思います。

kusanagiではデフォルトでDocumentRootというディレクトリをWebサーバソフトウェアの公開領域に割り当てているのですが、Laravelの場合は`Laravelのプロジェクトディレクトリ/public`というディレクトリが公開領域として想定されていますので、ここを少し変更します。

まずは、DocumentRootを削除します。

```bash:
$ rmdir DocumentRoot
$ ll
drwxr-xr-x 4 kusanagi kusanagi 4096 11月 23 16:50 log
```

Laravelのプロジェクトをlaravelというディレクトリの直下に作成します。プロジェクトをDocumentRoot直下に作っても良かったんですが名前的に紛らわしいので今回はそれは避けることにします。

```bash:
$ composer create-project laravel/laravel  laravel "5.1.*"
```

無事インストールが終了すると下記のようなディレクトリ構成になります。場合によってはPHPモジュールが足りないと怒られることがありますが、KUSANAGIの場合はLaravelに必要なモジュールが揃っているのでまず失敗することはないでしょう。

```bash:
$ ll
drwxr-xr-x 11 kusanagi kusanagi 4096 12月 11 16:49 laravel
drwxr-xr-x  4 kusanagi kusanagi 4096 11月 23 16:50 log
$ cd laravel
$ ll
drwxrwxr-x 10 kusanagi kusanagi   4096  4月  5  2016 app
-rwxr-xr-x  1 kusanagi kusanagi   1646  4月  5  2016 artisan
drwxrwxr-x  3 kusanagi kusanagi   4096  4月  5  2016 bootstrap
-rw-rw-r--  1 kusanagi kusanagi   1214  4月  5  2016 composer.json
-rw-rw-r--  1 kusanagi kusanagi 119369 12月  2 16:51 composer.lock
drwxrwxr-x  2 kusanagi kusanagi   4096  4月  5  2016 config
drwxrwxr-x  5 kusanagi kusanagi   4096  4月  5  2016 database
-rw-rw-r--  1 kusanagi kusanagi    503  4月  5  2016 gulpfile.js
-rw-rw-r--  1 kusanagi kusanagi    159  4月  5  2016 package.json
-rw-rw-r--  1 kusanagi kusanagi     87  4月  5  2016 phpspec.yml
-rw-rw-r--  1 kusanagi kusanagi   1026  4月  5  2016 phpunit.xml
drwxrwxr-x  2 kusanagi kusanagi   4096 12月  2 17:16 public
-rw-rw-r--  1 kusanagi kusanagi   1928  4月  5  2016 readme.md
drwxrwxr-x  5 kusanagi kusanagi   4096  4月  5  2016 resources
-rw-rw-r--  1 kusanagi kusanagi    567  4月  5  2016 server.php
drwxrwxr-x  5 kusanagi kusanagi   4096  4月  5  2016 storage
drwxrwxr-x  2 kusanagi kusanagi   4096  4月  5  2016 tests
drwxrwxr-x 30 kusanagi kusanagi   4096 12月  2 16:51 vendor
```

Webサーバソフトウェア(nginx)のドキュメントルート指定を変更します。
書き換えるのはrootの箇所です。

```bash:
$ sudo vim /etc/nginx/conf.d/kusanagi_html_http.conf
# 該当の箇所を下記のように書き換える。 
root  /home/kusanagi/kusanagi_html/laravel/public;
```

nginxを再起動します。せっかくなのでkusanagiのnginxサブコマンドで再起動します。

```bash:
$ sudo kusanagi nginx
Nginxを使用します。
完了しました。
```

切り替わりました。簡単ですね。

これでほぼやるべきことをやりましたが、Laravel5.1の場合あとすこしだけやるべきことがあります。

[公式ドキュメント](https://readouble.com/laravel/5.1/ja/installation.html)のディレクトリーパーミッションの項を見ると、storageディレクトリとbootstrap/cacheをWebサーバから書き込み可能にして下さいとあります。

```bash:
$ ll -d storage/
drwxrwxr-x 2 kusanagi kusanagi 4096  4月  5  2016 app
drwxrwxr-x 5 kusanagi kusanagi 4096  4月  5  2016 framework
drwxrwxr-x 2 kusanagi kusanagi 4096 12月 11 16:51 logs
$ ll -d bootstrap/cache/
drwxrwxr-x 2 kusanagi kusanagi 4096 12月  2 16:51 bootstrap/cache/
```

ユーザーとグループに書き込み権限があるようですが、kusanagiとなっていてWebサーバの権限からは書き込めないようになっています。かといって安易に777なんてパーミッションにするにはセキュリティ的な観点から好ましくありません。

そんな時のためのKUSANAGIではWebサーバのプロセスに対してhttpdユーザー、wwwグループが割り当てられているので、Webサーバが書き込まなければならないディレクトリに対しては、所有者をhttpd、グループをwwwにします。

なお、デフォルトではkusanagiユーザーはwwwグループにも属しているので、Webサーバが作成したディレクトリやファイルにkusanagiユーザーが書き込むことができないというようなことにはなっていません。まあ、このあたりは要件によってパーミッションを制限してもよいでしょう。

```bash:
$ id kusanagi
uid=1001(kusanagi) gid=1001(kusanagi) groups=1001(kusanagi),1000(www)
$ id httpd
uid=1000(httpd) gid=1000(www) groups=1000(www)
$ sudo chown -R httpd.www storage/
$ sudo chown -R httpd.www bootstrap/cache/
$ ll -d storage/
drwxrwxr-x 5 httpd www 4096  4月  5  2016 storage/
$ ll -d bootstrap/cache/
drwxrwxr-x 2 httpd www 4096 12月  2 16:51 bootstrap/cache/
```

これで、Webサーバからstorage/、bootstrap/cache/を書き込めるようになったので、Laravelが動作する準備が完全に整いました。

ブラウザからアクセスしてみます。

![2016:12:12 11-20-53.png](https://qiita-image-store.s3.amazonaws.com/0/90032/6ddcbe33-3cf3-de6c-87a2-9947856b2f97.png)

LaravelデフォルトのTOPページが表示されました。白すぎてわかりにくいですが😅

LAMP環境とのベンチマークは冒頭に述べたとおりです。

LAMPに関してもさくらのクラウドの画面で、KUSANAGIを立てたスペックと全く同じプランでサーバを立て、Laravelをインストールしました。Laravelの導入はともかく、ミドルウェアの導入、ファイルウォールの設定などを1からやるのが結構めんどくさかったです。。

さて、ここで最後にもう1パターンのベンチマークを検証しましょう。

先程のKUSANAGIはLAMP環境と比較したものの、実はミドルウェアの観点からみると、LEMP環境で動作していました。Webサーバソフトウェアがnginxだったんですね。

個人的にはKUSANAGIはnginxで使うことをオススメしているのですが、もちろんApacheでの使用も可能です。
Apacheを使えば本当の意味でKUSANAGIはLAMP環境同士の比較になり、厳密な比較になるのでやってみましょう。

ミドルウェアの構成変更についてはkusanagiのhttpdサブコマンドで一瞬で環境をApacheに切り替えることができますが、nginxの時にご説明したとおり、KUSANAGIでは現状公開ディレクトリがDocumentRootという名前のディレクトリになっているので、ここを編集しておきます。
このへんは正式にKUSANAGI for Laravelの為に自動化のコントリビュートをしたいところです😄

```bash:
$ sudo vim /etc/httpd/conf.d/kusanagi_html_http.conf 
# 該当の箇所を下記のように書き換える。
DocumentRoot /home/kusanagi/kusanagi_html/laravel/public
<Directory "/home/kusanagi/kusanagi_html/laravel/public">
```
この状態でkusanagiのhttpdサブコマンドを打つとApacheに切り替わります。

```bash:
$ sudo kusanagi httpd
httpd を使用します
完了しました
$ sudo kusanagi status
*** nginx ***
● nginx.service - The NGINX HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
   Active: inactive (dead)

*** Apache2 ***
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: active (running) since 火 2016-12-13 09:28:00 JST; 10min ago

*** HHVM ***
● hhvm.service - HHVM virtual machine, runtime, and JIT for the PHP language
   Loaded: loaded (/etc/systemd/system/hhvm.service; disabled; vendor preset: disabled)
   Active: inactive (dead)

*** php-fpm ***
● php-fpm.service - The PHP FastCGI Process Manager
   Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; disabled; vendor preset: disabled)
   Active: inactive (dead)

*** php7-fpm ***
● php7-fpm.service - The PHP FastCGI Process Manager
   Loaded: loaded (/usr/lib/systemd/system/php7-fpm.service; enabled; vendor preset: disabled)
   Active: active (running) since 火 2016-12-13 00:20:28 JST; 9h ago
```

Active: activeとなっているミドルウェアが動作しているので、PHP7とApacheで動いていることがわかります。

```bash:
$ ab -n 1000  -c 100 http://kusanagi-laravel.jp/
Server Software:        Apache
Server Hostname:        kusanagi-laravel.jp
Server Port:            80

Document Path:          /
Document Length:        1023 bytes

Concurrency Level:      100
Time taken for tests:   2.881 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      2017120 bytes
HTML transferred:       1023000 bytes
Requests per second:    347.07 [#/sec] (mean)
Time per request:       288.124 [ms] (mean)
Time per request:       2.881 [ms] (mean, across all concurrent requests)
Transfer rate:          683.68 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   1.5      0       7
Processing:    16  273  59.6    280     687
Waiting:       16  273  59.6    280     687
Total:         20  274  58.7    281     688

Percentage of the requests served within a certain time (ms)
  50%    281
  66%    285
  75%    288
  80%    290
  90%    303
  95%    325
  98%    397
  99%    481
 100%    688 (longest request)
```

Requests per secondが__347.07__となっています。
nginxよりは劣るものの、通常のLAMP環境が__37.13__でしたので、同じLAMP環境でも10倍弱のパフォーマンスを出すことができました👏

## まとめ

このようにKUSANAGIは超高速WordPress仮想マシンと謳っているものの、その他のLAMP、LEMPベースのアプリケーションでも高いパフォーマンスを発揮することを確認することができました。
今回のようにLaravelの実行環境としてはもちろん、まだ誰も試していない他のアプリケーションでもKUSANAGIの力を試してみて下さい👍

明日は@makoto1899さんです。