Vagrant es un programa que aprovecha una plataforma de virtualización para proporcionar un workflow simple de gestión del ciclo de vida de las máquinas virtuales.

Como sistema de virtualización utilizaremos Virtualbox. Su principal ventaja es que es muy sencillo de poner en funcionamiento y además corre en diferentes sistemas operativos anfitrión, como Mac OS X, GNU/Linux y Ms Windows.

La instalación se puede hacer de diversas maneras: con paquetes del sistema operativo anfitrión (en caso que existan como en GNU/Linux), también se puede instalar a partir de los fuentes de cada proyecto, pues se trata de sistemas de software libre. En la primer manera tenemos el problema de que la versión que está empaquetada no siempre es la última estable. En el segundo caso, es muy engorroso instalar toda la cadena de compilador y entorno de desarrollo, luego clonar los repositorios fuentes, y compilar e instalar manualmente; incluso aunque de esta manera tengamos la versión del «último grito de la moda», cuando salga una nueva, vamos a tener que rehacer todo el procedimiento.

Aquí vamos a dar las instrucciones para realizar la instalación utilizando los paquetes binarios disponibles para la descarga en cada proyecto. El motivo es que de esta manera podemos instalar la última versión estable provista por el dueño del proyecto, y será simple su actualización futura. El único inconveniente de este proceder puede ser si el dueño del proyecto no proporciona versiones binarias para las versiones de sistema operativo que necesitamos usar, y ése no es el caso con Debian y Ubuntu.

La opción de usar la instalación mediante el sistema de gestión de paquetes de tu sistema operativo GNU/Linux es buena. En particular es muy simple, por ejemplo en Debian o Ubuntu simplemente uno escribe:

  apt-get install virtualbox dkms vagrant

Si las versiones que consigues de esa manera alcanzan en tu trabajo, por favor, no sigas leyendo este artículo. Si necesitas las versiones actuales de cada paquete, entonces la instalación desde el gestor de paquetes tal vez no alcance, sigue leyendo.

Vamos a instalar entonces primero Virtualbox, luego Vagrant y a continuación algunos plugins muy útiles de Vagrant.

Instalación de Virtualbox

Debemos buscar paquete apropiado a arquitectura y cpu en https://www.virtualbox.org/wiki/Downloads

Son dos:

  1. VirtualBox platform package
  2. Oracle VM VirtualBox Extension Pack

Al momento de escribir esto la versión estable es la 5.1.4, pero la versión de Vagrant no la admite, así que vamos a instalar la versión 5.0.26, tomada desde https://www.virtualbox.org/wiki/Download_Old_Builds_5_0

La instalación en sistemas GNU/Linux está documentada en https://www.virtualbox.org/wiki/Linux_Downloads

La instalación para sistemas MS Windows es un programa ejecutable que se debe descargar y hacer funcionar en el sistema anfitrión.

Los pasos a seguir para instalar Virtualbox son:

  1. Agregar una fuente de paquetes .deb en APT.
  2. Instalar la clave pública de Oracle con la cual están firmados digitalmente los paquetes de ese repositorio del punto anterior.
  3. Actualizar la lista de paquetes conocida por APT.
  4. Instalar el paquete .deb de virtualbox.
  5. Instalar el paquete dkms en Debian y Ubuntu para que cuando se actualiza de manera rutinaria el núcleo del sistema operativo, se hagan las compilaciones de módulos de Virtualbox nacesarias, de manera automática.

Luego procedemos a instalar el Oracle VM VirtualBox Extension Pack.

  1. Descargamos el archivo del Extension Pack.
  2. Usamos VBoxManage para instalar el pack dentro del Virtualbox.

Para evitar errores y acciones manuales, escribí un script en Bash que automatiza todas estas tareas. Sólo hace falta proporcionarle el valor de las versiones que se buscan, y lo demás se realiza sin tropiezos. Las variables de marras son:

VB_MayorVersion=5.0
VB_MinorVersion=26
VB_EXTPACK_ReleaseNumber=108824

y sus valores se obtienen de la página https://www.virtualbox.org/wiki/Downloads antes mencionada. Por ejemplo, el enlace de descarga de las extensiones apunta a un archivo de nombre Oracle_VM_VirtualBox_Extension_Pack-5.0.26-108824.vbox-extpack y de allí se obtiene el 108824 mencionado en la variable VB_EXTPACK_ReleaseNumber.

Instalación de Vagrant

De igual manera que en el caso de Virtualbox, accedemos a la página de descargas de Vagrant en https://www.vagrantup.com/downloads.html y buscamos el paquete apropiado a la arquitectura y cpu.

Al momento de escribir esto, la última versión estable es la 1.8.1.

A diferencia de Virtualbox, no vamos a instalar una fuente de paquetes de APT, sino solamente descargar el archivo del paquete .deb de vagrant y luego lo instalaremos con dpkg -i.

