Multiples RoR en producción, con Unicorn y Nginx

Del: 29 Agosto 2010 por: ccastillop dentro de:

Busco instalar Ruby on Rails 3rc y Ruby on Rails 2.3.8 para dos aplicaciones en un servidor para producción. Se usa Unicorn y Nginx en vez de Passenger y Apache

La idea es tener diversas versions de Ruby on Rails, con sus respectivas gemas, para poder usar aplicaciones RoR2.3 y RoR 3 en un mismo servidor, evitando conflictos entre las gemas.

¿Cómo lograrlo?

Para esto se necesita un servidor listo para usar. Yo configuré un VPS Linode de 512RAM con Debian 5 Lenny 32 bits

Luego, es bueno configurar el servidor con los pasos que existen en Articles.Slicehost.com:

También instalé MySQL:

sudo aptitude install mysql-server mysql-client libmysqlclient15-dev

Luego, usé las instrucciones para instalar diversos rubies mediante RVM. Aquí el truco es instalar los Ruby en modo "system wide" para que estén disponibles: RVM system wide.

Luego, estas instrucciones rvm-plays-nice-on-production, desde el paso 7 hasta el final, terminará con una buena instalación. En mi caso, mi usuario (ccastillo) permite instalar los distintos rubies.

Luego, instalo el ruby que me interesa y preparo mi entorno inicial, RoR 3 Antes, es buena voz que, cuando instalamos las GEM, no se instalen los Ri docs ni los Rdocs, ocupan mucho tiempo en instalarse y no los vamos a consultar. Entonces, me conecto al server con mi usuario (ssh ccastillo@"server")

sudo nano /etc/gemrc
Agregar la línea gem: --no-rdoc --no-ri

Luego, instalar los Ruby que se deseen. Por ahora poner por defecto el 1.8.7

rvm install 1.8.7
rvm install ree
rvm use 1.8.7 --default
rvm gemset create rails3rc
rvm 1.8.7@rails3rc
gem install rails --pre

Por ahora he terminado con Ruby y con Rails. Instalamos Nginx en el servidor. Para instalar Nginx, basta un comando

sudo aptitude install nginx

Sin embargo, se instala la versión 0.6.32. La última versión es la 0.7 y hasta la 0.8. Si deseas la última versión, te recomiendo esta guía de Slicehost

Ahora la configuración de Nginx con Unicorn. Como vamos a usar Nginx como pasarela (proxy) para canalizar las solicitudes Http a la aplicación Rails, la configuración que utilizo la tomo de debian-lenny-nginx-configuration inicialmente. Luego, la ajusto para seguir con esta guía: configuring-nginx-and-unicorn

Entonces, primero sigo la guía de Slicehost para configurar nginx y ver que todo funciona. Me queda un archivo /etc/nginx/nginx.conf como este:

