Habilita la virtualización anidada para instancias de VM

En este documento, se describe cómo habilitar la asistencia para la virtualización anidada en instancias de VM de Compute Engine. También se indican los pasos básicos para iniciar y configurar una VM anidada.

La virtualización anidada agrega asistencia para las instrucciones de virtualización del procesador Intel VT-x a las VM de Compute Engine. Con la virtualización anidada, puedes iniciar una instancia de VM de forma habitual en Compute Engine y, luego, instalar un hipervisor compatible con KVM en la instancia de VM para que puedas ejecutar otra instancia de VM sobre ese hipervisor. Puedes usar la virtualización anidada en cualquier instancia de VM de Linux que se ejecute en una plataforma Haswell o más reciente. Si deseas conocer otras restricciones, consulta la subsección sobre las restricciones para la virtualización anidada.

La virtualización anidada es ideal para aplicaciones basadas en VM y cargas de trabajo en las que no es factible convertir tus imágenes de VM en Compute Engine ni importarlas. Por ejemplo, puedes usar la virtualización anidada y compilar una solución de recuperación ante desastres para una carga de trabajo local que se ejecuta en máquinas virtuales basadas en KVM, que puede conmutar por error a VM que se ejecutan en Compute Engine sin el tiempo adicional ni la organización que se necesita para convertir tu VM basada en KVM en una imagen nativa de Compute Engine. Otra carga de trabajo que podría ser adecuada para la virtualización anidada es un marco de trabajo de validación de software que necesita probar y validar nuevas versiones de un paquete de software en varias versiones de distintos SO compatibles con KVM. La ejecución de VM anidadas quita la necesidad de convertir y administrar una gran biblioteca de imágenes de Compute Engine.

Antes de comenzar

Cómo funciona la virtualización anidada

Las VM de Compute Engine se ejecutan sobre el hardware físico (el servidor host), que se conoce como el entorno L0. En el servidor host, un hipervisor preinstalado permite que un solo servidor aloje varias VM de Compute Engine, que se denominan VM nativas o L1 en Compute Engine. Cuando usas la virtualización anidada, instalas otro hipervisor sobre el SO invitado L1 y creas VM anidadas, que se denominan VM L2, con el hipervisor L1. Las VM nativas o L1 de Compute Engine que ejecutan un hipervisor invitado y las VM anidadas también pueden denominarse VM host.

Diagrama de una virtualización anidada

Restricciones

  • La virtualización anidada solo se puede habilitar para VM L1 que se ejecutan en procesadores Haswell o posteriores. Si el procesador predeterminado para una zona es Sandy Bridge o Ivy Bridge, puedes usar una selección mínima de CPU y así elegir Haswell, o versiones posteriores, para una instancia en particular. Revisa la página Regiones y zonas para determinar qué zonas son compatibles con los procesadores Haswell o versiones posteriores.
  • La virtualización anidada solo es compatible con hipervisores basados en KVM que se ejecutan en instancias de Linux. Los hipervisores Hyper-V, ESX y Xen no son compatibles.
  • Las VM de Windows no admiten la virtualización anidada; es decir, las VM host deben ejecutar un SO Linux. No obstante, las VM anidadas pueden ejecutar los sistemas operativos Windows que se describen a continuación.

Versiones probadas de KVM

Google ejecuta pruebas básicas de integración y de inicio de virtualización anidada con las siguientes combinaciones de VM host y VM anidada:

  • Debian 9 con versión de kernel 4.9 que aloja las siguientes VM anidadas:
    • CentOS 6.5 con versión de kernel 2.6
    • Debian 9 con versión de kernel 4.9
    • RHEL 5.11 con versión de kernel 2.6
    • SLES 12 SP3 con versión de kernel 4.4
    • Ubuntu 16.04 LTS con versión de kernel 4.15
    • Windows Server 2008 R2
    • Windows Server 2016 Datacenter Edition
  • SLES 12 SP3 con versión de kernel 4.4 que aloja las siguientes VM anidadas:
    • SLES 12 SP3 con versión de kernel 4.4
  • Ubuntu 16.04 LTS con versión de kernel 4.15 que aloja las siguientes VM anidadas:
    • Ubuntu 16.04 LTS con versión de kernel 4.15

Si tienes problemas para ejecutar VM anidadas en distribuciones y versiones de kernel/KVM que no figuran aquí, antes de informarlos, reproduce tu problema con uno de los entornos anteriores como sistema operativo invitado en la instancia de Compute Engine del host.

Rendimiento

