Manual Completo de KVM y QEMU para DevOps

1. Introducción a KVM y QEMU

KVM (Kernel-based Virtual Machine) y QEMU (Quick Emulator) son tecnologías fundamentales para la virtualización en Linux, ampliamente utilizadas en entornos DevOps para la creación y gestión de máquinas virtuales.

1.1. ¿Qué es KVM?

KVM es un módulo del kernel de Linux que permite al sistema operativo funcionar como un hipervisor Type-1 (bare metal). Convierte Linux en un hipervisor permitiendo que múltiples máquinas virtuales (VMs) aisladas ejecuten sus propios sistemas operativos.

1.2. ¿Qué es QEMU?

QEMU es un emulador de máquinas que puede ejecutar sistemas operativos completos para diferentes arquitecturas de CPU. Cuando se usa con KVM, QEMU puede aprovechar la aceleración por hardware para un rendimiento cercano al nativo.

1.3. Diferencias y relación entre KVM y QEMU

Característica KVM QEMU
Tipo Módulo del kernel (hipervisor) Emulador de máquina virtual
Rendimiento Alto (aceleración por hardware) Bajo (emulación por software)
Uso común Virtualización de producción Desarrollo y pruebas

Nota: En la práctica, KVM y QEMU se usan juntos: QEMU proporciona la emulación de dispositivos y la gestión de máquinas virtuales, mientras que KVM maneja la ejecución acelerada del código de la VM.

2. Requisitos e Instalación

2.1. Requisitos de hardware

2.2. Verificar soporte de virtualización

Verifica si tu CPU soporta virtualización:

egrep -c '(vmx|svm)' /proc/cpuinfo

Un resultado mayor que 0 indica soporte. También puedes verificar:

LC_ALL=C lscpu | grep Virtualization

2.3. Instalación en Ubuntu/Debian

sudo apt update
sudo apt install -y qemu qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager

2.4. Instalación en CentOS/RHEL

sudo yum install -y qemu-kvm libvirt libvirt-python libguestfs-tools virt-install virt-viewer
sudo systemctl enable --now libvirtd

2.5. Verificar la instalación

sudo kvm-ok
sudo virsh list --all

3. Gestión de Máquinas Virtuales

3.1. Creación de una VM con virt-install

sudo virt-install \
    --name vm1 \
    --ram 2048 \
    --vcpus 2 \
    --disk size=10 \
    --os-type linux \
    --os-variant ubuntu20.04 \
    --network bridge=virbr0 \
    --graphics spice \
    --location 'http://archive.ubuntu.com/ubuntu/dists/focal/main/installer-amd64/' \
    --extra-args 'console=ttyS0'

3.2. Comandos básicos de virsh

Comando Descripción
virsh list --all Listar todas las VMs
virsh start vm1 Iniciar una VM
virsh shutdown vm1 Apagar una VM
virsh destroy vm1 Forzar apagado de una VM
virsh suspend vm1 Suspender una VM
virsh resume vm1 Reanudar una VM suspendida
virsh console vm1 Conectarse a la consola de una VM
virsh edit vm1 Editar la configuración XML de una VM
virsh dumpxml vm1 Mostrar la configuración XML de una VM
virsh undefine vm1 Eliminar la definición de una VM (no elimina el disco)

3.3. Gestión de redes

Listar redes disponibles:

virsh net-list --all

Crear una nueva red:

virsh net-define /usr/share/libvirt/networks/nombre-red.xml
virsh net-start nombre-red
virsh net-autostart nombre-red

3.4. Gestión de almacenamiento

Listar pools de almacenamiento:

virsh pool-list --all

Crear un nuevo pool de almacenamiento:

virsh pool-define-as --name pool1 --type dir --target /ruta/al/pool
virsh pool-build pool1
virsh pool-start pool1
virsh pool-autostart pool1

4. Configuración Avanzada

4.1. Configuración XML de una VM

El archivo XML define todos los aspectos de una VM. Ejemplo básico:

<domain type='kvm'>
    <name>vm1</name>
    <memory unit='KiB'>2097152</memory>
    <vcpu placement='static'>2</vcpu>
    <os>
        <type arch='x86_64' machine='pc-i440fx-2.9'>hvm</type>
        <boot dev='hd'/>
    </os>
    <features>
        <acpi/>
        <apic/>
        <vmport state='off'/>
    </features>
    <cpu mode='host-model' check='partial'/>
    <clock offset='utc'/>
    <on_poweroff>destroy</on_poweroff>
    <on_reboot>restart</on_reboot>
    <on_crash>destroy</on_crash>
    <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/vm1.qcow2'/>
            <target dev='vda' bus='virtio'/>
            <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
        </disk>
        <interface type='network'>
            <mac address='52:54:00:12:34:56'/>
            <source network='default'/>
            <model type='virtio'/>
            <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
        </interface>
        <graphics type='spice' autoport='yes'>
            <listen type='address'/>
        </graphics>
        <video>
            <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
            <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
        </video>
    </devices>
