ラベル nginx の投稿を表示しています。 すべての投稿を表示
ラベル nginx の投稿を表示しています。 すべての投稿を表示

2017年7月17日月曜日

1つのサーバに2つのrailsアプリを共存させる方法

個人で作成しているKindleセール本まとめサイトで、railsアプリを1サーバに共存させる必要が出てきたのでその方法。

概要

http://kinsume.infoにアクセスした時はrails5.0.1のアプリに飛ばして、http://kinsume.info/kinsume_blogにアクセスされた時は、rails4.2.7のアプリに飛ばしたい。
kinsume_blogで動くアプリはオープンソースのCMS refinery-cmsを使用したかったのだが、rails4.x系にしか対応していなかったので、苦肉の策ではある。

環境はUbuntu, Nginx, Unicorn。

手順

まず、すでに動いているrails5.x系, ruby 2.3.xの環境には影響を与えたくなかったので、ruby 2.2.7をインストールして、ruby周りの環境を整える。


cd ~/repos/kinsume_blog
rbenv local install 2.2.7
gem install bundler
bundle install

Unicornの設定ファイルを作成

新しく設定したいアプリの下で、vim config/unicorn.rbでファイルを新規作成。


app_path = File.expand_path(File.dirname(__FILE__) + '/..')$
$
# workerをいくつ立ち上げるか。ここではCMSであまりアクセスないことを$
# 想定していて、メモリの空きもないので1にしている。$
worker_processes 1$
$
# どのソケットで連携するかNginxの設定ファイルにも書くので覚えておく$
listen app_path + '/tmp/kinsume_blog.sock', backlog: 64$
timeout 300$
working_directory app_path$
$
# この辺もすでに動いているアプリと被らないようにする$
pid app_path + '/tmp/kinsume_blog.pid'$
stderr_path app_path + '/log/kinsume_blog.log'$
stdout_path app_path + '/log/kinsume_blog.log'$
$
preload_app true$
$
GC.respond_to?(:copy_on_write_friendly=) &&$
GC.copy_on_write_friendly = true$
$
before_fork do |server, worker|$
defined?(ActiveRecord::Base) &&$
ActiveRecord::Base.connection.disconnect!$
end$
$
after_fork do |server, worker|$
defined?(ActiveRecord::Base) &&$
ActiveRecord::Base.establish_connection$
end$

railsアプリのルートパスを変える。refinery-cmsのパスを変えるには下記ファイルを変更。

vim config/initializers/refinery/core.rb


  # Specify a different Refinery::Core::Engine mount path than the default of "/".$
  # Make sure you clear the `tmp/cache` directory after changing this setting.$
  config.mounted_path = "/kinsume_blog"$


わかりやすくなるように、静的ファイルのパスを元のアプリと変える。

vim config/environments/production.rb


  config.assets.prefix = '/static'$

Nginxの設定ファイルは以下


upstream tagosaku{$
    server unix:/home/ishioka/repos/tagosaku/tmp/tagosaku.sock fail_timeout=0;$
}$

