
Tradicionalmente no era posible que los invitados de KVM se comportasen como hosts de virtualización, al no tener disponibles estos últimos las microinstrucciones hardware de virtualización (VMX, en el caso de los procesadores Intel-VT). Por ello, en el laboratorio que utilizamos en nuestros cursos de OpenStack utilizamos QEMU para poder virtualizar dentro de las máquinas virtuales con las que simulamos hosts físicos (nodos de virtualización) para el cloud.
Es decir, usamos el emulador QEMU para poder usar un "hypervisor" invitado dentro de otro hypervisor (KVM). Hay que decir que el uso de QEMU tiene unos costes muy drásticos en rendimiento (pues carece de soporte hardware), pero para nosotros es algo irrelevante en el contexto de un laboratorio, donde no se busca el rendimiento sino aprovechar que a todos los efectos QEMU se comporta funcionalmente como un hypervisor y OpenStack lo soporta a través de libvirt sin ningún problema.
KVM sobre KVM
Sin embargo, si queremos realmente correr KVM sobre KVM, disponemos de una funcionalidad de KVM que lo permite con procesadores Intel de forma eficiente y sencilla, aunque con ciertas limitaciones (solo con Linux e hipervisores invitados de 64 bits). Se denomina virtualización anidada y, como su nombre indica, permite a las máquinas virtuales ejecutar hipervisores como si se tratase de hosts físicos, también conocido coloquialmente como "efecto inception".
Para diferenciar de forma clara ambas formas de virtualizar, digamos que la virtualización convencional tiene dos niveles: el host físico (Level 0) y los invitados (Level 1). En cambio, en la virtualización anidada dispondremos de tres o más niveles:
- L0: host físico (KVM)
- L1: hypervisor invitado
- L2: invitado(s) anidado(s)
Esto se logra dando a la máquina virtual acceso directo a las extensiones de virtualización de la CPU de su host físico. La virtualización anidada supone una nueva vuelta de tuerca en la todavía joven tecnología de virtualización, muy interesante desde el punto de vista conceptual, aunque no para producción, al menos por el momento. Nosotros ni siquiera creemos que sea algo deseable ni recomendable para otro caso que no sea construir sandboxes y escenarios de pruebas, pero con muchas posibilidades futuras sobre todo en IaaS, con su complejidad añadida, pues no deja de ser una nueva capa de abstracción.
Configuración
Veamos cómo configurarla. En primer lugar, debemos comprobar si nuestro host físico (L0) tiene activada esta característica:
$ cat /sys/module/kvm_intel/parameters/nested
N
echo "options kvm-intel nested=1" | sudo tee /etc/modprobe.d/kvm-intel.conf
Comprobamos si se ha activado el flag:
host:~$ cat /sys/module/kvm_intel/parameters/nested
Y
En las distribuciones más modernas, como Ubuntu 14.04, se incluye ya activado en la configuración de QEMU:
host:~$ grep kvm_intel /etc/modprobe.d/*
/etc/modprobe.d/qemu-system-x86.conf:options kvm_intel nested=1
Una vez activado en el host físico, tenemos que declarar explícitamente el soporte VMX en el xml de nuestra nueva máquina virtual que ejercerá de host de virtualización:
<cpu match='exact'>
<model>Westmere</model>
<feature policy='require' name='vmx'/>
</cpu>
El XML completo quedaría así:
<domain type="kvm">
<name>nested</name>
<memory unit="M">2048</memory>
<vcpu>2</vcpu>
<cpu match='exact'>
<model>Westmere</model>
<feature policy='require' name='vmx'/>
</cpu>
<os>
<type arch="x86_64">hvm</type>
<boot dev="cdrom"/>
<boot dev="hd"/>
</os>
<features>
<acpi/>
<apic/>
</features>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type="file" device="disk">
<driver name="qemu" type="qcow2"/>
<source file="/var/lib/libvirt/images/nested.img" />
<target dev="vda" bus="virtio" />
</disk>
<disk type="file" device="cdrom">
<driver name="qemu" type="raw"/>
<source file="/var/lib/libvirt/images/ubuntu-14.04-server-amd64.iso"/>
<target dev="hdc" bus="ide"/>
</disk>
<interface type="network">
<source network="default"/>
<forward mode="nat"/>
<model type="virtio"/>
</interface>
<graphics type="vnc" port="-1" />
</devices>
</domain>
Creamos el volumen (disco virtual) donde instalaremos la VM con instrucciones VMX:
host:~$ virsh vol-create-as --pool default --name nested.img --capacity 5G --format qcow2
Ahora ya podemos definirla y arrancarla:
host:~$ virsh define nested.xml
host:~$ virsh start nested
Test
Conectamos por VNC a la VM (por ejemplo con virt-viewer), instalamos y configuramos el sistema operativo. Finalmente, verificamos desde dentro de la nueva máquina virtual que efectivamente disponemos de las instrucciones de virtualización hardware:
root@nested:~# egrep "vmx" /proc/cpuinfo
flags : fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx lm constant_tsc rep_good nopl pni pclmulqdq vmx ssse3 cx16 sse4_1 sse4_2 x2apic popcnt aes hypervisor lahf_lm vnmi ept
flags : fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx lm constant_tsc rep_good nopl pni pclmulqdq vmx ssse3 cx16 sse4_1 sse4_2 x2apic popcnt aes hypervisor lahf_lm vnmi ept
O más cómodamente desde Ubuntu:
root@nested:~# kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used
Ahora podremos empezar a desplegar sobre esta máquina virtual nuevas máquinas virtuales mediante nuestro flamante hypervisor virtualizado.
Publicado por flossystems el