Si queremos levantar máquinas virtuales en un entorno Linux KVM que no disponga de entorno gráfico podemos levantar máquinas virtuales desde linea de comando usando una plantilla XML.
Este artículo explica como funciona internamente el despliegue que se realiza con Ansible-libvirt en https://www.disasterproject.com/index.php/2019/06/entorno-minimo-kvm-y-ansible/
Table of Contents
Instalar Qemu-KVM y Libvirt
Primero debemos tener instalado libvirt y Qemu-KVM que en Ubuntu/Debian se instala con:
$ sudo apt-get install -y libvirt-daemon-system python-libvirt python-lxml
Y en CentOS/Redhat con:
$ sudo yum install -y libvirt-daemon-kvm python-lxml
Para iniciar el servicio haremos $ sudo systemctl enable libvirtd && sudo systemctl start libvirtd
Configurar una plantilla de red
Libvirt nos provee de una poderosa herramienta para gestión de las máquinas virtuales llamada ‘virsh’, la cual debemos de utilizar para poder gestionar las máquinas virtuales KVM desde la linea de comandos.
Para una máquina virtual necesitamos principalmente tres elementos, el primero es una configuración de red que entre otras cosas provea a las máquinas virtuales de IP vía DHCP. Para ello libvirt necesita de una plantilla XML como la siguiente (que llamaremos net.xml):
<network>
<name>NOMBRE_DE_RED</name>
<forward mode='nat'>
<nat>
<port start='1' end='65535'/>
</nat>
</forward>
<bridge name='NOMBRE_DEL_BRIDGE' stp='on' delay='0'/>
<ip address='IP_HOST' netmask='MASCARA_RED'>
<dhcp>
<range start='INICIO_RANGO_DHCP' end='FIN_RANGO_DHCP'/>
</dhcp>
</ip>
</network>
Cuyos elementos principales son:
- NOMBRE_DE RED: Nombre descriptivo que vamos a dar a la red, por ejemplo red_pruebas o red_producción.
- NOMBRE_DEL_BRIDGE: Cada red crea una interfaz en el servidor anfitrión que servirá para dar salida y entrada a los paquetes de dicha red hacia el exterior. Aquí le asignamos un nombre descriptivo que nos permita identificar el interfaz.
- IP_HOST: La IP que dicho interfaz tendrá en el servidor anfitrión y que será la puerta de enlace de las máquinas virtuales
- MASCARA_RED: Depende de la red, habitualmente para pruebas y demos siempre una clase C (255.255.255.0)
- INICIO_RANGO_DHCP: Para asignar IPs a las máquinas virtuales libvirt usa un servidor DHCP interno (basado en dnsmasq), aquí definimos la primera IP que podemos servir a las máquinas virtuales.
- FIN_RANGO_DHCP: Y aquí le decimos la última IP que podemos servir a las máquinas virtuales para su uso.
Preparando la imagen del sistema operativo
El segundo elemento es la imagen de la máquina virtual, la imagen se puede crear o descargar, siendo recomendable lo segundo para reducir el tiempo de despliegue. Una fuente de imágenes para máquinas virtuales con KVM/libvirt es Vagrant ( https://app.vagrantup.com/boxes/search?provider=libvirt ), para obtener una imagen de la máquina virtual que nos interese de las que existen en dicha página nos las descargaremos de https://app.vagrantup.com/NOMBRE_APP/boxes/ETIQUETA_APP/versions/VERSION_APP/providers/libvirt.box siendo NOMBRE_APP el nombre de la aplicación que queremos utilizar (p.e. debian), ETIQUETA_APP es la distribución de dicha aplicación (p.e. stretch64) y por último VERSION_APP es la versión de la aplicación (p.e. 9.9.0). Aún así existen repositorios de imágenes específicos como por ejemplo los de CentOs que están en http://cloud.centos.org/centos/7/vagrant/x86_64/images .
Una vez obtenido el archivo libvirt.box, se descomprime con tar -zcf libvirt.box
lo que nos genera tres archivos, uno de los cuales es la imagen de la máquina virtual (box.img) que renombraremos a NOMBRE_DESCRIPTIVO.qcow2 y copiaremos en la carpeta estándar para imágenes de máquinas virtuales de libvirt (/var/lib/libvirt/images) y le daremos permisos al usuario libvirt para que pueda gestionar dicha imagen (chown libvirt /var/lib/libvirt/images/NOMBRE_DESCRIPTIVO.qcow2
)
Es importante indicar que si queremos acceder a la máquina virtual vamos a necesitar una clave que la descargamos con wget -O insecure_private_key
https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant
, que le aplicamos permisos para el acceso solo para el usuario actual ( $ chmod 600 insecure_private_key
)
Plantilla para la máquina virtual
El tercer elemento para crear la máquina virtual una vez creada la red es una plantilla de máquina virtual, que para un sistema operativo reciente tendrá la siguiente forma:
<domain type='kvm'>
<name>NOMBRE_VM</name>
<memory unit='MB'>MEMORY_VM</memory>
<vcpu>CPU_NUMBER</vcpu>
<os>
<type>hvm</type>
<bootmenu enable='no'/>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='RUTA_ALMACEN_IMAGENES/NOMBRE_IMAGEN.qcow2'/>
<target dev='vda' bus='virtio'/>
</disk>
<interface type='network'>
<source network='NOMBRE_DE_RED'/>
<model type='virtio'/>
</interface>
<console type='pty'>
<target type='serial' port='0'/>
</console>
<input type='mouse' bus='ps2'>
<alias name='input0'/>
</input>
<input type='keyboard' bus='ps2'>
<alias name='input1'/>
</input>
<graphics type='spice' port='5900' autoport='yes' listen='127.0.0.1'>
<listen type='address' address='127.0.0.1'/>
<image compression='off'/>
</graphics>
<video>
<model type='cirrus' vram='16384' heads='1' primary='yes'/>
<alias name='video0'/>
</video>
<memballoon model='virtio'/>
</devices>
</domain>
Cuyos elementos son:
- NOMBRE_VM: El nombre descriptivo que nos permitirá identificar la máquina virtual
- MEMORY_VM: Cuanta memoria en MB le asignamos a la máquina virtual
- CPU_NUMBER: Cuantas CPU virtuales va a disponer la máquina virtual
- RUTA_ALMACEN_IMAGENES: La ruta donde hemos guardado la máquina virtual, la estándar es /var/lib/libvirt/images
- NOMBRE_IMAGEN: Que nombre descriptivo hemos dado a la imagen en el punto anterior
- NOMBRE_DE_RED: Que nombre descriptivo le hemos dado a la red que va a gestionar la máquina virtual
Desplegando la máquina virtual
Una vez creadas las plantillas y desplegada la imagen ejecutamos:
# sudo virsh net-create plantilla_red.xml
# sudo virsh create plantilla_máquina_virtual.xml
Por último comprobamos que funciona, primero identificamos si está iniciado con # sudo virsh list
, segundo obtenemos la ip en uso con # sudo virsh net-dhcp-leases NOMBRE_DE_RED
y por último accedemos a la IP asignada con # ssh -i insecure_private_key vagrant@IP