Al igual que en el caso de Virtualbox, a los fines de evitar errores, en el script hay una sección que hace estas tareas, y sólo hay que proporcionarle la versión de vagrant en una variable, como se muestra a continuación:

VAG_Version=1.8.1

Instalación de plugins en Vagrant

Los plugins son mecanismos de extensión que posee Vagrant para incorporar comportamiento adicional.

Una lista de los actualmente disponibles se puede encontrar en https://github.com/mitchellh/vagrant/wiki/Available-Vagrant-Plugins.

Los dos plugins que vamos a instalar son:

  • vagrant-vbguest actualiza las guest additions de VirtualBox si es necesario
  • vagrant-proxyconf configura la VM para que use las variables de entorno de proxy del anfitrión. Esto es fundamental si tu acceso a Internet es mediante un proxy corporativo.

La forma de instalar plugins es muy simple, en nuestro caso:

  vagrant plugin install vagrant-vbguest vagrant-proxyconf

En el caso de vagrant-proxyconf vamos a agregar a la configuración global de la cuenta de usuario que utilizamos lo siguiente en ~/.vagrant.d/Vagrantfile:

Vagrant.configure("2") do |config|
  puts "proxyconf..."
  if Vagrant.has_plugin?("vagrant-proxyconf")
    puts "find proxyconf plugin !"
    if ENV["http_proxy"]
      puts "http_proxy: " + ENV["http_proxy"]
      config.proxy.http     = ENV["http_proxy"]
    end
    if ENV["https_proxy"]
      puts "https_proxy: " + ENV["https_proxy"]
      config.proxy.https    = ENV["https_proxy"]
    end
    if ENV["no_proxy"]
      config.proxy.no_proxy = ENV["no_proxy"]
    end
  end
end

El script completo de instalación

Para lograr un entorno de Vagrant + Virtualbox repetible en diferentes estaciones de trabajo donde nos toque desempeñarnos, resulta más adecuado si en lugar de correr los mandatos manualmente, los englobamos en un pequeño programa en Bash.

Se puede ver en el código que se intentó realizar un control de errores en las acciones, informando cuando alguna no se puede llevar a cabo.

Además hay un rudimento de idempotencia, pues antes de realizar una acción (descargar un archivo, instalar un paquetes) se trata de verificar si ya fue realizada con anterioridad, para evitar repetirla innecesariamente.

El control de errores y la idempotencia agrega «ruido» a las simples instrucciones de instalación, lo cual hace que ya no sean tan fáciles de leer. En otra oportunidad veremos cómo usar una herramienta más apropiada a las instalaciones, llamada Ansible, la cual incorpora de fábrica estas importantes características.

A continuación, toma un momento para revisar el programa y si necesitas virtualización hecha simple, hazlo correr.

#!/bin/bash

# buscar paquete apropiado a arquitectura y cpu en https://www.vagrantup.com/downloads.html 
#
VAG_Version=1.8.1


# buscar paquete apropiado a arquitectura+cpu y que sea admitido por Vagrant en https://www.virtualbox.org/wiki/Downloads
# son dos:
#    1. VirtualBox platform package
#    2. VirtualBox Oracle VM VirtualBox Extension Pack
#

##
# info de la version del Virtualbox
VB_MayorVersion=5.0
VB_MinorVersion=26

##
# release number del Oracle Virtualbox Extension Pack
VB_EXTPACK_ReleaseNumber=108824

#######################################
##
# no hay mas cambios desde esta linea hacia abajo
#

##
# la distro donde se van a instalar los paquetes Virtualbox y Vagrant:
distro=`lsb_release -d | awk '{print $2}'`
release=`lsb_release -d | awk '{print $3}'`
codename=`lsb_release -c | awk '{print $2}'`
arch=`arch`


error() {
  echo $* >&2
  exit 1
}


oracle_pubkey() {
  if [ $codename == "trusty" -o $codename == "wheezy" ] ; then echo oracle_vbox.asc      ; return 0; fi
  if [ $codename == "xenial" -o $codename == "jessie" ] ; then echo oracle_vbox_2016.asc ; return 0; fi

  error "no se puede determinar cual es la clave de APT de Oracle para distro:"${distro}" y codename: "${codename}
}