Incluso con la virtualización anidada asistida por hardware, habrá una penalización por rendimiento para las propias VM anidadas y para cualquier aplicación o carga de trabajo que se ejecute dentro de ellas. Si bien es imposible predecir la degradación exacta del rendimiento para una determinada aplicación o carga de trabajo, debes esperar una penalización mínima del 10% para las cargas de trabajo vinculadas a la CPU y, posiblemente, mucho más para las cargas de trabajo vinculadas a E/S.

Habilita la virtualización anidada en una instancia

Puedes habilitar la virtualización anidada mediante la API o el componente de gcloud. Para habilitar la virtualización anidada, debes crear una imagen personalizada con una clave de licencia especial que habilite VMX en la instancia de L1 o VM host y, luego, usar esa imagen en una instancia que cumpla con las restricciones para la virtualización anidada. La clave de licencia no tiene cargos adicionales.

  1. Crea un disco de arranque a partir de una imagen pública o de una imagen personalizada con un sistema operativo. De manera alternativa, puedes omitir este paso y aplicar la licencia a un disco existente desde una de tus instancias de VM.

    gcloud

    Usa la herramienta de línea de comandos de gcloud para crear el disco a partir de la imagen de disco de arranque que elijas. Para este ejemplo, crea un disco con el nombre disk1 a partir de la familia de imágenes de debian-9:

    gcloud compute disks create disk1 --image-project debian-cloud --image-family debian-9 --zone us-central1-b

    API

    Crea un disco con el nombre disk1 a partir de la familia de imágenes de debian-9:

    POST https://compute.googleapis.com/compute/v1/projects/[PROJECT_ID]/zones/us-central1-b/disks
    
    {
     "name": "disk1",
     "sourceImage": "/projects/debian-cloud/global/images/family/debian-9"
    }

    en el que [PROJECT_ID] es el ID del proyecto.

  2. Con el disco de arranque que creaste o un disco de arranque a partir de una instancia existente, crea una imagen personalizada con la clave de licencia especial requerida para la virtualización.

    gcloud

    Si creas una imagen con la herramienta de línea de comandos de gcloud, proporciona la siguiente URL de licencia con la marca “--licenses”:

    https://compute.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx

    Por ejemplo, el siguiente comando crea una imagen denominada “nested-vm-image” a partir de un disco de ejemplo con el nombre “disk1”:

    gcloud compute images create nested-vm-image \
      --source-disk disk1 --source-disk-zone us-central1-b \
      --licenses "https://compute.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx"

    API

    En la API, incluye la propiedad de licencias de tu solicitud a la API:

    POST https://compute.googleapis.com/compute/v1/projects/[PROJECT_ID]/global/images
    
    {
       "licenses": ["projects/vm-options/global/licenses/enable-vmx"],
       "name": "nested-vm-image",
       "sourceDisk": "zones/us-central1-b/disks/disk1"
    }

    en la que [PROJECT_ID] es el ID del proyecto.

  3. Después de crear la imagen con la licencia necesaria, puedes borrar el disco de origen, si ya no lo necesitas.
  4. Crea una instancia de VM con la nueva imagen personalizada con la licencia. Debes crear la instancia en una zona que admita la plataforma de CPU Haswell o posterior. Por ejemplo:
    gcloud compute instances create example-nested-vm --zone us-central1-b \
                  --min-cpu-platform "Intel Haswell" \
                  --image nested-vm-image
  5. Confirma que la virtualización anidada esté habilitada en la VM.
    1. Conéctate a la instancia de VM. Por ejemplo:
      gcloud compute ssh example-nested-vm
    2. Ejecuta el siguiente comando para verificar que la virtualización anidada esté habilitada. Una respuesta distinta a cero confirmará que la virtualización anidada está habilitada.
      grep -cw vmx /proc/cpuinfo

Inicia una VM anidada

Puedes iniciar una VM anidada de muchas maneras diferentes. En esta sección, se proporciona un ejemplo sobre cómo iniciar una VM anidada con qemu-system-x86_64 en una VM L1 que ejecuta Debian. Si tienes problemas para ejecutar VM anidadas con métodos diferentes a este proceso documentado, reproduce tu problema con uno de estos procesos antes de informarlo como un error.

  1. Conéctate a la instancia de VM. Por ejemplo:

    gcloud compute ssh example-nested-vm
    
  2. Actualiza la instancia de VM y, luego, instala algunos paquetes necesarios:

    sudo apt-get update && sudo apt-get install qemu-kvm -y
    
  3. Descarga una imagen del SO:

    wget https://people.debian.org/~aurel32/qemu/amd64/debian_squeeze_amd64_standard.qcow2
    
  4. Ejecuta screen:

    screen
    
  5. Presiona Intro en el mensaje de bienvenida de screen.

  6. Inicia la VM anidada. Cuando se te solicite, accede con user: root, password: root.

    sudo qemu-system-x86_64 -enable-kvm -hda debian_squeeze_amd64_standard.qcow2 -m 512 -curses
    
  7. Prueba que tu VM tenga acceso externo:

    user@nested-vm:~$ wget google.com && cat index.html
  8. Cuando hayas terminado, desconéctate de la sesión de pantalla con Ctrl+A, Ctrl+D.

