13 julio 2008

Instalando Passenger (modrails) con Ubuntu 8.04 (aka Hardy Heron)

Voy a explicar los pasos que he seguido para instalar Passenger en Ubuntu 8.04, puesto que los "oficiales" que explica el instalador de Passenger no funcionan sin antes retocar algunos sencillos aspectos de la configuración de Apache.

Para empezar, doy por hecho que ya tenemos instalado en nuestro sistema los ingredientes previos necesarios, o sea Ruby, RubyGems y Rails. En caso contrario, sólo hay que seguir estos pasos (se explica para Ubuntu 7.10, pero imagino que no cambia casi nada para 8.04).

Paso 0: Evidentemente, debemos tener instalado Apache 2:
$ sudo apt-get install apache2
Paso 0,5: Además, necesitaremos las librerías de desarrollo de este, para que el instalador de Passenger pueda compilar el módulo:
$ sudo apt-get install apache2-prefork-dev
Paso 1: Instalar Passenger, con el "método fácil":
$ sudo gem install passenger
$ sudo passenger-install-apache2-module
Paso 2: Configurar Apache 2:
El segundo comando del paso anterior lanza el instalador del módulo de Passenger para Apache, que busca dónde está este, compila el módulo y lo instala. Además nos indica que debemos añadir las siguientes líneas al fichero de configuración de Apache, cosa que haremos con nuestro editor favorito y con permisos de root (el contenido de las líneas puede variar ligeramente):
$ sudo vim /etc/apache2/apache2.conf
Las lineas a añadir (al final del fichero) son:
# Passenger (modrails) module:
LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-2.0.1/ext/apache2/mod_passenger.so
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-2.0.1
PassengerRuby /usr/bin/ruby1.8
Paso 3: Probarlo con una aplicación Rails que sea über-cool.
Creamos nuestra aplicación rails con:
$ rails /home/usuario/my_fantastic_blog
$ cd /home/usuario/my_fantastic_blog
$ rake db:create
$ rake db:migrate
Ahora tenemos 2 opciones: modificar la configuración del sitio por defecto que trae Apache en ubuntu (/etc/apache2/sites-available/default) creamos un virtual host aparte como nos recomienda el instalador de Passenger. Yo he optado por esta última opción (¡atención a poner como DocumentRoot el directorio public de nuestra aplicación Rails!):
$ sudo vim /etc/apache2/sites-available/my_fantastic_blog
Ponemos esto:
<VirtualHost 127.0.0.1:8000>
   ServerName localhost
   DocumentRoot /home/usuario/my_fantastic_blog/public
</VirtualHost>
Y creamos un enlace simbólico que le indica a Apache que el nuevo virtual host está disponible:
$ sudo ln -s /etc/apache2/sites-available/my_fantastic_blog /etc/apache2/sites-enabled/001-my_fantastic_blog
E indicamos que nuestra aplicación estará disponible en el puerto 8000:
$ sudo vim /etc/apache2/ports.conf
Añadiendo la línea Listen 8000 al fichero /etc/apache2/ports.conf de forma que quede tal que así:
Listen 80
Listen 8000
<IfModule mod_ssl.c>
   Listen 443
</IfModule>
Finalmente, recargamos la configuración de Apache y ponemos en el navegador la dirección http://localhost:8000 para ver nuestra flamante aplicación Rails corriendo con Passenger:
$ sudo /etc/init.d/apache2 force-reload

PD
: Con una prueba rápida (y para nada científica :) he comparado Passenger + Apache2 contra 1 único Mongrel (corriendo en el puerto 3000 y con entorno de producción) usando para ello la herramienta httperf y la configuración por defecto tanto de Mongrel como de Passenger y Apache, resultando que: modrails es la leche! XDD. Para ser justos, debería haber utilizado nginx + un cluster de mongrels, pero daba una pereza de configurar.... Se aprecia en los resultados que un único Mongrel simplemente no puede con tantas conexiones, de ahí los errores de timeout. El PC es un Pentium 4 HT @ 2.6 GHz, con 1 GB de RAM.

Resultados para mongrel:
$ httperf --port 3000 --rate 300 --num-conn 2700 --num-call 1 --timeout 5
httperf --timeout=5 --client=0/1 --server=localhost --port=3000 --uri=/ --rate=300 --send-buffer=4096 --recv-buffer=16384 --num-conns=2700 --num-calls=1
Maximum connect burst length: 4

Total: connections 2700 requests 2366 replies 2354 test-duration 13.031 s

Connection rate: 207.2 conn/s (4.8 ms/conn, <=752 concurrent connections) Connection time [ms]: min 1.6 avg 1250.2 max 7995.8 median 704.5 stddev 1265.8 Connection time [ms]: connect 716.3 Connection length [replies/conn]: 1.000 Request rate: 181.6 req/s (5.5 ms/req)
Request size [B]: 60.0

Reply rate [replies/s]: min 197.8 avg 199.9 max 202.0 stddev 2.9 (2 samples)
Reply time [ms]: response 537.9 transfer 0.0
Reply size [B]: header 197.0 content 7557.0 footer 0.0 (total 7754.0)
Reply status: 1xx=0 2xx=2354 3xx=0 4xx=0 5xx=0

CPU time [s]: user 0.68 system 11.69 (user 5.2% system 89.7% total 95.0%)
Net I/O: 1378.5 KB/s (11.3*10^6 bps)

Errors: total 346 client-timo 346 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
Resultados para Passenger:
$ httperf --port 8000 --rate 300 --num-conn 2700 --num-call 1 --timeout 5
httperf --timeout=5 --client=0/1 --server=localhost --port=8000 --uri=/ --rate=300 --send-buffer=4096 --recv-buffer=16384 --num-conns=2700 --num-calls=1
Maximum connect burst length: 1

Total: connections 2700 requests 2700 replies 2700 test-duration 8.998 s

Connection rate: 300.1 conn/s (3.3 ms/conn, <=3 concurrent connections) Connection time [ms]: min 0.1 avg 0.6 max 8.6 median 0.5 stddev 0.3 Connection time [ms]: connect 0.0 Connection length [replies/conn]: 1.000 Request rate: 300.1 req/s (3.3 ms/req)
Request size [B]: 60.0

Reply rate [replies/s]: min 300.0 avg 300.0 max 300.0 stddev 0.0 (1 samples)
Reply time [ms]: response 0.6 transfer 0.0
Reply size [B]: header 260.0 content 7557.0 footer 0.0 (total 7817.0)
Reply status: 1xx=0 2xx=2700 3xx=0 4xx=0 5xx=0

CPU time [s]: user 1.88 system 6.46 (user 20.8% system 71.8% total 92.6%)
Net I/O: 2308.2 KB/s (18.9*10^6 bps)

Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0


Actualización
Acabo de encontrar este enlace donde explica este mismo procedimiento para Ubuntu 7.10 (eso sí, en inglés) junto con una bonita tarea de Capistrano que hace automáticamente un touch del fichero my_fantastic_blog/tmp/restart.txt (el cual reinicia la aplicación Rails) y además elimina el fichero my_fantastic_blog/tmp/public/.htaccess que según el puede causar problemas.