instalo_virtualbox() {

  # verifico si no esta ya instalado
  dpkg -l  virtualbox-${VB_MayorVersion} >/dev/null ; VB_INSTALADO=$?
  if [ 0 -ne "${VB_INSTALADO}" ] ; then
    Oracle_pubkey_filename=`oracle_pubkey`

    # fuente de paquetes de Oracle para Virtualbox
    sudo bash -c "echo 'deb http://download.virtualbox.org/virtualbox/debian '${codename}' contrib' > /etc/apt/sources.list.d/virtualbox.list"

    # The Oracle public key for apt-secure:
    wget -q https://www.virtualbox.org/download/${Oracle_pubkey_filename} -O- | sudo apt-key add - 

    # actualizo lista de paquetes
    sudo apt-get update

    # instalo Virtualbox y dkms to ensure that the VirtualBox host kernel modules (vboxdrv, vboxnetflt and vboxnetadp) are properly updated if the linux kernel version changes during the next apt-get upgrade. 
    sudo apt-get install -y --force-yes virtualbox-${VB_MayorVersion} dkms ; ret=$?
    [ 0 -eq "$ret" ] || error "no se pudo instalar dkms y "virtualbox-${VB_MayorVersion}
    
  fi
}


instalo_oracle_extension_pack() {

  VB_BASE_URL=http://download.virtualbox.org/virtualbox/${VB_MayorVersion}.${VB_MinorVersion}
  VB_EXTPACK_FILENAME=Oracle_VM_VirtualBox_Extension_Pack-${VB_MayorVersion}.${VB_MinorVersion}-${VB_EXTPACK_ReleaseNumber}.vbox-extpack

  # verifico si no esta ya instalado
  if [ 0 -eq `sudo VBoxManage list extpacks | awk '/Extension Packs:/ {print $3} '` ] ; then
    [ -r ${VB_EXTPACK_FILENAME} ] || wget -q ${VB_BASE_URL}/${VB_EXTPACK_FILENAME} ; ret=$?
    [ 0 -eq "$ret" ] || error "no se pudo descargar el extension pack: "${VB_BASE_URL}/${VB_EXTPACK_FILENAME}

    # instalo el Extension Pack
    sudo VBoxManage extpack install ${VB_EXTPACK_FILENAME} 2>/dev/null ; ret=$?
    [ 0 -eq "$ret" ] || error "no se pudo instalar el extension pack: "${VB_EXTPACK_FILENAME}

    #sudo VBoxManage list extpacks
    #sudo VBoxManage extpack uninstall "Oracle VM VirtualBox Extension Pack"
  fi

}


instalo_vagrant() {
  VAG_BASE_URL=https://releases.hashicorp.com/vagrant/${VAG_Version}
  VAG_PKG_NAME=vagrant_${VAG_Version}_${arch}.deb

  # verifico si no esta ya instalado
  dpkg -l vagrant >/dev/null ; VAG_INSTALADO=$?
  if [ 0 -ne "${VAG_INSTALADO}" ] ; then

    [ -r ${VAG_PKG_NAME} ] || wget -q ${VAG_BASE_URL}/${VAG_PKG_NAME} ; ret=$?
    [ 0 -eq "$ret" ] || error "no se pudo descargar vagrant: "${VAG_BASE_URL}/${VAG_PKG_NAME}

    sudo dpkg -i ${VAG_PKG_NAME} ; ret=$?
    [ 0 -eq "$ret" ] || error "no se pudo instalar "${VAG_PKG_NAME}
  fi

}


instalo_vagrant_proxyconf() {
  vagrant plugin install vagrant-proxyconf

  cat > ~/.vagrant.d/Vagrantfile << !EOF
Vagrant.configure("2") do |config|
  puts "proxyconf..."
  if Vagrant.has_plugin?("vagrant-proxyconf")
    puts "find proxyconf plugin !"
    if ENV["http_proxy"]
      puts "http_proxy: " + ENV["http_proxy"]
      config.proxy.http     = ENV["http_proxy"]
    end
    if ENV["https_proxy"]
      puts "https_proxy: " + ENV["https_proxy"]
      config.proxy.https    = ENV["https_proxy"]
    end
    if ENV["no_proxy"]
      config.proxy.no_proxy = ENV["no_proxy"]
    end
  end
end
!EOF
}


instalo_vagrant_plugins() {
  mkdir -p ~/.vagrant.d/

  instalo_vagrant_proxyconf
  vagrant plugin install vagrant-share
  vagrant plugin install vagrant-vbguest
}


##
# main
#
instalo_virtualbox
instalo_oracle_extension_pack

instalo_vagrant
instalo_vagrant_plugins

##
# luego se puede verificar la instalacion con:
#
# vagrant init ubuntu/trusty32; vagrant up # para crear una VM de prueba
# vagrant ssh     # para conectarte a la VM recien creada

Obtener el código fuente desde Github

Se creó un repo en Github: https://github.com/CesarBallardini/instala-virtualbox-vagrant

Para obtener este código fuente, debes clonar el repositorio mediante SSH o HTTPS:

  git clone git@github.com:CesarBallardini/instala-virtualbox-vagrant.git     # SSH
  git clone https://github.com/CesarBallardini/instala-virtualbox-vagrant.git # HTTPS

Para crear inicialmente este proyecto

Para subir el código de este proyecto, simplemente hay que hacer:

  • editar el .gitignore para evitar el directorio privado y el de vagrant:
provision/private/
.vagrant
  • inicializar el repo git, agregar los cambios relevantes, crear el commit inicial:
  git init
  git add .
  git commit -m "instrucciones de instalacion y Vagrantfile para probarlas"
  • crear un repo en Github, ene ste caso se creó el instala-virtualbox-vagrant
  • poner el repo de github como origin y subir los cambios:
  git remote add origin https://github.com/CesarBallardini/instala-virtualbox-vagrant.git
  git push -u origin master

Introducción

Vagrant[1] es una herramienta que simplifica el workflow y reduce la carga necesaria para crear, correr y operar máquinas virtuales (VM) en tu computadora.

La interfaz de gestión es mediante mandatos en modo CLI (Command Line Interface). Admite las soluciones principales de virtualización: VirtualBox, VMWare, KVM, Hyper-V. Trabaja con las herramientas de gestión de configuración más populares: Ansible, Chef, Puppet, Salt.

Además facilita la distribución de entornos virtuales, lo cual permite que los agentes de la organización tengan un accceso simple, sin complicaciones a entornos patrón, por ejemplo: entornos de desarrollo de un framework Web, entornos de testing repetibles, etc.

Hay un único mandato que se necesita para levantar una o más VMs que trabajan en concierto:

vagrant up

No importa si las VM se crearán sobre VirtualBox o sobre VMWare, si es una única VM o son tres, si se va correr dentro de la VM un GNU/Linux o un MS Windows, tampoco importa si tendrá Symfony o Django. Con ese solo mandato, la VM estará encendida y respondiendo en un tiempo que va desde segundos a minutos.

Lo que Vagrant automatiza para nosotros

Cuando se da el mandato enunciado unos párrafos más arriba, lo que Vagrant hace es:

  1. Lee el archivo de configuración de la infraestructura que va a crear (Vagrantfile)
  2. Descarga la plantilla (box) de la imagen que va a crear (VM)
  3. Inicia la VM
  4. Configura los recursos de la VM: RAM, cantidad de CPUs, directorios compartidos y configuración de red
  5. Si es apropiado, realiza la instalación del software solicitado para la VM

La VM está ahora operativa, y podemos ingresar mediante SSH con el mandato:

vagrant ssh

Mandatos usuales Vagrant

Las operaciones fundamentales son las siguientes:

vagrant up      # levanta la VM, creándola si es la primera vez que se ejecuta
vagrant ssh     # ingresa para SSH a la VM
vagrant halt    # detiene la ejecución de la VM (queda lista para otro vagrant up)
vagrant destroy # detiene la VM y elimina la imagen de la VM (desaparece completamente)

Virtualización

El problema que resuelve la virtualización es el del aislamiento de sistemas: el sistema instalado en mi computadora no necesita ser modificado para correr una aplicación Web.

Dentro de la VM puede existir otra versión de sistema operativo, por ejemplo tal vez mi computadora tiene instalado Ubuntu GNU/Linux, y en la VM estoy trabajando con un servidor Debian. Además la pesadilla del desarrollador es el dependency hell[4]: cuando diferentes aplicaciones en las cuales está trabajando requieren diferentes versiones incompatibles de una biblioteca en particular. O diferentes versiones de PHP, etc.

El aislamiento que proporciona la virtualización permite que en la computadora se instale una versión de PHP, y en la VM otro completamente diferente, sin que haya interferencias.

Algunos de los mecanismos de virtualización, por ejemplo Virtualbox, trabajan sobre diferentes sistemas operativos anfitrión, como Mac, GNU/linux y Ms Windows. Otros, basados en contenedores como LXC, trabajan sobre diferentes versiones de GNU/Linux.

Vagrant

Vagrant se apoya en un mecanismo de virtualización dado y proporciona mandatos y configuraciones que abstraen el detalle de cómo producir una VM operativa sobre ese dado mecanismo de virtualización.

Desventajas

  1. Eficiencia de la estación de trabajo. Las máquinas de los desarrolladores ejecutan las VM con una penalidad en la performance, y por ello deben ser de suficientes recursos en RAM y CPU para que sean usadas con eficacia. Las estaciones de los sysadmin deben ser de mejores prestaciones aún, pues la tarea de crear las VM y sus verificaciones es muy demandante.
  2. El directorio compartido que crea Virtualbox tiene una pésima performance, para mejorar este aspecto se debe usar NFS. Pero esta mejora no está disponible cuando el anfitrión es un MS Windows. Entonces no toda combinación de partes es factible.
  3. Algunas combinaciones de sistema operativo en el anfitrión y plataforma de virtualización no son funcionales.

Ventajas

  1. Simple workflow para obtener VMs correctamente configuradas: no hay que lidiar con el sistema de virtualización.
  2. Corto tiempo hasta que el entorno de trabajo está operativo, en el orden de minutos.
  3. El desarrollador puede cambiarse de estación de trabajo hacia otra, o cambiar su sistema operativo, sin tener que reinstalar nada de software. Sólo debe asegurarse que tiene instalado Virtualbox y Vagrant.
  4. El desarrollador ya no es responsable de instalar software del lado server.
  5. Todo el mundo usa exactamente el mismo software del lado server.
  6. A las VMs que usan los desarrolladores, las preparan los ingenieros de operaciones.
  7. Cada desarrollador puede crear, destruir y recrear los entornos virtuales en minutos.
  8. Vagrant facilita la actualización del software de server que se usa en las estaciones de los desarrolladores.
  9. El acceso a los recursos del sistema, como los puertos de red, está restringido, de manera predeterminada.
  10. La seguridad de todos los equipos usados para desarrollo se puede gestionar globalmente, porque es un sysadmin el que preparó las VM y las reglas de acceso a la computadora del desarrollador.
  11. Se puede lograr un mapeo casi 1:1 entre los entornos de desarrollo, testing y producción.
  12. Los entornos virtuales se crean para cada proyecto: todo proyecto corre aislado de los demás proyectos.
  13. Cada proyecto puede elegir usar paquetes de manera arbitraria: un proyecto puede usar Debian + PHP5.4 + Symfony2.8 y otro CentOS + Ruby2.3 + Rails4.
  14. Se usa un único workflow, sin importar la plataforma de virtualización, el sistema operativo de la VM, el lenguaje de programación, framework, o software del lado server.
  15. Los desarrolladores no necesitan una conexión de red para hacer su trabajo.
  16. Vagrant es Open Source y Free Software[2, 3].
  17. Vagrant funciona en las plataformas de sistema operativo más populares: GNU/Linux, Mac OS X y MS Windows.
  18. Vagrant dispone de una documentación clara y bien detallada.
  19. La funcionalidad de Vagrant puede extenderse mediante plugins.
  20. Es ideal para la presentación en cursos y capacitaciones. El instructor puede asegurarse el entorno que usarán los alumnos, es fácil para los alumnos entrar en carrera, sin necesidad de saber cómo instalar todo el software requerido.

Referencias

Nuevamente comenzamos revisando las instrucciones del tema HPSTR en

Entonces, dentro de la VM:

cd /vagrant/www/CesarBallardini.github.io/

Eliminamos los directorios:

  • theme-setup/
  • about/

Mantenemos los directorios siguientes:

  • assets/ (traducir back en js/plugins/jquery.dlmenu.js, y en js/sripts/.min.js)
  • images/ (dejo sólo las imágenes apple-touch-icon-114x114-precomposed.png, apple-touch-icon-144x144-precomposed.png, apple-touch-icon-72x72-precomposed.png, apple-touch-icon-precomposed.png, twitter-card-summary-large-image.jpg; agrego cesarballardini.jpg)
  • _data/ (comento los enlaces en _navigation.yml)
  • _includes/ (navigation.html traducir mensajes, read-more.html arreglar fechas, traducir tiempo de lectura en read-time-index.html y read-time.html)
  • _layouts/ (post.html arreglar fechas)
  • _posts/ (elimino los archivos con los posts de ejemplo)
  • _sass/ (atribución de entradas pasar a castellano en _page.scss)

Los siguientes, los mantenemos pero hay que personalizarlos:

  • about/ (elimino el directorio, lo voy a transformar en acerca-de-mi/index.md)
  • posts/ (traducir title y description en index.html)
  • tags/ (traducir title y description en index.html)
  • feed.xml
  • index.html (elimino la referencia a la imagen de fondo; corrijo el link hacia About y arreglo fechas)

Edito el archivo de configuración global _config.yml y queda:

title:            katra
description:      el espíritu y la tecnología de la información
disqus_shortname: 
reading_time:     true
words_per_minute: 200
# Your site's domain goes here (eg: https://mmistakes.github.io, http://yourdomain.com, etc)
# When testing locally leave blank or use http://localhost:4000
#url: http://ballardini.com.ar/blog
#url: http://CesarBallardini.github.io
url:

# Owner/author information
owner:
  name:           César Ballardini
  avatar:         cesarballardini.jpg
  bio:            "Soy un programador de alma inquieta. Las computadoras te incitan a programar, y una vez que empiezas, no se puede detener."
  email:          cesar@ballardini.com.ar
  # Social networking links used in footer. Update and remove as you like.
  twitter:        CesarBallardini
  facebook:       
  github:         CesarBallardini
  stackexchange:  
  linkedin:       CesarBallardini
  instagram:      
  flickr:         
  tumblr:         
  # google plus id, include the '+', eg +mmistakes
  google_plus:

# Background image to be tiled on all pages
background: 

# Analytics and webmaster tools stuff goes here
google_analytics:   
google_verify:      
# https://ssl.bing.com/webmaster/configure/verify/ownership Option 2 content= goes here
bing_verify:         

# http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
timezone:    America/Buenos_Aires
future:      true
highlighter: rouge
markdown:    kramdown
gems:
  - jekyll-sitemap
  - jekyll-paginate
  - jekyll-gist
  - jekyll-feed
sass:
  sass_dir: _sass
  style: compressed

# https://github.com/mojombo/jekyll/wiki/Permalinks
permalink:   /:categories/:title/

# Amount of post to show on home page
paginate: 5

kramdown:
  input: GFM
  auto_ids: true
  footnote_nr: 1
  entity_output: as_char
  toc_levels: 1..6
  enable_coderay: false

include: 
  - .htaccess
exclude: 
  - "*.less"
  - "*.sublime-project"
  - "*.sublime-workspace"
  - .asset-cache
  - .bundle
  - .jekyll-assets-cache
  - .sass-cache
  - CHANGELOG
  - Capfile
  - Gemfile
  - Gruntfile.js
  - LICENSE
  - README
  - Rakefile
  - config
  - gulpfile.js
  - lib
  - log
  - node_modules
  - package.json
  - spec
  - tmp

HPSTR es un tema de Jekyll que usa SCSS y requiere Jekyll 3.x.

Los pasos de instalación están descriptos en las instrucciones de instalación de este tema y los voy a adaptar al entorno de VM que hemos construído antes.

Luego de levantar nuestra VM con Jekyll instalado, nos conectamos a nuestra cuenta en Github y hacemos un fork del repo del tema en Github.

Para crear un sitio Web en Github, las instrucciones están muy claras en el tutorial de github-pages.

Vamos a tratar primero el caso inicial, cuando por primera vez creamos nuestro blog. Yo voy a referir mi cuenta en Github, que es CesarBallardini, así que en el resto de esta serie sobre cómo tener funcionando tu blog jekyll + HPSTR, vas a tener que cambiar este nombre de cuenta por el tuyo. Así también sucederá con mi nombre y apellido, y dirección de correo electrónico.

Debemos crear el repo CesarBallardini.github.io, completamente vacío: sin .gitignore ni README.md.

Clonamos el repo inicial:

cd /vagrant/www/
git clone https://github.com/CesarBallardini/CesarBallardini.github.io
cd CesarBallardini.github.io/

En la VM configuramos Git, sólo para este repo:

git config user.email "cesar@ballardini.com.ar"
git config user.name "Cesar Ballardini"

Cargamos el tema HPSTR desde el repo propio:

git remote add hipster https://github.com/CesarBallardini/hpstr-jekyll-theme.git
git fetch hipster master
git merge hipster/master -m "incorporo HPSTR al repo de jekyll"

Ahora tenemos dos alternativas: verlo localmente, para tener una visualización previa de cómo va a quedar el blog, y la otra posibilidad es subirlo a Github para hacerlo público.

Localmente desde la VM

Para verlo localmente, usaremos el programa jekyll, ya instalado en la VM, nos aseguramos de instalar las gemas requeridas como dependencias:

bundle install

Y lo publicamos localmente:

bundle exec jekyll build
bundle exec jekyll serve --host 192.168.33.10 --incremental

Queda accesible en http://192.168.33.10:4000/ en nuestro navegador (que es el IP configurado en el Vagrantfile en FIXME).

Publicado en Github

Por otro lado. lo podemos publicar en Github (aquí nos solicitará nuestro nombre de usuario y contraseña en Github):

La primera vez desconecto el tracking de la rama aguas arriba:

git branch --unset-upstream

Y ahora hago el push hacia Github:

git push origin master

Y accederlo desde allí en: http://cesarballardini.github.io/

Vamos a usar Vagrant para instalar Jekyll 3.x en una máquina virtual con Virtualbox, para editar y generar nuestro sitio, sin interferir con el sistema de escritorio que usemos para nuestro trabajo cotidiano.

Si no tienes instalado el combo vagrant + virtualbox, te recomiendo que lo hagas de acuerdo a las instrucciones en FIXME.

El Vagrantfile nos permite crear una VM liviana con Ubuntu 14.04 Trusty de 32 bits, con poca memoria, más que suficiente para nuestras necesidades. El aprovisionamiento se hace en dos etapas: 1. los paquetes esenciales del sistema operativo; 2. ansible.

El sistema operativo es todo lo necesario para que se puedan instalar paquetes, se aproveche un archivo de swap por si nos quedamos cortos con la RAM asignada, y la VM queda actualizada en sus paquetes.

El ansible lo instalamos en la VM. Esto es discutible. Como pretendo que esta VM corra, se instale y se configure sin importar el software del equipo host, no puedo asegurar que ansible funciona o siquiera es instalable en el host. Lo instalamos en la VM y hacemos que sea su propia máquina de control ansible. Cómo correr ansible para que ejecute todas las instalaciones es algo que documentamos en provision/ansible-setup.sh que es un oneliner. Todas las rutas de los archivos serán relativas a la ubicación del Vagrantfile.