# 先ほど作成したアプリのソケットファイルをここで指定
upstream kinsume_blog{$
    server unix:/home/ishioka/repos/kinsume_blog/tmp/kinsume_blog.sock fail_timeout=0;$
}$
$
server {$
  error_log /var/log/nginx/error.log debug;$
  listen 80;$
$
  root /home/ishioka/repos/tagosaku;$
  index index.html index.htm;$
$
  keepalive_timeout 300;$
  client_max_body_size 4G;$

 # kinsume_blogないで使っているgemから走るアクセスパスをどうしても変えられなかったので悲しみのrewriteで対応
  rewrite ^/wymiframe$ /kinsume_blog/wymiframe last;$
$
  # ここでもkinsume_blogないのgemから走るアクセスを変えられなかったので、いったんassetsを見てふぁいるがなければ/static/を見に行くように変更
  location ~ ^/assets/(.*) {$
    root /home/ishioka/repos/tagosaku/public/;$
    try_files $uri /static/$1 =404;$
  }$
$
 # staticへのアクセスはkinsume_blogの静的ファイルへのアクセスなのでロケーションを変更
  location /static/ {$
    root /home/ishioka/repos/kinsume_blog/public/;$
  }$

  location / {$
    # First attempt to serve request as file, then$
    # as directory, then fall back to displaying a 404.$
    #try_files $uri $uri/ =404;$
$
    # Uncomment to enable naxsi on this location$
    # include /etc/nginx/naxsi.rules$
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;$
    proxy_set_header Host $http_host;$
    proxy_set_header X-Forwarded_Proto $scheme;$
    proxy_redirect off;$
$
    # This passes requests to unicorn, as defined in /etc/nginx/nginx.conf$
    proxy_set_header Host $http_host;$
    proxy_pass http://tagosaku;$
    proxy_read_timeout 300s;$
    proxy_send_timeout 300s;$
  }$
$
  location /kinsume_blog {$
    # First attempt to serve request as file, then$
    # as directory, then fall back to displaying a 404.$
    #try_files $uri $uri/ =404;$
$
    # Uncomment to enable naxsi on this location$
    # include /etc/nginx/naxsi.rules$
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;$
    proxy_set_header Host $http_host;$
    proxy_set_header X-Forwarded_Proto $scheme;$
    proxy_redirect off;$
$
    # This passes requests to unicorn, as defined in /etc/nginx/nginx.conf$
    proxy_set_header Host $http_host;$
    proxy_pass http://kinsume_blog;$
    proxy_read_timeout 300s;$
    proxy_send_timeout 300s;$
  }$
$
  error_page 500 502 503 504 /500.html;$
$
  location = /500.html {$
    root /home/ishioka/repos/tagosaku/public;$
  }$
}


refinery-cmsのpluginからリクエストされる静的ファイルのパスを/から/kinsume_blogへ変更することができなかったので、nginxのrewriteを駆使して対応。 

あまりアクセスパスを変更されることを想定されてない作りっぽいので、PR出していきたい。





2017年5月1日月曜日

nginxによるアクセス制御に関して調べてみた

業務でアクセス制御する必要があったので、どのような解決策があるかを調べてみた。


要件

ある外部システムをWebAPIで叩いて連携する必要があるが、そのシステムはURLごとに2req/sしか叩かれないように制御したい。

例えば
/searchと/user はそれぞれに2req/sになるように制御したい。

この要件を聞いてみて使えそうかな?とおもったnginx調べてみた。

nginx

http limit req moduleでいけるか調べてみる。
ある$keyごとに1req/secondなど柔軟に処理できそうなので、URLごとにリクエストを制御できるかテストしてみる。

検証環境はmac
  • brew install nginx
  • sudo nginx
  • http://localhost:8080/にアクセスするとデフォルトページが表示された。
index.htmlを / と /testの2つに用意
mkdir /usr/local/var/www/test
cp /usr/local/var/www/index.html /usr/local/var/www/test
そこに$uriごとにアクセス制限をかける以下を追加

http {
    limit_req_zone $uri zone=one:10m rate=2r/s;

    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/access.log  main;

    sendfile        on;

    keepalive_timeout  65;

    server {
        limit_req zone=one burst=5;
        listen       8080;
        server_name  localhost;

        location / {
            root   html;
            index  index.html index.htm;
        }

設定完了したので、nginx再起動。

sudo nginx -s reload

そしてアクセスログを見守りつつ、/ と /testにpararel 4,  request数12で飛ばす。
ab -n 12 -c 4 http://127.0.0.1:8080/index.html & ab -n 12 -c 4 http://127.0.0.1:8080/test/index.html
するとアクセスログは以下のように同じ秒間にはuriごとに2リクエストしかさばいてないので、nginxの方でよしなに遅延させて処理してくれた模様。
[01/May/2017:00:31:23 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:23 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:23 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" [01/May/2017:00:31:26 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:26 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:26 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:26 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
秒間をこえたリクエストを遅延して処理するかどうかはburstが決めているのでそれをいじってエラーにしてみる。

十分これで目的を達成できそうな気がするな。