jueves, 19 de febrero de 2015

Aprovisionar Vagrant con Ansible y Galaxy

Cuando trabajamos con Vagrant, necesitamos aprovisionar la máquina con las herramientas necesarias para cada uno de los proyectos de forma específica. Para realizar este aprovisionamiento, existen diferentes herramientas como Chef, Puppet y Ansible, por nombrar unos pocos.

Cuando aprovisionamos con Ansible, tenemos varias opciones, pero la que vamos a explicar aquí es como usarlo junto con Galaxy para obtener toda la potencia de los roles que ya tiene a disposición toda la comunidad.

Lo primero de todo y necesario es crear un Vagrantfile donde se indique que se aprovisiona la máquina con Ansible e indicarle el playbook que vamos a utilizar. Esto se hace añadiendo las siguientes lineas.
config.vm.provision 'ansible' do |ansible|
 ansible.playbook = 'ansible/site.yml'
end

Con esto ya tenemos listo Vagrant para que utilice Ansible como provisioner y además ejecute todo lo que nosotros le indiquemos en el site.yml. Un típico ejemplo de LAMP en Ansible podría ser
- hosts: all
  sudo: yes
  vars_files:
    - vars/geerlingguy.apache.yml
    - vars/geerlingguy.php.yml
    - vars/geerlingguy.php-pecl.yml
  roles:
    - { role: geerlingguy.apache }
    - { role: geerlingguy.php }
    - { role: geerlingguy.php-pecl }

Donde vemos que cargamos las distintas variables para cada uno de los roles que hemos importado y definimos los roles en si mismo. Con esto ya tendríamos un entorno con Apache y PHP, donde nos faltaría añadir algún rol de Mysql. Puede encontrar muchos en Ansible Galaxy.

El problema de este sistema radica en que los roles tiene que ser descargados manualmente desde Galaxy y eso no nos garantiza tener los roles actualizados, ni resolver las dependencias entre ellos, por lo que aquí entra al rescate librarian-ansible. Esta herramienta nos permite automatizar toda la descarga de roles desde Galaxy y así evitar el proceso manual.

Como lo único que hace es evitar el proceso manual, lo que hará será descargar los roles en una carpeta. Para eso tendremos que crear junto a nuestro site.yml un archivo llamado Ansiblefile con un contenido similar al siguiente, con los roles que más nos interesen.
#!/usr/bin/env ruby
#^syntax detection
# @see https://github.com/bcoe/librarian-ansible

site "https://galaxy.ansible.com/api/v1"

role "geerlingguy.apache"
role "geerlingguy.php-pecl"
role "geerlingguy.php"

Este archivo será revisado por librarian-ansible cada vez que queramos actualizar/instalar roles. Para instalar y actualizar los roles, solamente necesitamos ejecutar
$ librarian-ansible install

Installing geerlingguy.apache (0.0.0)
Installing geerlingguy.php (0.0.0)
Installing geerlingguy.php-pecl (0.0.0)

Con esto podemos ver que librarian nos ha creado una carpeta llamada librarian, donde se encuentran todos los roles que habíamos definido en el Ansiblefile. Además este nos ha creado un archivo llamado Ansiblefile.lock, donde se puede ver en su contenido las versiones de las librerías que tenemos instaladas y cuales son.

GIT
  remote: https://github.com/geerlingguy/ansible-role-apache
  ref: master
  sha: 2abee5155caf66c5ff53d92a46b96a604244cc42
  specs:
    geerlingguy.apache (0.0.0)

GIT
  remote: https://github.com/geerlingguy/ansible-role-php
  ref: master
  sha: ee9a827049ff6e02864679861675dd3ac6f356b5
  specs:
    geerlingguy.php (0.0.0)

GIT
  remote: https://github.com/geerlingguy/ansible-role-php-pecl
  ref: master
  sha: 4d23c5e8902b0e5de905c12ab8901c89110f141a
  specs:
    geerlingguy.php-pecl (0.0.0)

DEPENDENCIES
  geerlingguy.apache (>= 0)
  geerlingguy.php (>= 0)
  geerlingguy.php-pecl (>= 0)

Si ahora ejecutamos Ansible, veremos que ocurre un error donde se indica que los roles no existen y eso es por que por defecto Ansible busca los roles dentro de la carpeta actual, por lo que si queremos que también encuentre los que se encuentran dentro de la carpeta librarian, tendremos que indicárselo. Para ello, creamos el archivo ansible.cfg junto a nuestro Vagrantfile con el siguiente contenido
[defaults]

# additional paths to search for roles in, colon separated
roles_path = ansible/librarian                           

Con esto ya lo tendríamos todo listo para funcionar, solo necesitaremos ejecutar librarian-ansible update antes de hacer un vagrant provision para así actualizar nuestros roles.