Inicia un puente privado entre el host y las VM anidadas

Para habilitar las conexiones entre el host y la VM anidada, puedes crear un puente privado. Este procedimiento de muestra está diseñado para una VM L1 que ejecuta Debian.

  1. Conéctate a la instancia de VM. Por ejemplo:

    gcloud compute ssh example-nested-vm
    
  2. Actualiza la instancia de VM y, luego, instala algunos paquetes necesarios:

    sudo apt-get update && sudo apt-get install uml-utilities qemu-kvm bridge-utils virtinst libvirt-daemon-system libvirt-clients -y
    
  3. Inicia la red predeterminada que viene con el paquete libvirt:

    sudo virsh net-start default
    
  4. Comprueba que ahora tienes el puente virbr0:

    sudo ifconfig -a
    
     eth0      Link encap:Ethernet  HWaddr 42:01:0a:80:00:02
               inet addr:10.128.0.2  Bcast:10.128.0.2  Mask:255.255.255.255
               UP BROADCAST RUNNING MULTICAST  MTU:1460  Metric:1
               RX packets:14799 errors:0 dropped:0 overruns:0 frame:0
               TX packets:9294 errors:0 dropped:0 overruns:0 carrier:0
               collisions:0 txqueuelen:1000
               RX bytes:97352041 (92.8 MiB)  TX bytes:1483175 (1.4 MiB)
    
     lo        Link encap:Local Loopback
               inet addr:127.0.0.1  Mask:255.0.0.0
               inet6 addr: ::1/128 Scope:Host
               UP LOOPBACK RUNNING  MTU:65536  Metric:1
               RX packets:0 errors:0 dropped:0 overruns:0 frame:0
               TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
               collisions:0 txqueuelen:0
               RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
    
     virbr0    Link encap:Ethernet  HWaddr 5a:fa:7e:d2:8b:0d
               inet addr:192.168.122.1  Bcast:192.168.122.255  Mask:255.255.255.0
               UP BROADCAST MULTICAST  MTU:1500  Metric:1
               RX packets:0 errors:0 dropped:0 overruns:0 frame:0
               TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
               collisions:0 txqueuelen:0
               RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
  5. Crea una interfaz tun para pasar de la VM host a la VM anidada:

    sudo tunctl -t tap0
    sudo ifconfig tap0 up
    
  6. Vincula la interfaz tun a la VM del puente:

    sudo brctl addif virbr0 tap0
    
  7. Verifica que la red del puente esté configurada correctamente:

    sudo brctl show
    
    bridge name     bridge id               STP enabled     interfaces
    virbr0          8000.5254005085fe       yes              tap0
  8. Descarga una imagen del SO:

    wget https://people.debian.org/~aurel32/qemu/amd64/debian_squeeze_amd64_standard.qcow2
    
  9. Ejecuta screen:

    screen
    
  10. Presiona Intro en el mensaje de bienvenida de screen.

  11. Inicia tu VM anidada:

    sudo qemu-system-x86_64 -enable-kvm -hda debian_squeeze_amd64_standard.qcow2 -m 512 -net nic -net tap,ifname=tap0,script=no -curses
    
  12. Cuando se te solicite, accede con user: root, password: root.

  13. En la VM anidada, ejecuta ifconfig para confirmar que la VM tiene una dirección en el espacio virbr0, como 192.168.122.89:

    user@nested-vm:~$ ifconfig
  14. Inicia un servidor web ficticio en el puerto 8000:

    user@nested-vm:~$ python -m SimpleHTTPServer
  15. Desconéctate de la sesión de pantalla con Ctrl+A, Ctrl+D.

  16. Prueba que la VM del host pueda hacer ping a la VM anidada:

    curl 192.168.122.89:8000
    

    La VM anidada debería mostrar algo similar a lo siguiente:

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
    <title>Directory listing for /</title>
    <body>
    <h2>Directory listing for /</h2>
    <hr>
    <ol>
    <li><a href=".aptitude/">.aptitude/</a>
    <li><a href=".bashrc">.bashrc</a>
    <li><a href=".profile">.profile</a>
    </ol>
    <hr>
    </body>
    </html>
    

