Automatizando entornos de desarrollo virtuales con Vagrant

Creando entornos de desarrollo basados en kvm y libvirt
9 de agosto de 2021 por
Automatizando entornos de desarrollo virtuales con Vagrant
Jorge Armando Medina Acevedo


Que tal a todos, es un gusto saludarlos de nuevo y traerles nuevo contenido que espero les sea de interés a quienes les gusta esto de Linux y la automatización de servidores. En esta ocación les vengo a contar de Vagrant, una herramienta hecha por Hashicorp, diseñada para simplificar la creación de ambiente de desarrollo. Vagrant automatiza las tareas para levantar un ambiente para que los desarrolladores, operadores y diseñadores inicien de forma rápida un ambiente parecido al que se usará en producción

Introducción

En entornos de gestión de TI tradicionales en donde todavía no adoptan métodos ágiles ni la automatización, es común que solo haya un ambiente de ejecución, normalmente es el ambiente productivo, o producción, este debe ser un ambiente estable y para que esto pase debe haber el minimo de cambios, por lo tanto los desarrolladores no pueden acceder a este ambiente para realizar sus pruebas. Aquí empieza el problema, los desarrolladores usarán su propio equipo local para realizar el proceso de desarrollo de software, por qué es un problema? normalmente los equipos de los desarrolladores tienen sistemas diferentes a los que se usan en producción, es decir, tienen una versión de sistema operativo, si, quizas ya usan Linux, pero es probable que su versión de escritorio tenga una versión de kernel diferente o las diferentes bibliotecas de sistema y de su stack de desarrollo, como pueden ser bibliotecas y el runtime de la aplicación, esto causa que al desarrollar la aplicación en un entorno más nuevo pueda introducir problemas de compatibilidad al llevar el desarrollo a producción, ya que el servidor tiene versiones más viejas (versiones estables probadas) y probablemente algunas funciones no están implementadas todavía en la versión del runtime de la aplicación que tiene el servidor de producción.

El costo de arreglar un bug es exponencialmente más alto conforme se acerca a producción, por lo tanto se debe evitar la disparidad con producción. Vagrant permite a los desarrolladores y operadores crear un su propio equipo un ambiente desarrollo consistente con las configuraciones que tiene el ambiente de producción, independientemente de que sistema operativo se tiene en local, es decir, funciona sobre Mac, Linux, Windows y otros. Vagrant trabaja con boxes, estas son imagenes preconfiguradas de diferentes sistemas operativos, estas imagenes vienen preparadas para trabajar sobre diferentes gestores de máquinas virtuales como pueden ser KVM, Virtualbox, VMware y otros. Normalmente las boxes están hospedadas en un repositorio central mantenido por vagrant, ahí diferentes creadores suben sus imagenes base.

Requisitos

Para poder realizar esta práctica vamos a trabajar sobre un sistema de escritorio basado en Ubuntu 20.04, ya que usaremos vagrant con máquinas virtuales KVM es necesario que el sistema tenga soporte de virtualización por hardware habilitado desde el BIOS, sin esto la virtualización no es acelerada y sería algo más como emulación, lo cual afecta gravemente el rendimiento de las máquinas virtuales. Además necesitamos los siguientes paquetes instalados:

  • qemu-kvm 4.2-3

  • libvirt-daemon-system 6.0.0

  • libvirt-clients 6.0.0

  • virt-manager 2.2.1

  • vagrant 2.2.16

Los primeros cuatro paquetes se pueden instalar con apt:

$ sudo apt update && sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients virt-manager libvirt-dev

Para instalar vagrant descargaremos la versión desde internet:

$ wget https://releases.hashicorp.com/vagrant/2.2.16/vagrant_2.2.16_linux_amd64.zip

Ahora descomprimimos e instalamos:

$ unzip vagrant_2.2.16_linux_amd64.zip
$ sudo cp vagrant /usr/local/bin

Ahora verificamos la versión que tenemos instalada:

$ vagrant --version

Ahora instalamos el plugin libvirt:

$ CONFIGURE_ARGS='with-ldflags=-L/opt/vagrant/embedded/lib with-libvirt-include=/usr/include/libvirt with-libvirt-lib=/usr/lib' \
GEM_HOME=~/.vagrant.d/gems GEM_PATH=$GEM_HOME:/opt/vagrant/embedded/gems \
PATH=/opt/vagrant/embedded/bin:$PATH \
vagrant plugin install vagrant-libvirt

Si todo fue bien, ahora podremos listar los plugins:

$ vagrant plugin list
vagrant-libvirt (0.5.3, global)

Perfecto, ahora si podemos empezar a crear el ambiente de desarrollo.

Creación de ambiente

