img

¿Qué es QEMU/KVM? ¿Y Libvirt?

QEMU/KVM es una tecnología que permite crear y gestionar máquinas virtuales en un servidor.

Estas máquinas virtuales actúan como si fueran ordenadores completos, pero sin necesidad de tener hardware físico adicional.

QEMU es el software que simula el hardware y KVM es una parte del núcleo de Linux que ayuda a que las máquinas virtuales funcionen de forma rápida y eficiente.

Libvirt es una herramienta que hace más fácil la gestión de estas máquinas virtuales. En lugar de usar comandos complejos, con Libvirt puedes gestionar, crear y eliminar máquinas virtuales de forma más sencilla a través de comandos o aplicaciones gráficas.

Requisitos Previos:

Para poder ejecutar QEMU/KVM de manera óptima, debe ser instalado en el host, es decir, en nuestro equipo principal. Pero antes de empezar la instalación, hay que comprobar si nuestro equipo es compatible con esta tecnología.

Para ser más concreto, necesitamos saber si nuestro procesador soporta extensiones de virtualización en su juego de instrucciones. Para poder comprobar que es compatible, vamos /proc/cpuinfo , pasándole un egrep, con las cadenas svm para procesadores AMD y vmx para procesadores Intel.

De tal forma que, si al ejecutar esta orden aparece smv o vmx , significa que nuestro procesador es compatible, y podemos continuar la instalación:

egrep 'svm|vmx' /proc/cpuinfo --color

Requerimientos mínimos:

Para usar QEMU/KVM en un entorno de pruebas/producción se recomienda:

  • RAM:

    • Sin entorno gráfico: 512 MB.
    • Con entorno gráfico: 1-2 GB.
    • Windows: Al menos 2 GB.
  • CPU:

    • Asignar suficientes núcleos virtuales mejora el rendimiento de las máquinas virtuales.

Configuración recomendada:

  • 8 GB de RAM.
  • 100 GB de disco duro.
  • 4 núcleos de CPU.

Instalación de QEMU/KVM + libvirt:

Una vez comprobado que cumplimos los requisitos previos, y la configuración recomendada, empezamos la instalación tanto para equipos Debian, como Ubuntu de la siguiente manera:

sudo apt install qemu-system libvirt-clients libvirt-daemon-system

Una vez que finalice podemos ver la versión instalada así:

virsh version

Ahora, para que el usuario de nuestro equipo, por ejemplo, debian pueda utilizar las conexiones privilegiadas, que sirven para poder ver todas las máquinas virtuales en nuestro equipo, y no sólo la del usuario actual, hay que añadir a dicho usuario al grupo libvirt:

sudo adduser debian libvirt

Y de esta forma, ahora sí, el usuario debian puede consultar de manera privilegiada usando qemu:///system :

Para ver todas las máquinas en ejecución y paradas:

virsh -c qemu:///system list --all

Como dato adiccional, si no queremos estar ingresando siempre la parte qemu:///system, se puede añadir una variable de entorno a nuestro equipo Debian así:

export LIBVIRT_DEFAULT_URI='qemu:///system'

Instalación de Virt Manager:

Virt-Manager es una herramienta de virtualización que proporciona una interfaz gráfica para administrar máquinas virtuales KVM (Kernel-based Virtual Machine) en Linux. Permite crear, configurar y controlar máquinas virtuales, así como gestionar sus recursos y almacenamiento.

Para instalar Virt-Manager en nuestro equipo Debian:

sudo apt install virt-manager

Pode defecto, tiene configurado una conexión local privilegiada que se llama QEMU/KVM. Vemos las máquinas virtuales que están creada en esa conexión.

Con la opción Archivo -> Nueva conexión se puede crear una nueva conexión, si fuera necesario.

Si quisiéramos conectarnos de forma remota a un servidor donde se está ejecutando libvirt, podríamos crear una nueva conexión: Archivo -> Añadir conexión…, y crear una conexión y elegir la opción Conectar a anfitrión mediante SSH.

Órdenes útiles de gestión:

Entre este artículo, y Virtualización en Linux y Practica: Virtualización en Linux y servidor DHCP , se encuentran distintas formas de gestión de almacenamiento, de redes, de clonación y gestión máquinas, pero por aquí pondré algunas más importantes:

Gestión de Máquinas Virtuales:

Para poder crear y gestionar máquinas virtuales mediante la línea de comandos, se necesita la herramienta virt-install , y para obtenerla hay que instalar el paquete virtinst:

