#292 Virtual Machines with Vagrant
- Download:
- source codeProject Files in Zip (41.1 KB)
- mp4Full Size H.264 Video (27.3 MB)
- m4vSmaller H.264 Video (13.6 MB)
- webmFull Size VP8 Video (13.2 MB)
- ogvFull Size Theora Video (30.4 MB)
Como desarrolladores Rails con frecuencia nos encontraremos con que nuestro entorno de desarrollo es muy distinto del entorno de producción. De hecho no es nada raro tener que desarrollar la aplicación en un sistema operativo distinto del que se ejecutará en producción. Por otro lado, las aplicaciones Rails suelen tener también muchas dependencias que pueden ser difíciles de replicar en varias máquinas diferentes.
Vagrant nos puede ser útil para solventar este problema. Permite configurar y manipular entornos de máquinas virtuales por lo que podemos configurar una pequeña distribución linux dentro nuestro sistema operativo para ejecutar en ella nuestra aplicación junto con todas sus dependencias, pudiéndose empaquetar todo de manera portable para poder compartirlo con otros.
Probar Vagrant resultará muy útil para todos los programadores Rails ya que da una idea precisa sobre cómo configurar un entorno de producción para las aplicaciones, y también resulta útil para configurar entornos de preproducción
Instalación de Virtual Box y Vagrant
Vagrant utiliza VirtualBox de Oracle, por lo que tendremos que instalarlo en nuestra máquina si todavía no lo hemos hecho. VirtualBox está disponible para Windows, OS X y Linux, por lo que deberíamos poder encontrar una versión instalable en nuestro sistema operativo. Una vez que tengamos VirtualBox podemos instalar Vagrant, que es una gema de Ruby que se instala ejecutando la siguiente orden:
$ gem install vagrant
Creación de una máquina
El siguiente paso es crear una máquina virtual, lo que Vagrant denomina una caja. Hay una lista de máquinas disponibles en Vagrantbox.es, de donde se pueden descargar. Usaremos Ubuntu lucid 32, que está basada en Ubuntu Linux 10.04. Para instalar la caja tan sólo tenemos que lanzar vagrant box add
pasandole el nombre y la URL de la máquina.
$ vagrant box add lucid32 http://files.vagrantup.com/lucid32.box [vagrant] Downloading with Vagrant::Downloaders::HTTP... [vagrant] Downloading box: http://files.vagrantup.com/lucid32.box [vagrant] Extracting box... [vagrant] Verifying box... [vagrant] Cleaning up downloaded box...
Las cajas pueden ser bastante grandes (del orden de varios cientos de megabytes) por lo que la descarga puede tardar un rato. Si ya tenemos la caja descargada podemos pasar una URL de archivo para instalar desde el sistema de archivos local.
Tras la descarga de la caja y su instalación podemos empezar a usarla para configurar nuestro entorno virtual. En Vagrant esto se hace por lo general para un proyecto específico, así que crearemos un nuevo proyecto con el que trabajar, y luego nos cambiaremos a su directorio.
$ rails new todo $ cd todo
Podemos crear una máquina virtual para esta aplicación y sus dependencias ejecutando vagrant init
y pasando el nombre de la caja que queremos utilizar.
$ vagrant init lucid32 create Vagrantfile
Lo que hace esta orden es crear un archivo llamado Vagrantfile
. El fichero contiene la información sobre la configuración de la caja Vagrant vinculada a esta aplicación y por defecto toda esta información viene comentada salvo la línea que especifica la caja a utilizar.
Vagrant::Config.run do |config| # All Vagrant configuration is done here. The most common configuration # options are documented and commented below. For a complete reference, # please see the online documentation at vagrantup.com. # Every Vagrant virtual environment requires a box to build off of. config.vm.box = "lucid32" # Rest of file omitted. end
Hay otras muchas opciones de configuración disponibles y merece la pena dedicar un minuto para estudiarlas.
Inicio de la máquina virtual de Vagrant
Es hora de que comience la magia. Lanzando vagrant up
comenzará el arranque de nuestra máquina virtual, lo que puede llevar varios minutos pero una vez que hayamos terminado podemos hacer SSH en ella con
$ vagrant ssh
Ya estamos dentro de nuestra máquina Virtual con Ubuntu. Se trata de una configuración con muy pocos paquetes instalados pero hay un par de cosas que merece la pena destacar. La primera es que existe el usuario vagrant
(que es con el que hemos iniciado la sesión), y el otro es que tenemos privilegios de sudo
sin necesidad de clave, lo cual está bien para nuestro entorno de desarrollo. Vagrant también deja configurado un directorio compartido en /vagrant
que apunta al directorio donde tenemos nuestra aplicación Rails.
Instalación de las dependencias de nuestra aplicación
El objetivo es poner en marca nuestra aplicación Rails dentro de la máquina virtual, por lo que tendremos que cargar sus dependencias. Primero tenemos que instalar Ruby y Sqlite. La máquina virtual viene con Ruby 1.8.7, por lo que puede ejecutar Recetas de Chef.
Chef permite automatizar la configuración de los servidores. Para instalar Ruby 1.9 y Sqlite podríamos aplicar las recetas necesarias y Chef las instalará por nosotros. Chef se integra muy bien con Vagrant pero es un tema aparte que veremos en un episodio futuro, así que vamos a configurar nuestro servidor sin usar Chef con lo que tendremos una mejor idea de cómo encajan todas las piezas.
Primero usaremos apt-get
para garantizar que el software instalado está al día.
$ sudo apt-get update
Tras esto, instalaremos el software que nos hace falta: lo esencial para compilar software, Zlib, Git y Sqlite3.
$ sudo apt-get install build-essential zlib1g-dev git-core sqlite3 libsqlite3-dev
Lo último que nos queda por instalar es Ruby 1.9. Podríamos instalarlo de cero o utilizando RVM pero vamos a usar una nueva herramienta llamada rbenv. Una ventaja de Vagrant es que podemos experimentar en un entorno seguro con herramientas que no hayamos usado antes, y si se rompe algo siempre podemos borrar la máquina virtual y empezar de cero.
Para instalar rbenv en nuestra máquina virtual tan sólo tenemos que lanzar las órdenes que se mencionan en la sección 2.1 del README. Primero clonaremos el repostorio en ~/.rbenv
.
$ cd $ git clone git://github.com/sstephenson/rbenv.git .rbenv
A continuación añadiremos el directorio bin
de rbenv en nuestro PATH y lo ejecutaremos con la opción init
en nuestro perfil de Bash.
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
Tendremos que volver a cargar el perfil de bash para que los cambios surtan efecto.
$ source .bash_profile
Ya tenemos disponible la orden rbenv
, que podemos utilizar para gestionar nuestras versiones de Ruby, pero todavía no podemos instalar Ruby. Utilizaremos Ruby Build para ello, tan sólo tenemos que clonar su repositorio Git y una vez dentro del directorio ejecutar su script de instalación.
$ git clone https://github.com/sstephenson/ruby-build.git $ cd ruby-build $ sudo ./install.sh
Podemos usar rbenv para instalar la versión actual de Ruby, la 1.9.2
$ rbenv install 1.9.2-p290
Tras esto habremos compilado Ruby 1.9.2. Tenemos que ejecutar rbenv rehash
cada vez que cambiemos los binarios y luego tenemos que ejecutar la siguiente orden para que 1.9.2 sea la versión global por defecto de Ruby en nuestra máquina virtual.
$ rbenv global 1.9.2-p290
Cuando comprobemos la versión de Ruby, veremos que es la 1.9.2, tal y como queríamos.
$ ruby -v ruby 1.9.2p290 (2011-07-09 revision 32553) [i686-linux]
Instalación de nuestra aplicación Rails
Una vez que tenemos la versión correcta de Ruby, podemos empezar a trabajar en levantar la aplicación Rails. Si cambiamos al directorio compartido de nuestra aplicación y ejecutamos bundle
para cargar sus dependencias nos toparemos con un problema.
vagrant@lucid32:~$ cd /vagrant/ vagrant@lucid32:/vagrant$ bundle bundle: command not found
Para corregir este problema sólo tenemos que instalar la gema Bundler
$ gem install bundler
Una vez que se haya instalado la gema tan sólo tenemos que ejecutar rbenv rehash
para que esté disponible el ejecutable bundle
. Ya podemos ejecutar bundle
para instalar las gemas de nuestra aplicación.
Si intentamos lanzar la aplicación ahora devolverá un error quejándose de que no puede encontrar un entorno de ejecución JavaScript. Tiene sentido, porque Rails 3.1 requiere que exista un entorno de JavaScript, y Ubuntu no viene con uno por defecto. La solución rápida es añadir una gema llamada therubyracer a nuestro Gemfile y ejecutar bundle
dentro de la máquina virtual. Con esto se instalará el motor JavaScript V8.
gem 'therubyracer'
Tras la instalación de esta gema podemos intentar lanzar el servidor otra vez.
$ bundle exec rails s
Esta vez arranca correctamente y nuestra aplicación se carga en el puerto 3000. No podemos verla en el navegador, porque está en ejecución dentro de la máquina virtual. Tenemos que decirle a Vagrant que redirija el puerto a nuestra máquina, lo que podemos hacer modificando el Vagrantfile
. Tenemos que descomentar la siguiente línea, ponerle un nombre más adecuado y decirle que dirija el puerto 3000 al mismo puerto en nuestra máquina local.
config.vm.forward_port "rails", 3000, 3000
Tras este cambio de configuración tenemos que salir de nuestra sesión en Vagrant ejecutando exit
dentro de la máquina virtual y luego volviendo a cargarla con vagrant reload
. Esto parará la máquina virtual y la recargará a continuación. Tras esto podemos volver a hacer SSH.
$ vagrant ssh
Ya en la máquina virtual podemos cambiarnos al directorio de nuestra aplicación y lanzar nuevamente el servidor.
vagrant@lucid32:~$ cd /vagrant vagrant@lucid32:/vagrant$ bundle exec rails s
Con esto arranca otra vez el servidor pero ya está accesible desde nuestra máquina.
Como la aplicación Rails está compartida con Vagrant, cualquier cambio que hagamos en el directorio de nuestro ordenador se verá reflejado en la máquina virtual. Si modificamos la página en /public/index.html
y recargamos el navegador, veremos los cambios inmediatamente.
<h2>You’re riding Ruby on Rails on Vagrant!</h2>
Otras posibilidades de Vagrant
Vagrant proporciona varias órdenes para gestionar la máquina virtual. Por ejemplo, para ver el estado actual podemos lanzar vagrant status
.
$ vagrant status Current VM states: default running The VM is running. To stop this VM, you can run `vagrant halt` to shut it down forcefully, or you can run `vagrant suspend` to simply suspend the virtual machine. In either case, to restart it again, simply run `vagrant up`.
Para parar temporalmente la máquina y luego reiniciarla podemos usar las órdenes suspend
y resume
.
$ vagrant suspend [default] Saving VM state and suspending execution... $ vagrant resume [default] Resuming suspended VM... [default] Booting VM... [default] Waiting for VM to boot. This can take a few minutes. [default] VM booted and ready for use!
Para parar totalmente la máquina virtual podemos ejecutar vagrant halt
. Luego tendremos que usar vagrant up
otra vez para arrancar la máquina.
Una de las órdenes más útiles es vagrant package
. Esto empaquetará la maquina virtual, en el estado en que se encuentre, en un fichero llamado package.box
. Este fichero se puede compartir y distribuir para recrear fácilmente la máquina virtual. Si luego usamos vagrant destroy
para borrar la máquina virtual, la podemos recuperar después con la misma orden vagrant box add
que usamos la primera vez.
Con esto finaliza nuestro repaso a Vagrant, que es una gran solución para capturar las dependencias de nuestras aplicaciones Rails y aislarlas en un entorno virtualizado que se puede luego empaquetar y distribuir entre otros desarrolladores, o como entorno de preproducción. Vagrant es todavía más útil cuando se utiliza en conjunto con Chef, lo que veremos en un episodio futuro.