Luego hay que correr el playbook que instala las dependencias de Jekyll y el propio Jekyll.

Otro playbook se ocupa de hacer el deploy del sitio estático, y de subirlo a Github.

Vamos a ver cada una de estas cosas en detalle.

Vagrantfile

El Vagrantfile simplemente descarga un box estándar de Ubuntu, le asigna una dirección IP y tamaño de memoria adecuado a las necesidades. Se crea un directorio www/ en el host, que se mapea dentro de la VM para que sea el lugar donde se aloje el contenido del Web server.

También se invocan cuatro scripts para el aprovisionamiento:

  • provision/os-setup.sh instala lo esencial del sistema operativo para que funcione en la locación de instalación (proxies, fuentes de paquetes Debian, swap, hostname, etc.)
  • provision/ansible-setup.sh (instala ansible)
  • provision/ansible-playbook-install.sh (instala roles y el playbook a usar)
  • provision/ansible-setup.sh (corre ansible para instalar Jekyll)
VAGRANTFILE_API_VERSION = "2"
arch= "i386" ; bits="32" ; distro="trusty"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.define "github-pages"+bits do |base|
    base.vm.box = "ubuntu/"+distro+bits
    base.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/trusty/current/"+distro+"-server-cloudimg-"+arch+"-vagrant-disk1.box"
    base.vm.hostname = "jk.dev"
    base.vm.provision "shell", path: "provision/os-setup.sh", privileged: true
    base.vm.provision "shell", path: "provision/ansible-setup.sh", privileged: true
    base.vm.provision "shell", path: "provision/ansible-playbook-install.sh", privileged: false
    base.vm.provision "shell", path: "provision/ansible-run.sh", privileged: false
    base.vm.network "forwarded_port", guest: 4000, host: 4000
    base.vm.network "private_network", ip: "192.168.33.10"
    base.vm.synced_folder "www/", "/srv/www", create: true
    base.ssh.forward_agent = true
    base.vm.provider "virtualbox" do |vb|
      vb.customize ["modifyvm", :id, "--nictype1", "Am79C973"]
      vb.customize ["modifyvm", :id, "--nictype2", "Am79C973"]
      vb.customize ["modifyvm", :id, "--memory", 512]
      vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
      vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
      vb.gui = false
      vb.name = "Jekyll Blog Vagrant "+arch+" arch"
      vb.memory = "512"
    end
  end
end

El aprovisionamiento del sistema operativo básico

No hay mucho más que comentar en el código siguiente. Use the source, Luke!

Creamos un directorio provision/ donde residirá todo el código de aprovisionamiento en shell, y un directorio provision/ansible/ donde estarán roles, configuración y playbooks de ansible.

mkdir -p provision/ansible

El provision/os-setup.sh será el siguiente:

#!/bin/bash
#
##
# provision/os-setup.sh
# instala lo necesario a nivel de sistema operativo
#

##
# Parametros de la VM
#
# vm_hostname: nombre de host dentro de la VM
vm_hostname=jk.dev

# vm_swapfilesize: si esta vacio no se crea area de swap en la VM
vm_swapfilesize=2G

##
# TODO: poner en configuracion de la ubicacion de trabajo
# Estos sources son para instalaciones con acceso a un mirror interno:
# si se hace un noop, se usan los que vienen configurados en la VM desde el vagrant box usado
#
aseguro_sources_list() {
  wget http://mirror.EXAMPLE.COM/listas/sources.list.14.04 -O /etc/apt/sources.list
  : 
}

############################################
##
# no hay mas que modificar desde esta linea hacia abajo
##

distro=`lsb_release -d | awk '{print $2}'`
release=`lsb_release -d | awk '{print $3}'`

aseguro_config_apt() {
  aseguro_sources_list
  apt-get    update
}

actualizo_paquetes_sistema() {
  apt-get    update
  apt-get -y upgrade
  apt-get -y autoremove
  apt-get -y dist-upgrade
  apt-get -y --force-yes autoremove
  apt-get -y autoclean
}

aseguro_un_minimo_espacio_de_swap() {
  vm_swapfilesize=$1

  if [ -n "${vm_swapfilesize}" ]
  then
    fallocate -l ${vm_swapfilesize} /swapfile
    chmod 600 /swapfile
    mkswap /swapfile
    swapon /swapfile
    # swapon -s  # verificar que el swap funciona
    echo '/swapfile   none    swap    sw    0   0' >> /etc/fstab
  fi
}


mejoras_en_performance() {
  sysctl vm.swappiness=10
  echo 'vm.swappiness=10' > /etc/sysctl.conf

  sysctl vm.vfs_cache_pressure=50
  echo 'vm.vfs_cache_pressure = 50' > /etc/sysctl.conf
}