sudo apt install virtinst

Con la herramienta instalada, hay que pasarle una serie de parámetros en el propio comando para poder realizar correctamente la instalación, por ejemplo:

- virt-type: Tipo de virtualización.

- name: Nombre que tendrá la máquina.

- cdrom: La ubicación de la imagen ISO para instalar el sistema.

- os-variant: El tipo de sistema.

- disk size: El tamaño que tendrá el disco.

- memory: El tamaño que tendrá la memoria RAM.

- vcpus: El número de núcleos o cores que tendrá la máquina.

Para poder crear una máquina necesitaremos que la red default este activa, si no lo está:

virsh -c qemu:///system net-start default

Ahora veamos un ejemplo, voy a crear una máquina llamada kvm-andres, que use una imagen de debian, con un disco de 5GB, una RAM de 1GB y 1 núcleo.

Como dato adiccional, la imagen ISO, para que no de problemas de privilegios, debe estar en /var/lib/libvirt/images/, así que la muevo de descargas:

sudo mv ~/Descargas/debian-12.7.0-amd64-netinst.iso /var/lib/libvirt/images/

Y ahora sí, creo la máquina:

virt-install --connect qemu:///system \
                         --virt-type kvm \
                         --name kvm-andres \
                         --cdrom /var/lib/libvirt/images/debian-12.7.0-amd64-netinst.iso\
                         --os-variant debian10 \
                         --disk size=5 \
                         --memory 1024 \
                         --vcpus 1

Hecho esto, se abrirá la ventana gráfica de virt-viewer en la cual empezaria una instalación como de costumbre.

Acabada la instalación, en Virt Manager (más abajo para instalarlo) aparece la nueva máquina creada.

Si queremos abrir el “modo gráfico” incluso sin entono de la máquina, es decir, la pantalla donde interactuamos directamente con la máquina, y no desde el host, es con:

virt-viewer -c qemu:///system kvm-andres

Aunque lo más recomendable, y la forma en la que gestionaremos las máquinas, debido el caso es por ssh.

Comandos útiles:

Algunos comandos más utilizados para la gestión de máquinas son:

Para ver la lista completa de máquinas:

virsh -c qemu:///system list --all

Para iniciar una máquina:

virsh -c qemu:///system start nombre

Para parar una máquina de forma correcta, y para apagarla de manera forzada:

virsh -c qemu:///system shutdown nombre

virsh -c qemu:///system destroy nombre

Para reiniciar una máquina:

virsh -c qemu:///system reboot nombre

Para establecer que se inicie automáticamente al iniciar el equipo:

virsh -c qemu:///system autostart nombre

Para eliminar una máquina y que elimine también el volumen que tenga asociado (si estuviera encendida):

virsh -c qemu:///system shutdown kvm-andres

virsh -c qemu:///system destroy kvm-andres

virsh -c qemu:///system undefine --remove-all-storage nombre

Para obtener información de una máquina:

virsh -c qemu:///system dominfo nombre 

Para obtener la dirección ip de una máquina:

virsh -c qemu:///system domifaddr nombre

Para obtener información de los discos que tiene:

virsh -c qemu:///system domblklist nombre

Para modificar el nombre de una máquina (con la máquina parada):

virsh -c qemu:///system domrename nombre nombrenuevo

Para modificar la definicion XML de la máquina directamente (donde podemos modificar por ejemplo la memoria RAM o los vcpu o cores):

virsh -c qemu:///system edit nombre

Para poder ver toda la definición XML de una máquina:

virsh -c qemu:///system  dumpxml nombre

Clonación de máquinas virtuales:

En el proceso de clonación de una máquina virtual, se copia la configuración XML de la máquina de origen junto con sus discos, realizando por otra parte, ajustes en los diversos parámetros para permitir que pueda crearse nuevas máquinas en base a una “original”.

La clonación nos permite crear nuevas máquinas, sin la necesidad de tener que estar instalándolas en base a una imagen ISO, y con el tiempo que conlleva respectivamente.

Para poder realizar la clonación, la máquina debe estar parada.

Partiendo de la base de tener una máquina llamada pruebas, para poder crear una clonación:

virt-clone --connect=qemu:///system --original pruebas --auto-clone

El resultado es una nueva máquina llamada pruebas-clone , idéntica a la original. Gracias al parámetro auto-clone tambien se clonan todos los discos de la máquina original manteniendo sus respectivos archivos y datos.

Aunque también se puede especificar el nombre tanto de la máquina clonada, como de sus discos:

virt-clone --connect=qemu:///system --original pruebas --name clonada1 --file /var/lib/libvirt/images/vol_clonada1.qcow2 --auto-clone

Creación de Plantillas para clonaciones:

Una plantilla de máquina virtual es una imagen preconfigurada que permite desplegar rápidamente máquinas virtuales, ahorrando tiempo de instalación y configuración.

Con virt-clone se puede crear un clon, es decir, una copia de una máquina virtual.

Existen dos formas de crear nuevas máquinas a partir de una plantilla:

  • Clonación completa (Full): Crea una copia independiente que ocupa el mismo espacio en disco que el original.

  • Clonación enlazada (Linked): Usa la plantilla como base en solo lectura y vincula una imagen adicional para almacenar nuevos datos, ocupando menos espacio en disco.

Teniendo claro todo esto, lo principal es crear y configurar primero una máquina, para posteriormente, convertirla en la plantilla que usaremos para todo el resto de máquinas. Para lograr esto primero tenemos que eliminar toda información única de la máquina que pueda crear conflictos a la hora de realizar las siguientes clonaciones, para ello usaremos virt-sysprep , que pertenece al paquete libguestfs-tools:

sudo apt install libguestfs-tools

Con la herramienta instalada, ahora partimos de la base de convertir a plantilla una máquina Debian 12 llamada “pruebas”, con el siguiente comando:

sudo virt-sysprep -d pruebas --hostname plantilla-debian12
  • Esto además cambia el hostname de la máquina.

Esta máquina nunca debe volver a iniciarse, y para ello, eliminamos los privilegios de escritura de su volumen:

cd /var/lib/libvirt/images 

sudo chmod -w pruebas.qcow2 

Y para más seguridad, se le modifica el nombre a la máquina para indicar que es una plantilla:

virsh -c qemu:///system domrename pruebas plantilla-pruebas

Clonación Completa:

Similar a la clonación que expliqué más arriba, se clona completamente la máquina, pero en este caso es en base a una plantilla ya configurada. Para realizar este proceso es con:

virt-clone --connect=qemu:///system --original plantilla-pruebas --name clonacion1 --auto-clone

Hecho esto, para poder acceder por ssh a la máquina recien clonada, hay que seguir una serie de pasos primero porque, al haber ejecutado antes virt-sysprep las claves ssh se eliminaron y hay que regenerarlas.

El primer paso es entrar a la máquina directamente con Virt Manager, o con virt-viewer si no esta disponible así:

virt-viewer --connect=qemu:///system clonacion1

Una vez dentro como superusuario, hay que cambiarle el nombre de nuevo y regenerar las claves con:

echo "clonacion1" > /etc/hostname

ssh-keygen -A

reboot
  • ssh-keygen -A regenera la clave de la propia máquina, para que no haya errores. Pero la clave pública del host, para que podamos conectarnos a esta máquina clonada, no esta, por lo que hay que volverla a enviar, ahora lo haremos.

El siguiente paso es averiguar la ip de la máquina con (o desde Virt Manager, o con ip a):

virsh -c qemu:///system domifaddr clonacion1

Le vuelvo a enviar la clave pública ssh desde el host, o pedirá contraseña en cada conexión:

ssh-copy-id usuario@ip

Hecho esto ya tenemos acceso para conectarnos por ssh:

ssh usuario@ip

Clonación Enlazada:

Este tipo de clonación es el que más nos interesa, y es el objetivo fundamental de usar la plantilla, ya que las máquinas clonadas la usan como imagen base o tambien llamada backing store. Esto ocupa mucho menos espacio en disco, y es más rápido, pero la plantilla siempre debe estar disponible en nuestro equipo.

El proceso es el siguiente:

Comprobamos primero el tamaño de la plantilla con:

virsh -c qemu:///system domblkinfo plantilla-pruebas vda --human

Creamos un volumen que tenga el mismo espacio que la plantilla:

virsh -c qemu:///system vol-create-as default clonacion2.qcow2 10G --format qcow2 --backing-vol pruebas.qcow2 --backing-vol-format qcow2 
  • Esto crea el volumen en el pool default llamado clonacion2.qcow2 de 10GB (suponiendo que la plantilla tuviera 10GB).

  • Con backing-vol se especifica que el nuevo volumen creado clonacion2, estará basado en el volumen de la plantilla que es pruebas.qcow2.

Aunque tambien es posible hacerlo con qemu-img asi:

cd /var/lib/libvirt/images

sudo qemu-img create -f qcow2 -b pruebas.qcow2 -F qcow2 clonacion2.qcow2 10G

virsh -c qemu:///system pool-refresh default

Con el volumen correctamente creado y configurado, el proceso de crear la máquina es similar al mostrado más arriba con la diferencia que se añade el parámetro import para no indicar el medio de instalación. Por ejemplo:

virt-install --connect qemu:///system \
			 --virt-type kvm \
			 --name nueva_prueba \
			 --os-variant debian10 \
			 --disk path=/var/lib/libvirt/images/clonacion2.qcow2 \
			 --memory 1024 \
			 --vcpus 1 \
			 --import

Aunque podemos usar mejor virt clone, personalmente prefiero esta opción:

virt-clone --connect=qemu:///system --original plantilla-pruebas --name clonacion2 --file /var/lib/libvirt/images/clonacion2.qcow2 --preserve-data
  • Con el parámetro preserve-data no se copia el volumen original al nuevo.

Instantáneas de máquinas virtuales:

Para poder crear un snapshot (o instantánea) de una máquina para poder volver a un estado anterior, y poder revertir posibles errores, partiendo de una máquina llamada pruebas:

virsh -c qemu:///system snapshot-create-as pruebas --name instantanea1 --description "Sistema limpio" --atomic
  • Sistema limpio es un ejemplo, esto es el comentario para identificar el snapshot.

  • Con el parámetro atomic evitamos corrupciones de datos.

Para poder ver las instantáneas que tenemos usando virsh:

virsh -c qemu:///system snapshot-list pruebas

O por ejemplo comprobando las instantaneas que hay dentro de un volumen, es usando qemu-img:

sudo qemu-img info /var/lib/libvirt/images/pruebas.qcow2

Una vez que tenemos una instantánea, para poder regresar al punto donde se hizo es con:

virsh -c qemu:///system snapshot-revert pruebas instantánea1
  • Donde pruebas es el nombre de la máquina, e instantanea1 el snapshot disponible creado antes.

Todo este proceso, junto con los demás tipos de gestiones, están puestos en practica en Virtualización en Linux y Practica: Virtualización en Linux y servidor DHCP .

Gestión de Almacenamiento:

La gestión del almacenamiento se hace mediante pools de almacenamiento y volúmenes.

  • Pools: Es una cantidad de almacenamiento para el uso de las máquinas virtuales.

  • Volúmenes: Los pools se dividen en volúmenes. Cada uno de estos volúmenes lo utilizaran las máquinas virtuales como discos (dispositivos de bloques).

Gestion de Pools:

Para poder ver los pools en nuestro sistema (default por defecto):

virsh -c qemu:///system pool-list

Para ver más detalles del pool default por ejemplo:

virsh -c qemu:///system pool-info default 

Para crear un nuevo pool de almacenamiento:

virsh -c qemu:///system pool-define-as nombre dir --target /srv/images

Una vez creado, hay que iniciarlo (autostart para que el inicio sea automático):

virsh -c qemu:///system pool-start nombre

virsh -c qemu:///system pool-autostart nombre

Para eliminar el pool:

virsh -c qemu:///system pool-destroy nombre

virsh -c qemu:///system pool-delete nombre

virsh -c qemu:///system pool-undefine nombre 

Gestión de Volúmenes:

Para ver los volúmenes de un determinado pool como por ejemplo default:

virsh -c qemu:///system vol-list default

virsh -c qemu:///system vol-list default --details

Para crear un volumen de 5GB por ejemplo en el pool default:

virsh -c qemu:///system vol-create-as default nombrevolumen.qcow2 --format qcow2 5G 

Para obtener información de un volumen en el pool default y comprobar que se ha creado:

virsh -c qemu:///system vol-info nombrevolumen.qcow2 default

sudo ls -l /var/lib/libvirt/images/

Para eliminar un volumen del pool default:

virsh -c qemu:///system vol-delete nombrevolumen.qcow2 default

Para crear un volumen por ejemplo de 5GB utilizando qemu-img en un pool llamado poolpruebas que se encuentra en /srv/images:

cd /srv/images/

qemu-img create -f qcow2 nombrevolumen.qcow2 5G

Hecho esto hay que refrescar el pool para que aparezca el fichero y ahora si se puede comprobar el pool:

virsh -c qemu:///system pool-refresh poolpruebas

virsh -c qemu:///system vol-list poolpruebas

Para asociar un volumen en caliente a una máquina:

virsh -c qemu:///system attach-disk nombremaquina /srv/images/volnuevo.qcow2 vdb --driver=qemu --type disk --subdriver qcow2 --persistent

Para desasociar un volumen de una máquina:

virsh -c qemu:///system detach-disk nombremaquina vdb --persistent
  • vdb: es el disco que quiero desasociar, lo compruebo con lsblk -f.

Para redimensionar un volumen de una maquina parada:

virsh -c qemu:///system vol-resize volumen.qcow2 5G --pool poolpruebas

Para redimensionarlo a 5GB en una máquina en caliente:

sudo qemu-img resize /srv/images/volumen.qcow2 5G

virsh -c qemu:///system blockresize nombremaquina /srv/images/volumen.qcow2 5G

Para redimensionarlo a 10GB usando mejor virt-resize (hay que parar la máquina y copiar el disco para que funcione):

qemu-img resize volumen.qcow2 10G

cp volumen.qcow2 newvol.qcow2

virt-resize --expand /dev/sda1 volumen.qcow2 newvol.qcow2

mv newvol.qcow2 volumen.qcow2

Gestión de Redes: Definición.

La definición de redes en libvirt utiliza el formato XML. Se crean como un archivo donde se especifica una serie de parámetros, que luego se activan.

Redes NAT:

Este tipo de redes como la red default se define creando un archivo en /usr/share/libvirt/networks/ de la siguiente manera:

sudo nano /urs/share/libvirt/networks/default.xml

Con el siguiente contenido:

<network>
  <name>default</name>
  <bridge name='virbr0'/>
  <forward/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

Redes Aisladas:

Es igual a la de tipo NAT, pero quitando la etiqueta forward para deshabilitar la característica de que el host haga de router/nat.

sudo nano /urs/share/libvirt/networks/red_aislada.xml

Con el siguiente contenido:

<network>
  <name>red_aislada</name>
  <bridge name='virbr1'/>
  <ip address='192.168.123.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.123.2' end='192.168.123.254'/>
    </dhcp>
  </ip>
</network>

Redes Muy Aisladas:

En estas el host no se conecta a la red. Por lo que no hay servidor DNS, ni DHCP.

Al crearla se creara un bridge virtual donde se conectarán las máquinas virtuales, que se configurarán de forma estática su direccionamiento.

sudo nano /urs/share/libvirt/networks/red_muy_aislada.xml

Con el siguiente contenido:

<network>
  <name>red_muy_aislada</name>
  <bridge name='virbr2'/>
</network>

Esto creará distintos bridge o puentes , dependiendo de las redes que tengamos. Estos bridges se verán reflejados en las interfaces del host.

Tambien, para poder ver los bridges creados:

sudo brctl show

Una vez que tengamos definida nuestra red, por ejemplo red_muy_aislada, hay que crearla con:

virsh -c qemu:///system net-define red_muy_aislada.xml

Comandos útiles:

Para poder ver todas las redes disponibles:

virsh -c qemu:///system net-list --all

Por defecto, se encuentra la red default, aunque si hubiera o crease otra red, puedo iniciarla así:

virsh -c qemu:///system net-start default 

O para que se inicie automáticamente:

qemu:///system net-autostart default

Para obtener información de una red o ver su definición XML:

virsh -c qemu:///system net-info nombrered

virsh -c qemu:///system net-dumpxml nombrered

Para crear un bridge de forma manual en Debian, hay que modificar el archivo /etc/network/interfaces:

auto lo
iface lo inet loopback

auto enp1s0
iface enp1s0 inet manual

auto br0
iface br0 inet dhcp
        bridge-ports enp1s0
  • Donde br0 es el puente que se declara como una interfaz más.

Y reinicio el servicio de red para que se aplique:

sudo ifdown enp1s0

systemctl restart networking.service

Para crear un bridge de manera manual pero en Ubuntu:

De la misma forma, pero utilizando netplan de Ubuntu.

# Let NetworkManager manage all devices on this system
network:
  version: 2
  renderer: networkd
  ethernets:
    enp1s0:
      dhcp4: no
  bridges:
    br0:
      dhcp4: yes
      interfaces:
             - enp1s0

Y aplico los cambios con:

sudo netplan apply

Hay muchas más órdenes para gestionar todas las necesidades que podamos tener, en este artículo he hecho una selección de las más útiles en una misma sección.