Para crear un ambiente de desarrollo con vagrant debemos crear un archivo de configuración, esta es la forma de hacer la declaración de como queremos que este configurado el ambiente, creamos un directorio de trabajo para nuestro nuevo ambiente, en este caso necesito levantar un ambiente basado en CentOS7 con dos máquinas virtuales, una llamada deployer y otra cms.

NOTA: En mi caso todo el código lo mantengo en $HOME/vcs.

$ cd $HOME/vcs
$ mkdir vagrant-centos7
$ vim Vagrantfile

El contenido del archivo es algo así:

 

Este archivo esta en formato de ruby, por eso al inicio escribo el header del modo ruby y sugiero el modo de edición para tipos de archivos ruby en vim, aquí definimos los parámetros generales tales como:

  • Vagrant.configure define el bloque de configuración

  • Se define el proveedor de virtualización, se usa libvirt y el driver kvm.

  • Se define el nombre de la box a usar generic/centos7 esta soportada para kvm.

  • Se define lista de archivos de configuración vagrant/Vagrantfile.deployer y vagrant/Vagrantfile.cms.

  • Se cargan las configuraciones definidas en cada uno de los archivos definidos.

Ahora debemos crear el directorio vagrant en donde almacenaremos los archivos de configuración especificos para cada una de las máquinas virtuales de este ambienteque levantaremos.

$ mkdir vagrant

Creamos el archivo vagrant/Vagrantfile.deployer con el siguiente contenido:


Ahora creamos el archivo vagrant/Vagrantfile.deployer con el siguiente contenido:


En ambas máquinas se define un bloque de configuración con los siguientes parámetros:

  • Nombre de host

  • Direccionamiento IP privado fijo

  • Redirección de puertos de local a la máquina virtual

Antes de ejecutar algo debemos validar que la configuración está correcta:


Ya estamos listos, antes de levantar el ambiente descargaremos la imagen de la box que usaremos:

$ vagrant box add generic/centos7 --provider=libvirt

Esta operación puede tardar varios minutos, dependerá de tu conexión de internet

Ya estamos listos para levantar el ambiente:

$ vagrant up
Bringing machine 'deployer' up with 'libvirt' provider...
Bringing machine 'cms' up with 'libvirt' provider...
==> deployer: Creating image (snapshot of base box volume).
==> cms: Creating image (snapshot of base box volume).
==> deployer: Creating domain with the following settings...
==> cms: Creating domain with the following settings...
...
...
...
==> cms: Machine booted and ready!
==> deployer: Machine booted and ready!
==> cms: Setting hostname...
==> deployer: Setting hostname...
==> cms: Forwarding ports...
==> cms: 80 (guest) => 1080 (host) (adapter eth0)
==> deployer: Forwarding ports...
==> deployer: 8080 (guest) => 1088 (host) (adapter eth0)
==> cms: Configuring and enabling network interfaces...
==> deployer: Configuring and enabling network interfaces...

El comando up verifica si ya existe una imagen para la box definida en los archivos Vagrantfile, de no ser así la descarga, después crea las imagenes de disco para las máquinas virtuales, estas las hace a través de snapshots de la imagen base generic/centos7.

Validando el ambiente

Ahora que ya se terminó de crear el ambiente debemos de hacer algunas validaciones, primero debemos ver el estado del proyecto vagrant:

$ vagrant status
Current machine states:

deployer running (libvirt)
cms running (libvirt)

This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.

En la salida podemos ver el estado actual de las máquinas, tanto deployer como cms están en ejecución y podemos ver que son de tipo libvirt.

Ahora debemos validar la configuración ssh que se construyo y que se usa para conectarse por SSH a la consola de las máquinas virtuales del ambiente:

$ vagrant ssh-config
Host deployer
HostName 192.168.121.215
User vagrant
Port 22
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile /home/jmedina/data/vcs/jorge.medina/vagrant-centos7/.vagrant/machines/deployer/libvirt/private_key
IdentitiesOnly yes
LogLevel FATAL

Host cms
HostName 192.168.121.53
User vagrant
Port 22
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile /home/jmedina/data/vcs/jorge.medina/vagrant-centos7/.vagrant/machines/cms/libvirt/private_key
IdentitiesOnly yes
LogLevel FATAL

En la salida podemos ver que se generó un bloque de configuraciones para cada host, se define la dirección IP privada, el usuario, el puerto, y otros parámetros de autenticación y logs.

Ahora usaremos el sub comando ssh para conectarnos a la máquina deployer:

$ vagrant ssh deployer
[vagrant@deployer ~]$ ip a ls
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:81:59:40 brd ff:ff:ff:ff:ff:ff
inet 192.168.121.215/24 brd 192.168.121.255 scope global noprefixroute dynamic eth0
valid_lft 3480sec preferred_lft 3480sec
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:1d:b7:ae brd ff:ff:ff:ff:ff:ff
inet 192.168.33.100/24 brd 192.168.33.255 scope global noprefixroute eth1
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe1d:b7ae/64 scope link
valid_lft forever preferred_lft forever
[vagrant@deployer ~]$ exit
logout
Connection to 192.168.121.215 closed.

