Creación de máquinas virtuales con Libvirt: Linux y Windows

lunes, 28 de agosto de 2023
Tiempo de lectura 12 minutos

Hace un par de semanas, como parte de una actualización a mi equipo DAS + la Mini PC con el Intel Celeron J4125 de la que he hablado hace ya tiempo, tuve la oportunidad de hacerme con un AMD Ryzen 5 5600G, junto con todo lo necesario para construir un equipo donde pudiera integrar los discos duros, a un muy buen precio. Una de las primeras cosas que vi posible para este procesador, que hasta la fecha se ha visto más que capaz de manejar todo lo que se le pida, es iniciarme con la virtualización. Tenía pendiente un par de proyectos para los que quería disponer de una máquina virtual con Windows, ya que no quería instalar un Windows 10 o similar en el servidor, pero sí necesitaba software que corre bajo entornos Windows funcionando 24/7.

Ahora que ya tengo un equipo que posee la posibilidad de virtualizar alcanzando un rendimiento más que notable, me he decidido a instalar libvirt y probar todo lo que se puede hacer con esta solución de software. Y el resultado me ha gustado mucho, aunque dejaré aquí algunos apuntes porque todo está muy disperso más allá de la documentación de RedHat, creadores de Libvirt y para cuyos sistemas se enfoca casi todo el desarrollo. Como referencia, todo esto se ha realizado en un sistema con Debian 12 y hasta la fecha solo me he concentrado en la virtualización KVM (libvirt soporta LXC, Xen y Virtualbox además de KVM). Eso sí, todavía no he tocado nada de redes, así que por el momento mis máquinas virtuales pueden acceder a internet, pero nadie fuera del equipo anfitrión puede acceder a ellas.

Hay que decir también que por el momento tengo poca idea de todo esto. Lo que viene a continuación son solo apuntes y cosas que he visto que funcionan.

Instalando Libvirt

Libvirt es una aplicación que pretende hacer la virtualización y creación de contenedores más fácil, abstrayendo para ello muchas de las cosas que anteriormente requerían parámetros diferentes (como KVM y LXC) o ediciones manuales (como redes virtuales). La idea es que gracias a libvirt, que en realidad funciona como una capa de abstracción, se pueda gestionar la creación de contenedores y máquinas virtuales en diferentes plataformas.

Naturalmente, antes de comenzar, es necesario instalar las herramientas del propio libvirt. en debian, esto se hace con el siguiente comando en terminal:

$ sudo apt-get install --no-install-recommends qemu-kvm libvirt-daemon-system libvirt-daemon virtinst bridge-utils libosinfo-bin

Una vez instalado, libvirt-daemon debería iniciar automáticamente (la unidad se llama libvirtd en Debian). Esta unidad se encarga de cargar los módulos KVM en el Kernel para permitir la virtualización. Si se cuenta con un procesador AMD o intel, este también debería cargar los módulos kvm-amd o kvm-intel, lo que permite virtualización asistida por hardware. Se puede comprobar la lista de módulos del kernel cargados con el siguiente comando:

lsmod | grep kvm

Si en el resultado de este comando no aparecen kvm_intel o kvm_amd, y el procesador donde se ejecuta el sistema soporta virtualización asistida por hardware, es importante activar este soporte en las opciones UEFI del equipo. De lo contrario no se estará aprovechando toda la potencia que estos equipos pueden ofrecer al emular otros.

finalmente, es importante iniciar la red por defecto que proporciona libvirt. Esto permite comunicar al anfitrión con las máquinas virtuales en caso de ser necesario. Esto se hace con los siguientes comandos:

$ sudo virsh net-start default
$ sudo virsh net-autostart default

Creando máquinas virtuales

