もくじ
- WEB/APサーバが一体化された構成
- WEB/APサーバが分離された構成(WEB:AP = 1:1)
- WEB/APサーバが分離された構成(WEB:AP = 1:多)
- WEB/APサーバが分離された構成(共有ディレクトリ有り)
- UNIXドメインソケット利用時の注意点
1. WEB/APサーバが一体化された構成
WEB(Nginx)とAP(Rails)を1台のサーバ内に収める構成です。
NginxとRailsの連携にはUNIXドメインソケットを利用します。
【Nginx ポケットリファレンスより抜粋】
UNIXドメインソケットのでの接続は同一サーバ内に制限されますが、TCP接続と比べて接続時のオーバーヘッドが少ないので、細かい大量のアクセスを処理する際に負荷の軽減を図ることができます。
Rails
UNIXドメインソケットを利用するために、pumaのコンフィグにsockファイルのパスを指定します。
アプリのtmp/sockets
配下にsockファイルを配置する場合は以下のように記述します。
UNIXドメインソケットでの連携時、TCP通信での連携は不要になるので、port設定をコメントアウトすることでtcpでのlistenを行わなくなります。
# port ENV.fetch("PORT") { 3000 }
...
# UNIXドメインソケット
bind "unix://#{Rails.root}/tmp/sockets/puma.sock"
上記の設定後はrails server
起動時にsockファイルがlistenされるようになります。
$ rails s
...
* Listening on unix:///var/www/my-app/tmp/sockets/puma.sock
Use Ctrl-C to stop
ポートを指定した状態でrails server
を起動した場合はsockファイルがlistenされなくなり、tcpがlistenされます。
$ rails s -p 8080
...
* Listening on tcp://localhost:8080
Use Ctrl-C to stop
Nginx
nginx.confのhttp
ディレクティブ配下にRailsと連携させるための設定を記述します。upstream > server
にUNIXドメインソケットのパスを指定します。
upstream backend {
server unix:/var/www/my-app/tmp/sockets/puma.sock;
}
server {
listen 80;
server_name .*;
root /var/www/my-app/public;
location / {
try_files $uri @app;
}
location @app {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://backend;
}
}
2. WEB/APサーバが分離された構成(WEB:AP = 1:1)
WEB(Nginx)とAP(Rails)を異なるサーバに収める構成です。
1台のWEBサーバに対して1台のAPサーバが割り当てられるケース(WEB:AP = 1:1)では、Nginxのリバースプロキシ機能を利用して連携できます。
Nginx
server {
listen 80;
server_name .*;
root /var/www/my-app/public;
location / {
try_files $uri @app;
}
location @app {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://xx.xx.xx.xx:yyy; # AP(Rails)サーバのIP/PORTを指定する
}
}
WEB/APサーバが一体化された構成での利用
proxy_pass
にローカルホスト( http://127.0.0.1:3000 )を指定すれば、WEB/APサーバが一体化された構成
でも利用可能です。
3. WEB/APサーバが分離された構成(WEB:AP = 1:多)
WEB(Nginx)とAP(Rails)を異なるサーバに収める構成です。
1台のWEBサーバに対して複数台のAPサーバが割り当てられるケース(WEB:AP = 1:多)では、Nginxのロードバランシング機能を利用して連携できます。
Nginx
upstream backend {
server xx.xx.xx.xx:yyy; # AP(Rails)サーバ1のIP/PORTを指定する
server xx.xx.xx.xx:yyy; # AP(Rails)サーバ2のIP/PORTを指定する
server xx.xx.xx.xx:yyy; # AP(Rails)サーバ3のIP/PORTを指定する
}
server {
listen 80;
server_name .*;
root /var/www/my-app/public;
location / {
try_files $uri @app;
}
location @app {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://backend;
}
}
WEB/APサーバが一体化された構成での利用
serverにローカルホスト( http://127.0.0.1:3000 )を指定すれば、WEB/APサーバが一体化された構成
でも利用可能です。
WEB/APサーバが分離された構成(WEB:AP = 1:1)での利用
upstream > server
の指定を1つだけにすれば、WEB/APサーバが分離された構成(WEB:AP = 1:1)
構成でも利用可能です。
4. WEB/APサーバが分離された構成(共有ディレクトリ有り)
WEB(Nginx)とAP(Rails)を異なるサーバに収める構成であっても、共有ディスクの利用やNFSマウントによってWEB(Nginx)とAP(Rails)の両者から同一のsockファイル
にアクセスできる環境を構築すれば、UNIXドメインソケットを利用して「WEB:AP = 1:多」環境を構築することも可能です。
Rails
pumaのコンフィグにsockファイルのパスを指定します。
sockファイルのパスにはWEB(Nginx)と共通しているディレクトリ配下を指定する必要があります。
例:/mnt/web-ap1
がWEB(Nginx)と共有しているディレクトリの場合
# port ENV.fetch("PORT") { 3000 }
...
# UNIXドメインソケット
bind "unix:///mnt/web-ap1/my-app/tmp/puma.sock"
Nginx
upstream > server
にUNIXドメインソケットのパスを指定します。
sockファイルのパスには各AP(Rails)と共有しているディレクトリ配下を指定する必要があります。
例:/mnt/web-ap1~3
が各AP(Rails)と共有しているディレクトリの場合
upstream backend {
server unix:/mnt/web-ap1/my-app/tmp/puma.sock; # AP(Rails)サーバ1のsockファイル
server unix:/mnt/web-ap2/my-app/tmp/puma.sock; # AP(Rails)サーバ2のsockファイル
server unix:/mnt/web-ap3/my-app/tmp/puma.sock; # AP(Rails)サーバ3のsockファイル
}
server {
listen 80;
server_name .*;
root /var/www/my-app/public;
location / {
try_files $uri @app;
}
location @app {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://backend;
}
}
5. UNIXドメインソケット利用時の注意点
UNIXドメインソケットを利用するためにはWEB(Nginx), AP(Rails)両者が同一のsockファイルへアクセスできる必要があります。
sockファイルへのアクセス権や配置ディレクトリが適切ではない場合、ブラウザからアクセスした際にNginxで50xエラーとなりRailsアプリまで到達できませんのでご注意ください。
Permission denied
Nginx
nginxのworkerプロセスを起動するユーザがsockファイルにアクセスする権限がない場合、ブラウザからアクセスした際に503エラー等になります。
その際、Nginxのエラーログには以下のようにPermission denied
と出力されます。
$ sudo tail /var/log/nginx/error.log
2017/10/21 01:46:29 [crit] 3467#0: *82 connect() to unix:/var/www/my-app/tmp/sockets/puma.sock failed (
13: Permission denied) while connecting to upstream, client: xx.xx.xx.xx, server: *, request: "GET / HTTP/1.1", u
pstream: "http://unix:/var/www/my-app/tmp/sockets/puma.sock:/", host: "xx.xx.xx.xx"
対応として、
- アクセス権を設定してworkerプロセス起動ユーザがsockファイルへアクセスできるようにする
- workerプロセス起動ユーザをsockファイルへのアクセス権があるユーザに変更する
などを行います。
Rails
rails server
起動ユーザがsockファイルにアクセスする権限がない場合、サーバ起動に失敗します。
その際、Railsのログには以下のようにPermission denied
と出力されます。
$ rails s
...
* Listening on unix:///mnt/web-ap1/my-app/tmp/puma.sock
Exiting
/xxx/ruby/gems/2.4.0/gems/puma-3.9.1/lib/puma/binder.rb:366:in `initialize':
Permission denied - connect(2) for /mnt/web-ap1/my-app/tmp/puma.sock (Errno::EACCES)
対応として、
- アクセス権を設定してrails server起動ユーザがsockファイルへアクセスできるようにする
- rails server起動ユーザをsockファイルへのアクセス権があるユーザに変更する
などを行います。
No such file or directory
Nginx
nginxのworkerプロセスを起動するユーザがsockファイルにアクセスできない場合、ブラウザからアクセスした際に502エラー等になります。
その際、Nginxのエラーログには以下のようにNo such file or directory
と出力されます。
$ sudo tail /var/log/nginx/error.log
2017/10/22 02:30:13 [crit] 3855#0: *1 connect() to unix:/mnt/web-ap1/my-app/tmp/puma.sock failed (2: No such file or directory) whil
e connecting to upstream, client: xx.xx.xx.xx, server: *, request: "GET / HTTP/1.1", upstream: "http://unix:/mnt/web-ap1/my-app/tm
p/puma.sock:/", host: "xx.xxx.xx.xx"
対応として、
- sockファイルのパスを正しい値に修正する
-
rails server
を起動してsockファイルが存在する状態にする - AP(Rails)との共有ディレクトリをマウントして、WEB(Nginx)からsockファイルにアクセスできるようにする
などを行います。
Rails
rails server
起動ユーザがsockファイルにアクセスできない場合、サーバ起動に失敗します。
その際、Railsのログには以下のようにNo such file or directory
と出力されます。
$rails s
...
* Listening on unix:///mnt/web-ap1/my-app/tmp/puma.sock
Exiting
/xxx/ruby/gems/2.4.0/gems/puma-3.9.1/lib/puma/binder.rb:366:in `initialize':
No such file or directory - connect(2) for /mnt/web-ap1/my-app/tmp/puma.sock(Errno::ENOENT)
対応として、
- sockファイルを配置するディレクトリを作成する
- WEB(Nginx)との共有ディレクトリをマウントして、AP(Rails)からsockファイルにアクセスできるようにする
などを行います。