1. hirohero

    Posted

    hirohero
Changes in title
+APIサーバ時代のnginx設定決定版
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,91 @@
+かどうかは別として、こんな構成もできるよ。というネタと思っていただければ。(笑)
+
+**ご注意: この構成は所属先の見解ではなく、また、実運用の実績があるものではありません。あくまでも情報の一つとしてお読みください。**
+
+php-fpm(fastcgi)によるAPIサーバを建てるにあたって、LBをフロントエンドに置いて負荷分散。
+というのは当たり前すぎる構成ですね。
+
+図にするとこんな感じ。
+![スクリーンショット 2017-03-26 14.31.39.png](https://qiita-image-store.s3.amazonaws.com/0/145575/1a5226b0-c4f8-3421-1a20-be111a91f1f1.png)
+
+さて、ここからが本題。
+APIサーバということは、全てのリクエストはフレームワークを経由することになります。
+最近のフレームワークは`public/index.php`を単一のフロントコントローラとしているものがほとんどです。
+LaravelやLumenなどがそうですね。
+
+ということは、バックエンド側にはwebサーバは不要だと思いませんか? phpの処理系である`php-fpm`デーモンだけが立っていれば良いと思いませんか?
+図にするとこんな感じ。
+![スクリーンショット 2017-03-26 14.31.19.png](https://qiita-image-store.s3.amazonaws.com/0/145575/47d5496f-995f-212d-7dab-35642743042d.png)
+
+`php-fpm`はTCP/IPをlistenできるので、元々こういう使い方も想定されているわけですね。
+
+この構成だとwebサーバが1つ減るのでオーバヘッドが減ります。CPU処理コスト、メモリ消費、アクセスログの書き出しアクセス、(webサーバ → php-fpmの)内部接続コストがなくなります。サーバ間の役割がはっきり分離できるのもポイントだと思いませんか?
+
+静的ファイルについてはフロントエンド側で対応するか、静的専用のwebサーバを建てるか、S3のwebホスティングを使うか、CDNを使えば十分ですね。
+
+
+# 具体的な設定方法
+nginxをフロントエンド(LB)にした場合の設定例です。
+httpsでリクエストを受けてSSL terminationをした上で、複数のバックエンドにラウンドロビンでロードバランスする構成です。
+
+## php-fpm(バックエンド側)
+こちらは極めて単純。
+listenアドレスに`0.0.0.0`を指定してデーモンを再起動するだけ。
+
+```ini:/etc/php/fpm-php7.1/fpm.d/www.conf
+listen = 0.0.0.0:9000
+```
+
+## nginx(フロントエンド側)
+```nginx:/etc/nginx/conf.d/frontend.conf
+upstream backends {
+ server [backend IP 1]:9000;
+ server [backend IP 2]:9000;
+}
+
+server {
+ listen 443 ssl http2;
+ server_name site.localdomain;
+
+ charset utf-8;
+ root /var/www/html;
+
+ access_log /var/log/nginx/access.log;
+ error_log /var/log/nginx/error.log;
+
+ # SSL terminationをする場合
+ ssl on;
+ ssl_certificate /path/to/cert.pem;
+ ssl_certificate_key /path/to/key.pem;
+
+ location / {
+ try_files $uri /index.php?$query_string;
+ }
+
+ location ~ \.php$ {
+ fastcgi_pass backends;
+ fastcgi_index index.php;
+ fastcgi_param SCRIPT_FILENAME [php-fpm側のindex.phpがあるディレクトリのpath]$fastcgi_script_name;
+ include fastcgi_params;
+ }
+}
+```
+
+ポイントは3つ。
+
+- バックエンド側の`php-fpm`サーバを、upstreamとして登録する。
+- **nginx側のrootディレクトリ(`/var/www/html`)に、ダミーのindex.phpファイルを作成しておく。(重用)**
+- `SCRIPT_FILENAME` は php-fpm側のindex.phpがあるディレクトリを指定する。
+
+ダミーのindex.phpが必要なのは、`try_files`でリクエストURLが`/index.php`に変換されて存在チェックが入るからです。
+このチェックが通らないと、`location ~ \.php$`に制御が渡らず`404 NotFound`となってしまいます。
+
+`index.php`ファイルは存在している事自体が重要なので、中身は空でもかまいません。
+
+```bash
+touch /var/www/html/index.php
+```
+
+このあたりがもう少しエレガントに設定できれば良いのですが、他の方法が思いつきませんでした。
+
+一応手元で環境構築してテストしたところ、ちゃんとラウンドロビンされてることと、バックエンドサーバを停止したらそこへの振り分けが停止され、バックエンドサーバを再開したら再度振り分け対象になったことは確認できました。