Virtualización con KVM bajo GNU/Linux

Este artículo presenta un resumen de cómo instalar y utilizar la tecnología de virtualización KVM para provisionar y ejecutar máquinas virtuales en Hosts GNU/Linux.


¿Qué es KVM?

La descripción oficial de KVM dice aproximadamente:

KVM (de Kernel-based Virtual Machine) es una solución de virtualización para Linux corriendo sobre hardware x86 que hace uso de las extensiones de virtualización por hardware del procesador (Intel VT o AMD-V).

Con KVM, un host Linux puede ejecutar múltiples máquinas virtuales con Linux o Windows sin ninguna modificación necesaria en estos. Cada máquina virtual tiene hardware virtualizado privado: tarjeta de red, disco, adaptador gráfico, etc.

KVM es parte del kernel desde la versión 2.6.20 y consta de:

  • Un módulo del kernel (kvm.ko) que proporciona el core de la infraestructura de virtualización.
  • Un módulo específico para cada procesador (kvm-intel.ko o kvm-amd.ko).

Otras partes (algunas de apoyo, otras opcionales) de KVM son:

  • libvirt: Una biblioteca para interactuar con las capacidades de virtualización de Linux independientemente de la solución de virtualización que hay debajo (KVM, XEN, etc), con la que arrancar/parar/etc máquinas virtuales.
  • virt-manager: Herramienta GUI para la gestión de máquinas virtuales de un host.
  • virt-install: script de python desarrollado por RedHat para la provisión desatendida de guests.
  • ubuntu-vm-builder: desarrollado por Canonical, permite la provisión desatendida de guests Ubuntu.
  • tigervnc / xtightvncviewer: Cliente de VNC, para conectarse a la consola "física" de los guests virtuales remotamente.
  • libmigration: Necesaria para disponer de HA entre hosts KVM.
  • OpenNebula: Interfaz web para la administración de una infraestructura Cloud ("en la nube") entre hosts KVM y XEN (y, teóricamente, VMWare).


Instalación de KVM

Verificamos si la CPU soporta virtualization por hardware (HVT):

# egrep -c '(vmx|svm)' --color=always /proc/cpuinfo
0  = Nuestra CPU no soporta virtualización por hardware (KVM funcionará, pero más lento)
>1 = La CPU sí soporta virtualización por hardware.

Verificamos que estamos utilizando un procesador y kernel de 64 bits. En caso contrario, no podremos levantar máquinas virtuales de 64 bits o con más de 2GB de RAM.

# egrep -c ' lm ' /proc/cpuinfo
0  = CPU de 32 bits.
>1 = CPU de 64 bits.

# uname -m
x86_64 = kernel de 64 bits
i386/i486/i586/i686 = kernel de 32 bits

Instalamos los paquetes necesarios para virtualización:


En el caso de CentOS / RedHat:

# rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY*
# yum groupinstall Virtualization "Virtualization Client" bridge-utils \
                "Virtualization Platform" "Virtualization Tools"
# yum install dejavu-lgc-sans-fonts xorg-x11-xauth 
# yum install tigervnc (if you plan to connect to machines locally)
# yum install virt-manager openssh-askpass

(Instalará qemu-kvm, qemu-kvm-tools, libvirt, python-virtinst, y virt-manager)


En el caso de Ubuntu / Debian:

# apt-get install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils
# apt-get install virt-viewer xtightvncviewer
# apt-get install virt-manager

Reiniciamos el servidor para asegurarnos de que se arrancan todos los servicios necesarios y que se aplican las reglas de udev para KVM. Esto también permitirá a dbus crear el machine-id. Si no lo hacemos, al arrancar virt-manager obtendremos el siguiente error:

# virt-manager
D-Bus library appears to be incorrectly set up; failed to read machine uuid: 
Failed to open "/var/lib/dbus/machine-id": No such file or directory

Si no podemos reiniciar por algún motivo (aunque es lo recomendado), podemos generar el machine-id a mano con el siguiente comando:

	
# dbus-uuidgen > /var/lib/dbus/machine-id

A continuación, cargamos en memoria los módulos de kvm y arrancamos libvirtd (si no lo ha hecho ya el sistema tras el reinicio). Para ello cargamos los módulos kvm y kvm_intel o kvm_amd y arrancamos libvirtd. Si es necesario, añadiremos la configuración del sistema necesaria para que se carguen en el arranque.

# modprobe kvm
# modprobe kvm_intel   # o kvm_adm
# lsmod | grep kvm
kvm_intel 46589  0
kvm       292815 1 kvm_intel

# /etc/init.d/libvirtd start

# chkconfig libvirtd on     (en CentOS/Redhat)

Verificamos la instalación, comprobando que todo ha levantado correctamente. Lo haremos solicitando el listado de máquinas en ejecución. Si todo está correcto, veremos (inicialmente) un listado de VMs vacío:

OK:
# virsh -c qemu:///system list
 Id Name                 State
----------------------------------

ERROR:
# virsh -c qemu:///system list
libvir: Remote error : Permission denied 
error: failed to connect to the hypervisor