En el ejemplo nos conectamos por SSH usando los parámetros antes definidos, ejecuto ip para listar las direcciones IP de las interfaces locales y cierro la sesión.

Ahora nos conectamos a la máquina cms:

$ vagrant ssh cms
[vagrant@cms ~]$ ip a ls
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:0e:1c:e0 brd ff:ff:ff:ff:ff:ff
inet 192.168.121.53/24 brd 192.168.121.255 scope global noprefixroute dynamic eth0
valid_lft 3432sec preferred_lft 3432sec
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:e4:b8:b7 brd ff:ff:ff:ff:ff:ff
inet 192.168.33.10/24 brd 192.168.33.255 scope global noprefixroute eth1
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fee4:b8b7/64 scope link
valid_lft forever preferred_lft forever
[vagrant@cms ~]$ ping -c 3 192.168.33.100
PING 192.168.33.100 (192.168.33.100) 56(84) bytes of data.
64 bytes from 192.168.33.100: icmp_seq=1 ttl=64 time=1.52 ms
64 bytes from 192.168.33.100: icmp_seq=2 ttl=64 time=1.03 ms
64 bytes from 192.168.33.100: icmp_seq=3 ttl=64 time=1.02 ms

--- 192.168.33.100 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 1.021/1.192/1.520/0.233 ms
[vagrant@cms ~]$ exit
logout
Connection to 192.168.121.53 closed.

En este ejemplo mostramos el direccionamiento local de cms y además hacemos un ping a la dirección IP de deployer.

Con esto validamos que las máquinas virtuales están arriba, se puede conectar por SSH como a cualquier servidor y además tiene comunicación con las otras máquinas del ambiente.

Después de usar el ambiente por un rato lo podemos apagar para liberar por completo todos los recursos del sistema para después volver  levantarlo, en ese caso usamos el sub comando halt, por ejemplo:

$ vagrant status

Ahora apagamos el ambiente:

$ vagrant halt

Y validamos el estado apagado:

$ vagrant status

En el ejercicio se puede ver primero el estado running, después del halt el estado aparece shutoff, si se quiere volver a encender el ambiente usamos nuevamente el sub comando up.

Ahora veamos un ejercicio en donde queremos pausar las máquinas del ambiente, usamos el sub comando pause, después restauramos el estado del as máquinas con resume.

Veamos esta secuencia de comandos, primero vemos el estado del ambiente:

$ vagrant status

Ahora suspendemos las máquinas del ambiente:

$ vagrant suspend

Volvemos a ver el estado:

$ vagrant status

Al verificar que están pausadas restauramos su ejecución:

$ vagrant resume

Finalmente volvemos a validar el estado:

$ vagrant status

Con este nuevo ambiente ya se pueden realizar todas las pruebas de instalación y configuración de servicios, se pueden gestionar todas las máquinas virtuales con vagrant.

Destruyendo el ambiente

Cuando ya no se necesite el ambiente de desarrollo en la máquina local podemos destruír todos los recursos para liberar disco y deshacernos de ese artefacto.


Esto también nos puede servir si estamos en un proceso de aprendizaje, en donde creamos las máquinas, investigamos sobre como configurar un servicio, lo aplicamos y validamos, si funciona bien, destruímos el ambiente, documentamos y volvemos a probar el procedimiento, esto ayuda a generar documentación y procedimientos consistentes, así cuando volvemos a empezar de cero nos aseguramos que no haya pasos que se hayan omitodo en el proceso y que puedan causar inconsistencias en las configuraciones. Estos ambientes de desarrollo también pueden servir para probar diferentes versiones del software de los servicios que desplegaremos, o también podemos probar las nuevas versiones del sistema operativo, creamos y destruimos a nuestro antojo todo en pro de una cultura de aprendizaje continuo.

Siguientes pasos

Espero que al llegar hasta aquí hayan disfrutado de este articulo y que hayan podido realizar las prácticas de forma exitosa, todo el código que usamos lo puedes descargar de este repositorio en gitlab vagrant-centos7, en las siguientes publicaciones usaremos vagrant para crear ambientes de desarrollo en donde probaremos como desplegar diferentes servicios como un servidor Gitlab y Jenkins, hasta pronto!.

Referencias

Esta es una lista de referencias externas que puedes consultar para conocer más del tema:


Automatizando entornos de desarrollo virtuales con Vagrant
Jorge Armando Medina Acevedo 9 de agosto de 2021
Compartir
Archivar