user www-data;
worker_processes  4;

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    access_log  /var/log/nginx/access.log;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  10;
    tcp_nodelay        on;

    gzip  on;
    gzip_comp_level 2;
    gzip_proxied any;
    gzip_types      text/plain text/html text/css application/x-javascript     text/xml
                application/xml application/xml+rss text/javascript;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Sigo ahora la guía para instalar un servidor virtual (debian-lenny-nginx-virtual-hosts-1)[http://articles.slicehost.com/2009/9/1/debian-lenny-nginx-virtual-hosts-1]. En sí la guía nos dice que se configura un dominio virtual creando un archivo en /etc/nginx/sites-avaiable.

server {

            listen   80;
            server_name  www.domain1.com;
            rewrite ^/(.*) http://domain1.com/$1 permanent;

           }


server {

            listen   80;
            server_name domain1.com;

            access_log /home/ccastillo/apps/domain1.com/log/access.log;
            error_log /home/ccastillo/apps/domain1.com/log/error.log;

            location / {

                        root   /home/ccastillo/apps/domain1.com/public/;
                        index  index.html;

                        }

            }

Y luego habilito el sitio virtual con un link simbólico. También elimino el servidor "default", para evitarme problemas.

sudo ln -s /etc/nginx/sites-available/domain1.com /etc/nginx/sites-enabled/domain1.com
sudo rm /etc/nginx/sites-enabled/default

Reinicio Nginx y el nuevo sitio debería ser visible. (Previamente has configurado bien los DNS del dominio ¿no?)

En mi caso, estoy creando el dominio http://domain1.com, he apuntado el IP de mi server a ese dominio y he creado una aplicación de pruebas en /home/ccastillo/apps/domain1.com. He creado una aplicación de prueba y reiniciado el nginx,

rails new domain1.com --database=mysql
sudo /etc/init.d/nginx restart

Ya el sitio será visible en http://domain1.com. Se ha logrado configurar RVM, Rails 3 y nginx. Ahora, le toca el turno a Unicorn. Siguiendo con el usuario (ccastillo) y ruby 1.8.7 con las gemas de Rails3rc

rvm 1.8.7@rails3rc
gem install unicorn

Ahora sigo las guías de configuring-nginx-and-unicorn modificando el archivo de configuración del dominio domain1.com:

Primero, crear un archivo en la aplicación: config/unicorn.rb. Este archivo le dice al Rack de Rails que utilice Unicorn como webserver: Modifica el wd (working directory) a donde esté tu aplicación.

wd = "/home/ccastillo/apps/mbacentrum.com" 
worker_processes 2
working_directory wd

# This loads the application in the master process before forking
# worker processes
# Read more about it here:
# http://unicorn.bogomips.org/Unicorn/Configurator.html
preload_app true

timeout 30

# This is where we specify the socket.
# We will point the upstream Nginx module to this socket later on
listen "#{wd}/tmp/sockets/unicorn.sock", :backlog => 64

pid "#{wd}/tmp/pids/unicorn.pid"

# Set the path of the log files inside the log folder of the testapp
stderr_path "#{wd}/log/unicorn.stderr.log"
stdout_path "#{wd}/log/unicorn.stdout.log"

before_fork do |server, worker|
# This option works in together with preload_app true setting
# What is does is prevent the master process from holding
# the database connection
  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
# Here we are establishing the connection after forking worker
# processes
  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.establish_connection
end

Ahora le decimos a Nginx que utilice Unicorn como pasarela, modificando /etc/sites-avaiable/domain1.com que queda así:

#servidor unicorn
upstream unicorn_domain1 {
 # This is the socket we configured in unicorn.rb
 server unix:/home/ccastillo/apps/domain1.com/tmp/sockets/unicorn.sock fail_timeout=0;
}


server {

  listen 80;
  server_name  www.domain1.com;
  rewrite ^/(.*) http://domain1.com/$1 permanent;

}


server {

  # listen   80;
  server_name domain1.com;
  keepalive_timeout 5;

  access_log /home/ccastillo/apps/domain1.com/log/access.log;
  error_log /home/ccastillo/apps/domain1.com/log/error.log;
  root   /home/ccastillo/apps/domain1.com/public/;

  location / {

    #index  index.html;

    if (-f $request_filename) {
      access_log off;
      rewrite_log off;
      expires 30d;
      break;
    }

    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
    proxy_redirect off;

    if (!-f $request_filename) {
      # my_web_app needs to be the same as whatever upstream name you assigned above
      proxy_pass http://unicorn_domain1;
      break;
    }

  }


}

Y se inician el demonio Unicorn desde tu aplicación Rails.

unicorn_rails -c config/unicorn.rb -D

Si no arranca, ver los errores en "cat log/unicorn.stderr.log". En mi caso faltó un "sudo aptitude install sqlite3 libsqlite3-dev" y luego "bundle install". Se instaló de una vez MySQL. Parece ser que Debian Lenny tiene un Sqlite muy antiguo y no funciona con la gema de Ruby.

Hay que estar seguros que la aplicación Ruby on Rails funciona correctamente, revisando constantemente ese log de errores del Unicorn.

Suerte!

P.D. falta el iniciar y parar Unicorn, y la puesta en servicio (deploy) con Capistrano:

http://github.com/blog/519-unicorn-god

http://www.stopdropandrew.com/2010/06/01/where-unicorns-go-to-die-watching-unicorn-workers-with-monit.html

Receta Capistrano para deploy con Unicorn:

http://gist.github.com/393178

Unicorn init script http://gist.github.com/308216

Github strategy http://github.com/blog/470-deployment-script-spring-cleaning

Bookmark and Share

Dentro de Arquitectura Etiquetado como ruby on rails, RVM

1 comentarios

A15258c4859d845df34ee9922ad34aec

Por: Alex el: 01 Setiembre 2010 19:00

Buen articulo hermano.. en la revista del mes pasado de Rails, viene un buen articulo sobre RVM.. Saludos.

Nuevo comentario