Configura una VM anidada para que sea accesible desde fuera de la VM host

Puedes configurar una instancia con varias interfaces de red o configurar una instancia con un IP de alias para que las VM fuera de la VM host puedan hacer ping a la VM anidada.

En el siguiente procedimiento de muestra, se configura el host y la VM anidada para que la VM anidada sea accesible desde otras VM en la misma red, mediante la IP de alias. En este procedimiento, se usa una subred imaginaria llamada subnet1 que se creó con anterioridad. Puedes reemplazar subnet1 con el nombre de tu propia subred o crear una subred nueva llamada subnet1.

Por último, ten en cuenta que este procedimiento está diseñado para una VM L1 que ejecuta Debian.

  1. Crea una VM y habilita la virtualización anidada, pero asegúrate de incluir un rango de IP de alias y compatibilidad con el tráfico HTTP/HTTPS. Por ejemplo:

    gcloud compute instances create example-nested-vm --image nested-vm-image \
        --tags http-server,https-server --can-ip-forward \
        --min-cpu-platform "Intel Haswell" \
        --network-interface subnet=subnet1,aliases=/30
    
  2. Conéctate a la instancia de VM. Por ejemplo:

    gcloud compute ssh example-nested-vm
    
  3. Actualiza la instancia de VM y, luego, instala algunos paquetes necesarios:

    sudo apt-get update && sudo apt-get install uml-utilities qemu-kvm bridge-utils virtinst libvirt-daemon-system libvirt-clients -y
    
  4. Inicia la red predeterminada que viene con el paquete libvirt:

    sudo virsh net-start default
    
  5. Comprueba que ahora tienes el puente virbr0:

    sudo ifconfig -a
     
     eth0      Link encap:Ethernet  HWaddr 42:01:0a:80:00:02
               inet addr:10.128.0.2  Bcast:10.128.0.2  Mask:255.255.255.255
               UP BROADCAST RUNNING MULTICAST  MTU:1460  Metric:1
               RX packets:14799 errors:0 dropped:0 overruns:0 frame:0
               TX packets:9294 errors:0 dropped:0 overruns:0 carrier:0
               collisions:0 txqueuelen:1000
               RX bytes:97352041 (92.8 MiB)  TX bytes:1483175 (1.4 MiB)

    lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

    virbr0 Link encap:Ethernet HWaddr 5a:fa:7e:d2:8b:0d inet addr:192.168.122.1 Bcast:192.168.122.255 Mask:255.255.255.0 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

  6. Crea una interfaz tun para pasar de la VM host a la VM anidada:

    sudo tunctl -t tap0
    sudo ifconfig tap0 up
    
  7. Vincula la interfaz tun a la VM del puente:

    sudo brctl addif virbr0 tap0
    
  8. Verifica que la red del puente esté configurada correctamente:

    sudo brctl show
    
    bridge name     bridge id               STP enabled     interfaces
    virbr0          8000.5254005085fe       yes              tap0
  9. Descarga una imagen del SO:

    wget https://people.debian.org/~aurel32/qemu/amd64/debian_squeeze_amd64_standard.qcow2
    
  10. Ejecuta screen:

    screen
    
  11. Presiona Intro en el mensaje de bienvenida de screen.

  12. Inicia tu VM anidada:

    sudo qemu-system-x86_64 -enable-kvm -hda debian_squeeze_amd64_standard.qcow2 -m 512 -net nic -net tap,ifname=tap0,script=no -curses
    
  13. Cuando se te solicite, accede con user: root, password: root.

  14. En la VM anidada, ejecuta ifconfig para confirmar que la VM tiene una dirección en el espacio virbr0, como 192.168.122.89:

    user@nested-vm:~$ ifconfig
  15. Inicia un servidor web ficticio en el puerto 8000:

    user@nested-vm:~$ python -m SimpleHTTPServer
  16. Desconéctate de la sesión de pantalla con Ctrl+A, Ctrl+D.

  17. Prueba que la VM del host pueda hacer ping a la VM anidada:

    curl 192.168.122.89:8000
    

    La VM anidada debería mostrar algo similar a lo siguiente:

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
    <title>Directory listing for /</title>
    <body>
    <h2>Directory listing for /</h2>
    <hr>
    <ol>
    <li><a href=".aptitude/">.aptitude/</a>
    <li><a href=".bashrc">.bashrc</a>
    <li><a href=".profile">.profile</a>
    </ol>
    <hr>
    </body>
    </html>
    
  18. En tu VM host, configura iptables para permitir el reenvío desde VM host a tu VM anidada. Para la imagen de invitado L2 que se usa en estas instrucciones (debian_squeeze_amd64_standard.qcow2), primero es necesario limpiar las tablas de IP:

    sudo iptables -F
    

    A continuación, determina la IP de alias de la VM:

    ip route show table local
    

    La VM debería mostrar algo similar al resultado que se muestra a continuación. En este ejemplo hay dos direcciones IP asociadas con el dispositivo ethernet de la VM, eth0. El primero, 10.128.0.2, es la dirección IP principal de la VM, que muestra sudo ifconfig -a. La segunda, 10.128.0.13, es la dirección IP del alias de la VM.

    local 10.128.0.2 dev eth0 proto kernel scope host src 10.128.0.2
    broadcast 10.128.0.2 dev eth0 proto kernel scope link src 10.128.0.2
    local 10.128.0.13/30 dev eth0 proto 66 scope host
    broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1
    local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
    local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
    broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
    broadcast 192.168.122.0 dev virbr0 proto kernel scope link src
    192.168.122.1 linkdown
    local 192.168.122.1 dev virbr0 proto kernel scope host src 192.168.122.1
    broadcast 192.168.122.255 dev virbr0 proto kernel scope link src
    192.168.122.1 linkdown
    

    Para reenviar el tráfico desde la IP de alias (10.128.0.13) a la VM anidada (192.168.122.89):

    echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
    sudo iptables -t nat -A PREROUTING -d 10.128.0.13 -j DNAT --to-destination 192.168.122.89
    sudo iptables -t nat -A POSTROUTING -s 192.168.122.89 -j MASQUERADE
    sudo iptables -A INPUT -p udp -j ACCEPT
    sudo iptables -A FORWARD -p tcp -j ACCEPT
    sudo iptables -A OUTPUT -p tcp -j ACCEPT
    sudo iptables -A OUTPUT -p udp -j ACCEPT
    
  19. A continuación, accede a otra VM que esté en la misma red que la VM alojada y realiza una solicitud curl a la IP de alias. Por ejemplo:

    user@another-vm:~$ curl 10.128.0.13:8000

    La VM anidada debería mostrar algo similar a lo siguiente:

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
    <title>Directory listing for /</title>
    <body>
    <h2>Directory listing for /</h2>
    <hr>
    <ol>
    <li><a href=".aptitude/">.aptitude/</a>
    <li><a href=".bashrc">.bashrc</a>
    <li><a href=".profile">.profile</a>
    </ol>
    <hr>
    </body>
    </html>
    

