Es sabido que una de las fortalezas de FreeBSD es su sistema de virtualización mediante
jails
, pero hay ocasiones en las que necesitaremos instalar algún sistema no-FreeBSD, ya sea un Windoz o Linux.
En estos casos se suele optar por algún gestor
basado en Bhyve
, pero si el equipo es muy viejo(en mi caso: IntelCore2Duo P9500/2.53GHz) y no dispone de las extensiones de virtualización necesarias a nivel de CPU, Bhyve no podrá funcionar, la única opción que nos queda es Qemu.
Qemu es mucho mas lento ya que se emula un procesador completo sin utilizar ninguna ayuda hardware, según el uso que le vayamos a dar esto resultará viable o no.
Pero no todo es malo, Qemu permite delegar solo un puerto USB a una máquina virtual, cosa que con BHyve no era posible si no era
delegando una tarjeta PCI entera
.
Instalación Qemu:
Instalamos el software:
pkg install qemu
Vamos a hacer las pruebas con una Debian, asà que nos bajamos la ISO:
wget https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.1.0-amd64-netinst.iso
Creamos el disco duro:
mkdir qemu-vms
qemu-img create -f qcow2 /root/qemu-vms/debian13.img 50G
Arrancamos la máquina virtual desde el CD-ROM:
qemu-system-x86_64 -m 2048 -hda /root/qemu-vms/debian13.img -cdrom debian-13.1.0-amd64-netinst.iso -boot d -vnc :0 -vga std
Si tenemos el tráfico filtrado en el servidor padre mediante
PF
, debemos añadir una ACL para tener acceso al VNC/SSH de la máquina virtual y añadir reglas adicionales en caso de proporcionar otros servicios en la máquina virtual:
vi /etc/pf.conf
# VNC Qemu installation:
pass in proto tcp from 192.168.XX.XX to any port 5900
# SSH Qemu:
pass in proto tcp to 192.168.XX.XX port 2222
Accedemos al VNC:
vncviewer 192.168.YY.YY:5900
En mi caso resulta necesario delegar un puerto USB a la máquina virtual, asà que identificamos el puerto en cuestión:
usbconfig
ugen1.3: <RTL2838 DVB-T Realtek Semiconductor Corp.> at usbus1, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (500mA)
Desvinculamos el USB del SO antes de pasárselo a la máquian virtual:
usbconfig -u 1 -a 3 detach_kernel_driver
Le pasamos el puerto USB, por defecto Qemu utiliza SLIRP(NAT red interna), asà que debemos redirigir los puertos que nos interesen:
qemu-system-x86_64 \
-accel tcg,thread=multi \
-cpu max \
-smp 2 \
-m 2048 \
-drive file=/root/qemu-vms/debian13.img,if=virtio,cache=writeback \
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8073-:8073 \
-device virtio-net,netdev=net0 \
-device qemu-xhci,id=xhci \
-device usb-host,hostbus=1,hostaddr=3 \
-vnc :0 -vga std \
-daemonize
Accedemos a la máquina virtual via SSH:
ssh kr0m@192.168.YY.YY -p2222
Donde podemos comprobar que efectivamente se le ha delegado el puerto USB:
lsusb
Bus 001 Device 002: ID 0bda:2838 Realtek Semiconductor Corp. RTL2838 DVB-T
Para parar la máquina virtual no basta con un halt, he tenido que utilizar systemctl poweroff.
Cada vez que creemos una máquina virtual nueva debemos tomar la precaución de no pisar el puerto SSH ni el VNC, si lo hacemos veremos estos mensajes:
qemu-system-x86_64: -netdev user,id=net0,hostfwd=tcp::2222-:22: Could not set up host forwarding rule 'tcp::2222-:22'
qemu-system-x86_64: -vnc :0: Failed to find an available port: Address already in use
Un ejemplo cambiado al siguiente puerto serÃa:
-netdev user,id=net0,hostfwd=tcp::2223-:22 --> ssh kr0m@192.168.YY.YY -p2223
-vnc :1 -vga std --> vncviewer 192.168.YY.YY:5901
Si se trata de una máquina virtual que vamos a utilizar de forma asidua, la mejor manera de gestionarla es mediante un script de RC:
vi /usr/local/etc/rc.d/qemuDebian
#!/bin/sh
#
# PROVIDE: qemuDebian
# REQUIRE: DAEMON
# KEYWORD: shutdown
. /etc/rc.subr
name=qemuDebian
rcvar=qemuDebian_enable
command="/usr/local/bin/qemu-system-x86_64"
command_args="\
-accel tcg,thread=multi \
-cpu max \
-smp 2 \
-m 2048 \
-drive file=/root/qemu-vms/debian13.img,if=virtio,cache=writeback \
-netdev user,id=net0,hostfwd=tcp::2222-:22,hostfwd=tcp::8073-:8073 \
-device virtio-net,netdev=net0 \
-device qemu-xhci,id=xhci \
-device usb-host,hostbus=1,hostaddr=3 \
-vnc :0 -vga std"
start_cmd="${name}_start"
stop_cmd="${name}_stop"
status_cmd="${name}_status"
pidfile="/var/run/${name}.pid"
qemuDebian_start(){
echo "Starting service: ${name}."
/usr/sbin/daemon -c -f -p ${pidfile} ${command} ${command_args}
}
qemuDebian_stop(){
if [ -f ${pidfile} ]; then
echo "Stopping service: ${name}"
kill -s TERM $(cat ${pidfile})
sleep 3
else
echo "It appears ${name} is not running."
fi
}
qemuDebian_status(){
if [ -f ${pidfile} ]; then
echo "${name} running with PID: $(cat ${pidfile})"
else
echo "It appears ${name} is not running."
fi
}
load_rc_config $name
run_rc_command "$1"
NOTA: Como ahora lanzamos Qemu desde daemon, no hace falta el parámetro -daemonize
Asignamos permisos:
chmod 555 /usr/local/etc/rc.d/qemuDebian
Habilitamos el servicio y lo arrancamos:
sysrc qemuDebian_enable="YES"
service qemuDebian start
Comprobamos que haya arrancado:
service qemuDebian status
Trucos:
Podemos ver un htop de las máquina Qemu pero debemos tener en cuenta que si se lanzan nuevas máquinas tendremos que relanzar el comando para que refresque la lista:
htop -p $(pgrep qemu-system | tr '\n' ',' | sed 's/,$//')
Podemos consultar información de un disco de este modo:
qemu-img info /root/qemu-vms/debian13.img
image: /root/qemu-vms/debian13.img
file format: qcow2
virtual size: 50 GiB (53687091200 bytes)
disk size: 2.21 GiB
cluster_size: 65536
Format specific information:
compat: 1.1
compression type: zlib
lazy refcounts: false
refcount bits: 16
corrupt: false
extended l2: false
Child node '/file':
filename: /root/qemu-vms/debian13.img
protocol type: file
file length: 4.77 GiB (5116657664 bytes)
disk size: 2.21 GiB
Como podemos ver la información cuadra:
du -h /root/qemu-vms/debian13.img
2.2G /root/qemu-vms/debian13.img
Cada vez que creemos una máquina virtual nueva debemos tomar la precaución de no pisar el puerto SSH ni el VNC, si lo hacemos veremos estos mensajes:
qemu-system-x86_64: -netdev user,id=net0,hostfwd=tcp::2222-:22: Could not set up host forwarding rule 'tcp::2222-:22'
qemu-system-x86_64: -vnc :0: Failed to find an available port: Address already in use
Un ejemplo cambiado al siguiente puerto serÃa:
-netdev user,id=net0,hostfwd=tcp::2223-:22 --> ssh kr0m@192.168.YY.YY -p2223
-vnc :1 -vga std --> vncviewer 192.168.YY.YY:5901