Al terminar de instalar estos paquetes y configurar el arranque automático de la red proporcionada por libvirt, estamos listos para comenzar a crear una máquina virtual. Normalmente este proceso no suele ser de lo más accesible, ya que como mínimo después de crear la máquina virtual se debe instalar el sistema operativo. Para ver la máquina virtual se suele utilizar VNC, lo que transmite la imagen desde un servidor remoto, pero no se ocupa de ningún otro medio, como el audio. Afortunadamente, podemos configurar un servidor de spice, lo que, entre otras cosas, nos ayudará, con ciertos temas puntuales de los que todavía no sé cómo solucionar, a tener tanto audio como video al manejar la máquina virtual, haciendo mucho por la accesibilidad en ese sentido.

Ejemplo 1: Máquina virtual Linux

Para este ejemplo, crearemos una máquina virtual (utilizando virt-install) donde podremos meter el propio instalador de Debian 12. Esta máquina escuchará a través del servidor Spice en un puerto consecutivo, comenzando por el 5900, y nos podremos conectar a ella mediante una contraseña. Una vez dentro de la sesión Spice, podremos manejar el instalador y activar su lector de pantalla en caso de ser necesario, para realizar todo el proceso de instalación en el sistema virtual.

Lo primero siempre será descargar la imagen ISO del sistema que se desea instalar, para luego presentarla a libvirt como unidad de disco. En el caso de Debian 12, se puede descargar la imagen netinst, lo que presenta solo el sistema mínimo desde donde correremos la instalación accesible. Las imágenes ISO del sistema netinst se encuentran en esta página

$ wget https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.1.0-amd64-netinst.iso

Después, habrá que mover la imagen hacia el directorio propiedad de libvirt, de lo contrario se quejará de no poder acceder a la imagen en pasos posteriores:

$ sudo mkdir /var/lib/libvirt/iso
$ sudo mv debian-12.1.0-amd64-netinst.iso /var/lib/libvirt/iso

finalmente, ya podemos crear la máquina virtual, de esta forma:

$ sudo virt-install --name test --cdrom /var/lib/libvirt/iso/debian-12.1.0-amd64-netinst.iso --os-variant=debian11 --network network=default --disk size=20,cache=none,bus=virtio --memory 2048 --sound default --graphics spice,listen=::,password=test1 --vcpu 2 --noautoconsole

Donde las opciones, de acuerdo con la documentación de virt-install, se explican como sigue:

  • –name: el nombre de nuestro “dominio”. Para libvirt, todo lo que creamos, sea una máquina virtual o un contenedor, se llama Dominio (domain en inglés). Este nombre será útil después, para hacer operaciones con la máquina virtual.
  • –cdrom: Especifica la ruta hacia una imagen ISO donde se encuentran los archivos necesarios para la instalación del sistema. Esta ISO será considerada como el “CD de instalación”. Si te encontraras en el directorio /var/lib/libvirt/iso, esta ruta podría ser relativa.
  • –os-variant: La variante del sistema a instalar. Se debe colocar la más próxima, aunque la versión no coincida, como en este caso. Para ver la lista de variantes que se pueden colocar aquí, se puede usar el comando virt-install –os-variant=list y seleccionar una.
  • –network: Red a utilizar. Si en la instalación de libvirt del equipo anfitrión hay creadas más de una red, aquí se puede especificar una distinta.
  • –disk: Estas son las opciones para añadir una unidad de disco a la nueva máquina virtual. Cuando las opciones que se añadirán tienen varios parámetros, la sintaxis es colocarlos todos juntos, separados por una coma, pero normalmente sin espacios. Aquí el parámetro size controla la cantidad de gigabytes que se desea reservar para el disco duro virtual, y hemos decidido desactivar la cache para aumentar el rendimiento y la vida útil del SSD del servidor. Finalmente, con bus=virtio, nos valemos de la “paravirtualización” para aumentar en gran medida el rendimiento de nuestra máquina virtual. Este tipo de mejora en la virtualización permite hacer un uso más eficiente y compartido de algunos recursos del hardware donde corre la máquina virtual, evitando así emular todo el hardware necesario para el sistema operativo.
  • –memory: Cantidad de memoria, en megabytes, a asignar a la máquina virtual. Debería siempre ser menor a la del equipo anfitrión. Es importante que en general no se exceda el valor del equipo anfitrión en todas las máquinas virtuales, ya que podría producirse un problema si todas las máquinas comienzan a utilizar más memoria al mismo tiempo y el anfitrión se quedara sin RAM.
  • –sound default: Se añade un dispositivo de audio, el predeterminado, a la máquina virtual.
  • –graphics: Este es quizá uno de los argumentos más complejos y a la vez importantes. Spice (simple protocol for independent computing environments) es lo que nos permitirá poder ver una máquina virtual, aunque no nos encontremos en el mismo equipo donde se creó. Además de algunas otras mejoras, Spice transmite de manera predeterminada audio y video, lo que nos será de gran ayuda para ejecutar la instalación de forma accesible. Por defecto Spice reserva el puerto 5900 para la primera sesión, luego 5901 para la segunda sesión, y así sucesivamente. Con listen se indica la dirección de escucha. Por defecto es 127.0.0.1, lo que hará accesible la conexión solo a través del mismo equipo donde se crea la máquina virtual. Poniendo 0.0.0.0, hacemos que escuche en todas las direcciones IPV 4 disponibles, permitiendo la conexión remota. Si escribimos :: hará lo mismo, pero usando IPV6 en lugar de la versión 4. Finalmente, se debería especificar una contraseña, con password. Esta clave la solicita el cliente Spice al conectar, y no debe ser la misma que se use al momento de instalar el sistema virtual.
  • –vcpu: Cantidad de CPU virtuales a asignar al dominio.
  • –noautoconsole: Esta opción impedirá que libvirt intente conectarse a la consola justo después de crear e iniciar el dominio.

Una vez ejecutado este comando, libvirt creará la imagen donde se guardarán los archivos del disco duro virtual, le asignará un dispositivo virtual de red a la VM, y la iniciará. A partir de este momento, debemos iniciar la sesión conectándonos a la sesión de spice para poder instalar así el sistema operativo. Cómo se instalará el sistema no es algo que se va a cubrir en esta publicación, pero es importante hablar sobre el cliente que usaremos para conectarnos a Spice. Eso sí, si queremos revisar la URL de conexión a nuestro dominio, desde la máquina donde haya sido ejecutado virt install, se puede obtener así:

$ sudo virsh domdisplay test

Esto nos mostrará la cadena que forma nuestra URL, que será del tipo “spice://localhost:5900”. Al conectar al servicio, recuerda que ese “localhost” se debe cambiar por la dirección IP del servidor, o de lo contrario fallará.

Descargando remote viewer

Remote viewer es una aplicación que permite conectarnos a una máquina virtual mediante el protocolo Spice. Esta aplicación está disponible para todos los sistemas operativos más populares, aunque en Windows no es accesible. De todos modos, no es difícil usarla. Su descarga, que puedes ver en esta página, permite hacernos con virt viewer para sistemas de 32 o 64 bits. Cualquiera que sea la arquitectura, se descarga y se instalará como cualquier archivo instalable para Windows.

Para conectarnos a Spice es necesario introducir una cadena de caracteres indicando el protocolo por delante. Si la IP donde escucha nuestro servidor Spice fuera 192.168.1.12, por ejemplo, y nuestro puerto fuera el 5900 como en el ejemplo anterior, entonces nuestra URL de spice sería spice://192.168.1.12:5900.

Una vez abierto remote viewer, simplemente hay que escribir la URL de conexión a spice y pulsar intro. Después de eso, si el título de la ventana cambia a “autenticación requerida”, debemos escribir la contraseña y volver a pulsar enter. Si cambia a alguna otra cosa, se puede utilizar el OCR del lector de pantalla para poder leer la información de la ventana y comprender así el error.

Después de haber autenticado la sesión, el título de la ventana debería cambiar al nombre de nuestra máquina virtual. Si esto ha sido así, significa que en la ventana podemos ver la máquina virtual, y tan pronto como presionemos alguna combinación de teclado, por ejemplo, esta se enviará a la VM. También podemos escuchar sonido si esta lo emite. De forma predeterminada, cuando la ventana de la VM gana el foco del sistema, el teclado y mouse son capturados y enviados a la VM. Para salir de ahí, se puede pulsar la combinación ctrl+alt+G y ya se puede trabajar en la máquina física en lugar de la virtual. Aquí se debe ya realizar la instalación normal y corriente de cualquier sistema.

Un punto importante y curioso de la instalación: al terminar la primera fase de la misma, cuando el equipo deberá reiniciarse, por alguna razón que todavía no entiendo bien, en lugar de esto se apaga y debemos iniciarlo manualmente. Afortunadamente esto solo ocurre la primera vez. Para iniciar un dominio, se debe utilizar este comando, donde “test” es el nombre del dominio:

$ sudo virsh start test

Si deseas ver la lista de dominios y su estado actual, es con este otro:

$ sudo virsh list --all

Windows

Tener una máquina Virtual de Linux está bien, pero poder tener Windows y Linux en un solo equipo es todavía mejor. Para esto, sin embargo, hay que realizar algunos pasos extra, ya que lo más óptimo para que los sistemas Windows funcionen bien cuando son virtualizados es recurrir a los drivers VirtIO para Windows, que no están incluidos en la ISO de instalación proporcionada por Microsoft. Entonces, en resumen, se deben descargar los drivers en su propia imagen ISO, descargar la ISO de Windows que se desee instalar, y generar una máquina virtual con ambas imágenes como dispositivos. Después, cuando Windows muestre la pantalla para seleccionar el disco donde se debe instalar el sistema, cargar los nuevos drivers leyéndolos desde la ISO de VirtIO drivers.

Esta es la versión más reciente de la imagen ISO de los drivers VirtIO.

Una vez con los drivers descargados, se deben colocar ambas imágenes ISO en el directorio /var/lib/libvirt/iso, y luego se debe crear el dominio con un comando parecido al siguiente:

$ sudo virt-install --name windows-vm --cdrom /var/lib/libvirt/iso/windows10.iso --os-variant=win10 --network network=default --disk size=50,cache=none,bus=virtio --disk path=/var/lib/libvirt/iso/virtio-drivers.iso,device=cdrom --memory 4096 --sound default --graphics spice,listen=::,password=hardpasswordforwindows --vcpu 4 --video qxl --noautoconsole

En este comando lo que ha cambiado es que se añade un segundo disco con el contenido de la imagen ISO de los drivers VirtIO. Al terminar de crear el dominio, se puede utilizar spice para instalar el sistema en la máquina virtual, cargando el driver directamente de la unidad que debería ser visible para el Windows.

Driver Balloon

Una vez terminada la instalación normal de Windows, debería instalarse el driver “Balloon” para permitir un acceso más rápido, eficiente y ordenado a la memoria RAM del equipo anfitrión. Para esto, desde el administrador de dispositivos de la máquina Virtual, en la sección “otros dispositivos”, se debe abrir el menú de contexto del dispositivo llamado simplemente “dispositivo PCI” y seleccionar la opción “Actualizar controlador”. Después, del diálogo que aparece, seleccionar la opción “Buscar controladores en este equipo”, lo que permitirá buscar un directorio del sistema donde se encuentren los controladores. En este punto, se debe seleccionar el directorio de la unidad de disco que contiene los drivers VirtIO, y dejar que Windows busque e instale los drivers desde esa ubicación.

Finalmente, desde la misma unidad de disco, se pueden instalar las “guest tools” en caso de ser necesarias. Mejoran las prestaciones de Spice en general.

Conclusión

A partir de aquí las posibilidades son muchas. Se puede jugar con las redes y redireccionamiento de puertos entre el anfitrión y las máquinas virtuales, crear más máquinas y probar el sistema en diferentes de ellas, crear “Snapshots” de las mismas y hasta clonar una VM para que sirva como base a nuevas creaciones.

Comments

You can use your Mastodon account to reply to this post.

Reply

Administración Linux NAS tutoriales

Libvirt KVM qemu spice Linux Windows