Solución de problemas

Google ejecuta pruebas básicas de integración y de inicio de virtualización anidada con distribuciones específicas de Linux y versiones de kernel/KVM en la instancia de Compute Engine. Además, estas pruebas usan un proceso específico. Antes de informar los problemas como un error, reproduce esos problemas con los siguientes elementos:

La ejecución de grep -c vmx /proc/cpuinfo muestra 0 y determina que mi VM no está habilitada para anidar.

  1. Asegúrate de haber iniciado tu VM con una plataforma de CPU de Haswell o posterior.
  2. Asegúrate de usar la licencia correcta con tu imagen de VM.

No puedo salir de mi VM anidada.

Si no ejecutaste screen antes de cada sesión de VM anidada, puedes apagar la VM anidada o finalizar el proceso desde otra terminal. Para apagar la VM anidada, ejecuta el comando poweroff desde tu VM anidada. Otra opción es acceder a la VM host en otra terminal y finalizar el proceso. Luego, ejecuta screen en la VM host antes de iniciar una nueva VM anidada.

Mis reglas de iptables no reenvían tráfico a mi VM anidada.

  • iptables resuelve las reglas de manera descendente. Asegúrate de que tus reglas sean de mayor prioridad que otras.
  • Verifica que no haya reglas en conflicto que pudieran interceptar tus paquetes.
  • Considera limpiar tus iptables:

    1. Primero, configura las políticas predeterminadas:

      sudo iptables -P INPUT ACCEPT
      sudo iptables -P FORWARD ACCEPT
      sudo iptables -P OUTPUT ACCEPT
      
    2. A continuación, limpia todas las tablas y cadenas y, luego, borra las cadenas no predeterminadas:

      sudo iptables -t nat -F
      sudo iptables -t mangle -F
      sudo iptables -F
      sudo iptables -X
      
¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...

Documentación de Compute Engine