</domain>

4.2. Configuración de CPU y memoria

Asignación de CPUs:

<vcpu placement='static'>4</vcpu>
<vcpu placement='static' current='2'>4</vcpu>  <!-- 2 de 4 CPUs activas -->

Configuración avanzada de CPU:

<cpu mode='host-passthrough' check='none'/>  <!-- Pasa toda la CPU al guest -->
<cpu mode='custom' match='exact' check='full'>
    <model fallback='forbid'>Skylake-Client</model>
    <feature policy='require' name='aes'/>
</cpu>

Configuración de memoria:

<memory unit='KiB'>4194304</memory>  <!-- 4GB -->
<currentMemory unit='KiB'>2097152</currentMemory>  <!-- 2GB asignados actualmente -->

4.3. Configuración de red avanzada

Interfaz puente (bridge):

<interface type='bridge'>
    <mac address='52:54:00:12:34:56'/>
    <source bridge='br0'/>
    <model type='virtio'/>
    <driver name='vhost'/>
</interface>

Interfaz VLAN:

<interface type='network'>
    <source network='vlan100'/>
    <virtualport type='openvswitch'/>
    <vlan>
        <tag id='100'/>
    </vlan>
</interface>

4.4. Configuración de almacenamiento avanzado

Disco raw:

<disk type='file' device='disk'>
    <driver name='qemu' type='raw'/>
    <source file='/path/to/disk.raw'/>
    <target dev='vda' bus='virtio'/>
</disk>

Disco qcow2 con cache:

<disk type='file' device='disk'>
    <driver name='qemu' type='qcow2' cache='none'/>
    <source file='/path/to/disk.qcow2'/>
    <target dev='vda' bus='virtio'/>
</disk>

Disco iSCSI:

<disk type='network' device='disk'>
    <driver name='qemu' type='raw'/>
    <source protocol='iscsi' name='iqn.2013-06.example.com:target0/0'>
        <host name='iscsi.example.com' port='3260'/>
    </source>
    <target dev='vda' bus='virtio'/>
</disk>

5. Automatización para DevOps

5.1. Creación automatizada de VMs

Script Bash para crear múltiples VMs:

#!/bin/bash

# Configuración
IMAGE_DIR="/var/lib/libvirt/images"
OS_VARIANT="ubuntu20.04"
RAM=2048
VCPUS=2
DISK_SIZE=20
NETWORK="default"

# Crear 5 VMs
for i in {1..5}; do
    VM_NAME="vm${i}"
    DISK_PATH="${IMAGE_DIR}/${VM_NAME}.qcow2"
    
    # Crear imagen de disco
    qemu-img create -f qcow2 "${DISK_PATH}" "${DISK_SIZE}G"
    
    # Instalar VM
    virt-install \
        --name "${VM_NAME}" \
        --ram "${RAM}" \
        --vcpus "${VCPUS}" \
        --disk path="${DISK_PATH}",format=qcow2 \
        --os-variant "${OS_VARIANT}" \
        --network network="${NETWORK}",model=virtio \
        --graphics none \
        --console pty,target_type=serial \
        --location "http://archive.ubuntu.com/ubuntu/dists/focal/main/installer-amd64/" \
        --extra-args "console=ttyS0,115200n8 serial" \
        --noautoconsole
done

5.2. Uso con Ansible

Playbook de Ansible para gestionar VMs:

---
- name: Manage KVM VMs
  hosts: kvm_servers
  become: yes
  tasks:
    - name: Ensure libvirt is installed
      apt:
        name:
          - qemu-kvm
          - libvirt-daemon-system
          - libvirt-clients
          - bridge-utils
          - virtinst
        state: present
        update_cache: yes
    
    - name: Create VM
      community.libvirt.virt:
        name: "{{ vm_name }}"
        state: running
        command: create
        xml: "{{ lookup('file', 'vm_template.xml') }}"
        uri: "qemu:///system"
    
    - name: Start VM if not running
      community.libvirt.virt:
        name: "{{ vm_name }}"
        state: running
        command: start
        uri: "qemu:///system"
      when: vm_state.stat.exists and not vm_state.stat.active
    
    - name: Gather VM facts
      community.libvirt.virt:
        command: facts
        name: "{{ vm_name }}"
      register: vm_facts
    
    - name: Print VM IP address
      debug:
        var: vm_facts.network_interfaces[0].addresses[0].addr

5.3. Uso con Terraform