set_hostname() {
  echo '127.0.0.1   '$1 >> /etc/hosts
}

instalo_keyring() {
  [ $release == "Debian" ] && apt-get install -y debian-keyring
  [ $release == "Ubuntu" ] && apt-get install -y --force-yes ubuntu-keyring ubuntu-extras-keyring
}

instalo_paquetes_esenciales() {
  apt-get install -y --force-yes debconf-utils
  apt-get install -y --force-yes python-software-properties build-essential
  apt-get install -y --force-yes git
}

###################################
##
# main
#
aseguro_config_apt
aseguro_un_minimo_espacio_de_swap ${vm_swapfilesize}
mejoras_en_performance
set_hostname ${vmhostname}

instalo_keyring
instalo_paquetes_esenciales
actualizo_paquetes_sistema
# EOF

Instalación de Ansible

Este script corre con privilegios de root y se ocupa de instalar la fuente de paquetes en Ubuntu (FIXME para otros S.O.) necesarios para instalar la versión estable más moderna de ansible.

#!/bin/bash
#
##
# provision/ansible-setup.sh
# instala lo necesario para que funcione ansible
#

apt-get install -y python-software-properties build-essential
apt-add-repository -y ppa:ansible/ansible
apt-get update
apt-get install ansible -y

Instalación de Jekyll y sus dependencias

Vamos a usar playbooks de ansible para realizar la instalación de Jekyll y sus dependencias.

El primer paso es asegurar la configuración de ansible, la cual requiere un archivo de inventario, y uno de configuración global.

El inventario se denomina jk.inventory y su contenido es un grupo denominado jk, donde sólo reside la identificación de la VM (jk.dev) con una conexión local, para evitar el uso de SSH:

[jk]
jk.dev  ansible_connection=local

El archivo de configuración de ansible se denomina ansible.cfg, y se instala localmente en el directorio de trabajo, para que se use en lugar del archivo global a nivel de sistema. En nuestro caso está casi vacío de contenido y sólo tiene las líneas:

[defaults]
roles_path    = ./roles

[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[accelerate]
[selinux]

Para ejecutar ansible usaremos el mandato provision/ansible-run.sh:

cd /vagrant/provision/ansible
time ansible-playbook -vv -i jk.inventory instala-jekyll.yml

Cómo crear el playbook de instalación de Jekyll

Primero debemos instalar los roles necesarios desde Ansible Galaxy:

cd /vagrant/provision/ansible/roles/
ansible-galaxy install rvm_io.rvm1-ruby
ansible-galaxy install igor_mukhin.jekyll

Nuestro playbook de instalación será: instala-jekyll.yml

- hosts: jk
  vars:
    jekyll_version: 3.2.1

  roles:
    - {role: rvm_io.rvm1-ruby, rvm1_gpg_key_server: 'hkp://keyserver.ubuntu.com:80' }
    - {role: igor_mukhin.jekyll, tags: jekyll, become: true }

Nota: Un problema de permisos en la creación de symlinks en roles/rvm_io.rvm1-ruby/tasks/rubies.yml se resuelve usando privilegios de administrador en el task, que debería quedar (cerca de la línea 54):

- name: Symlink ruby related binaries on the system path
  file:
    state: 'link'
    src: '/wrappers/default/'
    dest: '/'
    owner: 'root'
    group: 'root'
  when: not '--user-install' in rvm1_install_flags
  with_items: ''
  become: yes

Todos estos pasos los englobaremos en un script bash para que corra al momento del aprovisionamiento, provision/ansible-playbook-install.sh es:

#!/bin/bash
#
##
# provision/ansible-playbook-install.sh
# instala roles, playbboks y variables
#

##
# playbook de instalacion de software
#
cat > /vagrant/provision/ansible/instala-jekyll.yml <<!EOF
- hosts: jk
  vars:
    jekyll_version: 3.2.1

  roles:
    - {role: rvm_io.rvm1-ruby, rvm1_gpg_key_server: 'hkp://keyserver.ubuntu.com:80' }
    - {role: igor_mukhin.jekyll, tags: jekyll, become: true }

!EOF

##
# instalo roles
#

mkdir -p /vagrant/provision/ansible/roles/
cd /vagrant/provision/ansible/

ansible-galaxy install rvm_io.rvm1-ruby
ansible-galaxy install igor_mukhin.jekyll

##
# emparcho rvm_io.rvm1-ruby, sino da problema de permisos al crear los symlinks
#
[ -z "$( sed -n -e "63p"  /vagrant/provision/ansible/roles/rvm_io.rvm1-ruby/tasks/rubies.yml )" ] \
  && sed -i '63i\ \ become: yes' /vagrant/provision/ansible/roles/rvm_io.rvm1-ruby/tasks/rubies.yml