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.
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.
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.
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.
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
sudo apt update
sudo apt install -y qemu qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager
sudo yum install -y qemu-kvm libvirt libvirt-python libguestfs-tools virt-install virt-viewer
sudo systemctl enable --now libvirtd
sudo kvm-ok
sudo virsh list --all
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'
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) |
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
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
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>
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 -->
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>
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>
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
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
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
}
}
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
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>
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>
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
Error: "Could not initialize KVM"
lsmod | grep kvm
Problemas de red
systemctl status libvirtd
virsh net-list --all
virsh net-destroy default && virsh net-start default
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
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
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: