Migraciones a KVM: Servidor

Hoy vamos a liberarnos de Virtualbox y la tiranía de Oracle. El proyecto parece que ha entrado en un tramo de velocidad lenta, por decirlo suavemente. Hay que reconocer que para experimentar en casa es una herramienta muy cómoda y rápida de aprender, pero qué me diríais si por el mismo precio nos podemos mudar a un lugar mejor, donde el sol brilla más y las flores huelen más frescas.

Ese lugar existe y se llama KVM. Ahora me diréis que para llegar a ese sitio hay que atravesar el desierto, pero nada más lejos de la realidad. Yo pensaba igual, pero una vez que me decidí en serio a cambiar, todo se había hecho más simple.

Para empezar os diré que tenemos a nuestra disposición una herramienta gráfica incluso mejor que la que nos proporciona virtualbox, su nombre: virt-manager. Desde ahí podréis manejar vuestras máquinas virtuales cómodamente, añadir nuevas, hacer snapshots y todo lo que conlleva el manejo de estas instancias virtuales. Además, si arrancáis una instancia virtual, en cualquier momento (y desde cualquier ordenador con acceso por ssh a su anfitrión) podréis acceder a ella como si pinchárais un monitor, un teclado y un ratón.

En este primer artículo prepararemos el terreno, es decir, el servidor principal. En el siguiente ya veremos cómo configurar las máquinas virtuales con virt-manager. Para terminar, en un tercero explicaremos cómo podemos migrar las máquinas virtuales de VirtualBox a KVM, y si os lo estáis preguntando, sí, las máquinas windows también se pueden migrar.

Vamos a empezar instalando los paquetes necesarios en el servidor principal. He de decir que los guests de virtualbox activos no pueden convivir con los de kvm. De momento, si utilizáis virtualbox, lo que debéis hacer es parar todas las máquinas virtuales. Probáis kvm y más adelante, si os convence, podréis desinstalar virtualbox:

# apt-get install kvm bridge-utils libvirt-bin libvirt0 ifenslave

Como distribución estamos utilizando una Ubuntu Server 14.04.2, pero en casa tengo la misma configuración funcionando perfectamente con mi Debian Sid. En ubuntu conseguiremos estabilidad pero en otro ordenador podremos instalar una versión más moderna de virt-manager, ya que la que nos proporciona la última LTS de Ubuntu no tiene la capacidad de manejar las snapshots mediante la GUI.

El primer paquete, como habréis intuido, monta toda la configuración de la virtualización y el segundo paquete lo necesitaremos para administrar la red de una forma más cómoda. En las primeras pruebas con KVM la configuración de red fue el principal quebradero de cabeza. Crear una máquina virtual y conectarla a la red fue fácil, el problema vino cuando quise crear la segunda, a la red se le fue la pinza, pero del todo, tampoco estoy seguro de que no fuera problema de mi configuración, pero vosotros no os encontraréis con esos inconvenientes.

Investigando por ahí encontré el paquete bridge-utils, con él podremos hacer que nuestra tarjeta de red se convierta en un switch con respecto a nuestra red local y ahí engancharemos todas nuestras máquinas virtuales.

Por ahora vamos a establecer la configuración básica mediante el bridge. Suponiendo que tenemos una interfaz de red, eth0, simplemente tendremos que editar el fichero /etc/network/interfaces para que contenga la siguiente configuración:

auto lo  
iface lo inet loopback

auto eth0  
iface eth0 inet manual

auto br0  
iface br0 inet static  
    address         192.168.1.x
    netmask         255.255.255.0
    gateway         192.168.1.1
    bridge_ports    eth0
    bridge_stp      off
    bridge_fd       0
    bridge_maxwait  0
    bridge_maxage   0
    bridge_ageing   0

Recordad poner en address vuestra dirección ip. Primera observación, con esta configuración perdemos el dhcp para nuestro servidor, pero es un precio que no nos importa pagar. Seguro que hay formas de compatibilizarlo, pero seguiremos la tecnología KISS (Keep-It-Simple-Stupid). Aunque si alguien conoce la forma de configurar el bridge con el dhcp que le dé el router seguro que alguien de la comunidad le agradece la explicación.

Segunda observación, por mucho que nos duela, network-manager es nuestro enemigo, desinstaladlo sin compasión. Lo siento por los que tengan una wifi y les sea supercómoda esta herramienta, pero no casa muy bien con nuestros intereses actuales. Para el día a día y nuestro portátil favorito es la mejor opción, pero ahora no es lo que perseguimos.

De nuevo, seguro que hay formas de compatiblizarlo pero creo que no merecen la pena, teniendo en cuenta que la virtualización la solemos implementar en servidores con conexión de red ethernet hemos optado por esta configuración.

Ahora vamos a configurar el acceso a libvirt del usuario que vayamos a utilizar para conectarnos al servidor. Para ello simplemente debemos añadirlo al grupo libvirt:

# adduser <nombre_usuario> libvirt

Para nuestra comodidad, vamos a preparar el acceso remoto al servidor utilizando este usuario y sin necesidad de password. Esta receta es muy útil para nuestro día a día en el cuál accedemos a multitud de servidores aquí y allá. Lo que debemos hacer es generarnos un par de claves ssh. En el ordenador cliente ejecutaremos lo siguiente:

$ ssh-keygen
Generating public/private rsa key pair.  
Enter file in which to save the key (/home/user/.ssh/id_rsa):  
Created directory '/home/user/.ssh'.  
Enter passphrase (empty for no passphrase):  
Enter same passphrase again:  
Your identification has been saved in /home/user/.ssh/id_rsa.  
Your public key has been saved in /home/user/.ssh/id_rsa.pub.  
The key fingerprint is:  
xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx [email protected]  
The key's randomart image is:  
+--[ RSA 2048]----+
|+o  .            |
|.oo. o           |
| o.oo o .        |
|  +.   + .       |
|   .  . S .      |
|    . .. o       |
|    .o .  =      |
|     ooE.o .     |
|    ..oo         |
+-----------------+

Esta clave debemos copiarla al servidor mediante el siguiente comando:

$ ssh-copy-id -i .ssh/id_rsa.pub [email protected]

The authenticity of host 'ubuntu-server' can't be established.  
ECDSA key fingerprint is xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx.  
Are you sure you want to continue connecting (yes/no)? yes  
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
[email protected]'s password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh '[email protected]'"  
and check to make sure that only the key(s) you wanted were added.  

Y como bien habréis podido leer en la última línea, ya podréis comprobar cómo al acceder al servidor mediante ssh no os pedirá ninguna clave.

Con esto ya podríamos pasar al siguiente artículo, pero si tenéis más de una interfaz de red esperad un poco porque podremos aprovechar mejor sus capacidades, además, todavía no tengo publicado el siguiente artículo.

En virtualbox, si lo habéis probado, sabréis que podéis asignar cualquier interfaz de red del anfitrión a cualquier máquina virtual, en KVM es un poco más complicado. Mi primera intención fue configurar varios puentes y asignarle a cada máquina uno de ellos, error. Por más puentes que configuréis, al final todo el tráfico saldrá por un único punto. Si alguien ha descubierto cómo hacerlo de esta manera que lo comparta con todos nosotros. Yo me tiré varias horas intentándolo y al final opté por agrupar las interfaces de red, o lo que es lo mismo, un bonding.

Con el bonding conseguiremos sumar el ancho de banda de todas las interfaces de red y repartirlo equitativamente entre nuestras máquinas virtuales. El driver del kernel tiene varias posibilidades de despachar los paquetes que le llegan a la interfaz de red o que salen de ella. Vamos a redefinir nuestro fichero de configuración de red y luego explicamos varias cosas.

Este archivo supone que tenemos seis interfaces de red, en mi caso, dos gigabit en la placa base (em1 y em2) y una tarjeta auxiliar con cuatro puertos, también gigabit (p1p1, p1p2, p1p3 y p1p4):

auto lo  
iface lo inet loopback

auto bond0  
iface bond0 inet manual  
    bond-slaves none
    bond-mode   0
    bond-miimon 100

auto em1  
iface em1 inet manual  
    bond-master bond0

auto em2  
iface em2 inet manual  
    bond-master bond0

auto p1p1  
iface p1p1 inet manual  
    bond-master bond0

auto p1p2  
iface p1p2 inet manual  
    bond-master bond0

auto p1p3  
iface p1p3 inet manual  
    bond-master bond0

auto p1p4  
iface p1p4 inet manual  
    bond-master bond0

auto br0  
iface br0 inet static  
    address         192.168.1.x
    netmask         255.255.255.0
    gateway         192.168.1.1
    bridge_ports    bond0
    bridge_stp      off
    bridge_fd       0
    bridge_maxwait  0
    bridge_maxage   0
    bridge_ageing   0

El orden en la declaración es importante. Primero definiremos el bond, sin especificar sus esclavos. Lo más destacable aquí es el modo de trabajo del bonding. Hemos elegido el modo 0 que es el más simple, hay una cola de peticiones y se van despachando conforme hay slots libres. Los otro modos son más complejos y promenten mayor rendimiento, en nuestro caso nos basta con éste. Si tenéis algún router que tenga la posibilidad de establecer sus puertos en modo 802.3ad, vuestro modo es el 4, así podríais aprovechar la potencia del hardware que habéis adquirido. En esta página podréis ver con más detalle los modos y alguna configuración más.

Los esclavos del bonding contendrán la declaración de pertenencia en su misma área de configuración. Y al final del archivo ya definimos el bridge propiamente dicho.

Es muy simple, pero esto que véis aquí fueron varios días de investigación y ayudas de sysadmins amigos (@orioldemaria y @yonailo). Las líneas que destacaría son las dos últimas, sin ellas se perderán paquetes entre diferentes máquinas, tanto físicas como virtuales y además el dhcp que esté configurado en la red local no llegará a las máquinas virtuales, con lo que os aconsejo encarecidamente que no las olvidéis. La clave, como muchas veces ocurre apareción después de una intensa búsqueda.

Luego está la parte de cada anfitrión que queramos controlar, pero esto lo haremos en el siguiente artículo, explicando cómo configurar virt-manager en otro ordenador accediendo a nuestro servidor recién configurado mediante ssh.

Esto está muy bien para centralizar el manejo de estas máquinas, siempre que sean pocas, para entornos serios en producción deberemos optar por algo más elaborado como openstack, o crearnos scripts propios mediante python y utilizar virt-manager para casos puntuales.

En Mirai tenemos dos o tres anfitriones configurados en las oficinas centrales y controlamos todas sus máquinas virtuales desde un único punto.

Y ahora, como metáfora de toda esta interconexión de máquinas y redes, no podía olvidarme de los grandérrimos (como diría nuestro aún más grande Javier Gallego Crudo) Stereo MC's y su tema Connected, extraído de su álbum homónimo del año 1992. Todavía recuerdo aquella noche de principios de agosto, unos años después, en Benicàssim, en el FIB, en la que nos dieron una lección de que cómo hacer que una multitud de poppitos sosainas se levanten y bailen durante todo un concierto, impresionantes.

Suerte.