(En ese caso específico de error, verifica que existen permisos de escritura de grupo sobre /var/run/libvirt/libvirt-sock y que hemos reentrado en el sistema con el usuario ya dentro del grupo concreto).


SELINUX / PolicyKit

Puede resultar conveniente desactivar SELINUX en el host KVM. Si decidimos no desactivarlo, pueden ser necesarios cambios para mover la ubicación por defecto de las máquinas virtuales (normalmente /var/lib/libvirt/images). Si, por ejemplo, queremos mover los datos a /vm/, deberemos (por ejemplo, en CentOS):

# yum install policycoreutils-python
# semanage fcontext -a -t virt_image_t "/vm(/.*)?"
restorecon -R /vm

Si queremos acceder a libvirt (una vez instalado) con algún usuario no privilegiado, tendremos que hacer cambios en PolicyKit:

# vim /etc/polkit-1/localauthority/50-local.d/50-libvirt-remote-access.pkla
[libvirt Management Access]
Identity=unix-user:USER_NAME_HERE
Action=org.libvirt.unix.manage
ResultAny=yes
ResultInactive=yes
ResultActive=yes
(En lugar de unix-user:USER_NAME, podemos usar Identity=unix-group:GROUP_NAME)

# /etc/init.d/libvirtd restart


Configuración de red

Lo normal si planeamos prestar servicios con las máquinas virtuales bajo KVM es que debamos reconfigurar el host para que el interfaz de red con el direccionamiento donde se prestarán estos servicios haga de bridge para el tráfico de las máquinas virtuales.

Tanto en RedHat / CentOS como en Ubuntu, esto pasa por instalar el paquete bridge-utils y por reconfigurar los interfaces de red para pasar la configuración de red del interfaz en cuestión a un interfaz "br0" (br1, br2…) que será el que hará el bridging.


En el caso de RedHat / Centos:

# yum install bridge-utils
# cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-br0

Modificamos ifcfg-eth0 y comentamos BOOTPROTO, IPADDR, PREFIX, GATEWAY, DNS1, DNS2, etc y añadimos BRIDGE=br0. Modificamos ifcfg-br0 y mantenemos las anteriores variables añadiendo TYPE=Bridge en lugar de TYPE=Ethernet:

# cat /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
HWADDR=xx:yy:zz:aa:bb:cc
ONBOOT=yes
BRIDGE=br0

# cat /etc/sysconfig/network-scripts/ifcfg-br0
DEVICE=br0
TYPE=Bridge
BOOTPROTO=static
ONBOOT=yes
IPADDR=192.168.1.3
NETMASK=255.255.255.0
(...)

# service network restart


En el caso de Ubuntu / Debian:

Lo primero que tenemos que hacer es asignar la "capability" CAP_NET_ADMIN al usuario que va a gestionar las máquinas virtuales (si no es root) ya que desde el kernel 2.6.18 se requieren para usar TUN/TAP.

# apt-get install libcap2-bin

Para 64 bits: 
# setcap cap_net_admin=ei /usr/bin/qemu-system-x86_64 

Para 32 bits:
# setcap cap_net_admin=ei /usr/bin/qemu

# cat /etc/security/capability.conf:
cap_net_admin        USER-NAME-HERE

Después, editamos /etc/network/interfaces y renombramos eth0 como br0:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual

auto br0
iface br0 inet static
        address 192.168.1.3
        network 192.168.1.0
        netmask 255.255.255.0
        broadcast 192.168.1.255
        gateway 192.168.1.1
        bridge_ports eth0
        bridge_stp off
        bridge_fd 0
        bridge_maxwait 0

Si queremos usar DHCP:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual

auto br0
iface br0 inet dhcp
        bridge_ports eth0
        bridge_stp off
        bridge_fd 0
        bridge_maxwait 0

Después, reiniciamos la red:

# /etc/init.d/networking restart

Si detectamos una pequeña parada en el host KVM cuando arrancamos o detenemos un guest, deberemos añadir lo siguiente a la configuración de br0:

post-up ip link set br0 address xx:yy:zz:aa:bb:cc

Reemplazando xx:yy:zz:aa:bb:cc por la MAC del adaptador ethernet físico qu forma parte del bridge.

NOTA para todas las versiones de Linux: El Bridging podría no funcionar si el dispositivo físico de red es un dispositivo wireless, ya que no todos los dispositivos wireless soportan bridging.


Creación de máquinas virtuales

Para crear las máquinas virtuales tenemos diferentes alternativas:

  • virt-manager: interfaz gráfica de usuario para la gestión y creación de las máquinas virtuales, tanto localmente en el propio host (con ssh + X11 Forwarding) como en remoto.
  • virt-install / ubuntu-vm-builder: scripts para provisionar una nueva máquina completa incluyendo la instalación de la misma y la configuración de parámetros como networking, hostname, memoria, procesadores, paquetes instalados, etc.
  • virsh / qemu-img: Creación de discos y máquinas virtuales manualmente, utilizando los comandos apropiados para ello.

[EN PREPARACION]



<Volver a la sección de GNU/Linux>