Ejemplo de configuración de Terraform con el provider libvirt:

terraform {
  required_providers {
    libvirt = {
      source = "dmacvicar/libvirt"
    }
  }
}

provider "libvirt" {
  uri = "qemu:///system"
}

resource "libvirt_volume" "ubuntu-qcow2" {
  name   = "ubuntu.qcow2"
  pool   = "default"
  source = "https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img"
  format = "qcow2"
}

resource "libvirt_cloudinit_disk" "commoninit" {
  name      = "commoninit.iso"
  pool      = "default"
  user_data = data.template_file.user_data.rendered
}

data "template_file" "user_data" {
  template = file("${path.module}/cloud_init.cfg")
}

resource "libvirt_domain" "ubuntu-vm" {
  name   = "ubuntu-vm"
  memory = "2048"
  vcpu   = 2

  cloudinit = libvirt_cloudinit_disk.commoninit.id

  network_interface {
    network_name   = "default"
    wait_for_lease = true
  }

  console {
    type        = "pty"
    target_port = "0"
    target_type = "serial"
  }

  console {
    type        = "pty"
    target_port = "1"
    target_type = "virtio"
  }

  disk {
    volume_id = libvirt_volume.ubuntu-qcow2.id
  }

  graphics {
    type        = "spice"
    listen_type = "address"
    autoport    = true
  }
}

5.4. Cloud-init para configuración automática

Ejemplo de archivo cloud-init.cfg:

#cloud-config
hostname: ubuntu-vm
manage_etc_hosts: true
users:
  - name: devops
    ssh-authorized-keys:
      - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ...
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    groups: sudo
    shell: /bin/bash
packages:
  - qemu-guest-agent
  - nginx
runcmd:
  - systemctl enable qemu-guest-agent
  - systemctl start qemu-guest-agent
  - systemctl enable nginx
  - systemctl start nginx

6. Optimización y Seguridad

6.1. Optimización de rendimiento

Configuración de CPU y memoria:

<cpu mode='host-passthrough' check='none'/>
<numatune>
    <memory mode='strict' nodeset='0'/>
</numatune>
<memoryBacking>
    <hugepages/>
</memoryBacking>

Configuración de disco para máximo rendimiento:

<disk type='file' device='disk'>
    <driver name='qemu' type='qcow2' cache='none' io='native' discard='unmap'/>
    <source file='/path/to/disk.qcow2'/>
    <target dev='vda' bus='virtio'/>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</disk>

6.2. Configuración de seguridad

Habilitar SELinux para VMs:

<seclabel type='dynamic' model='selinux' relabel='yes'/>

Configuración de AppArmor:

<seclabel type='dynamic' model='apparmor' relabel='yes'/>

Restricciones de cgroups:

<resource>
    <partition>/machine</partition>
</resource>
<blkiotune>
    <weight>500</weight>
</blkiotune>

6.3. Snapshots y backups

Crear un snapshot:

virsh snapshot-create-as --domain vm1 --name snapshot1 --description "Primer snapshot"

Listar snapshots:

virsh snapshot-list vm1

Restaurar un snapshot:

virsh snapshot-revert vm1 snapshot1

Backup completo de una VM:

# Exportar la configuración XML
virsh dumpxml vm1 > vm1.xml

# Copiar las imágenes de disco
cp /var/lib/libvirt/images/vm1.qcow2 /backup/vm1.qcow2

7. Solución de Problemas

7.1. Problemas comunes

Error: "Could not initialize KVM"

Problemas de red

7.2. Herramientas de diagnóstico

Comandos útiles:

# Ver información sobre KVM
virsh nodeinfo

# Ver estadísticas de CPU
virsh nodecpustats

# Ver estadísticas de memoria
virsh nodememstats

# Ver información de la VM
virsh dominfo vm1

# Ver estadísticas de la VM
virsh domstats vm1

# Ver logs de libvirt
journalctl -u libvirtd -f

# Ver logs de QEMU
tail -f /var/log/libvirt/qemu/vm1.log

7.3. Depuración avanzada

Ejecutar QEMU manualmente para depuración:

qemu-system-x86_64 \
    -enable-kvm \
    -m 2048 \
    -smp 2 \
    -drive file=/path/to/image.qcow2,format=qcow2 \
    -net nic,model=virtio -net user \
    -nographic \
    -serial mon:stdio \
    -D /tmp/qemu.log \
    -d guest_errors,cpu_reset

8. Conclusión

KVM y QEMU proporcionan una plataforma poderosa y flexible para la virtualización en entornos Linux, especialmente valiosa para DevOps que necesitan automatizar la creación y gestión de infraestructura.

Las claves para un uso efectivo son:

Recursos adicionales: