Table of Contents
Virtualizzazione con Linux
Sistemi di virtualizzazione provati:
Linux kernel KVM
Una soluzione più semplice (perché integrata nel kernel) e più performante (perché realizzata in hardware) è costituita dal Kernel Based Virtual Machine. Per attivarla bisogna avere un kernel >= 2.6.20 e un processore con le estensioni Intel VT oppure AMD-V.
Per vedere se il processore ha tali estensioni controllare che in /proc/cpuinfo
sia presente il flag vmx (per i processori Intel) svm (per i processori AMD).
Per utilizzare KVM in Debaian Lenny si installa il pacchetto kvm, i moduli kernel necessarie vanno compilati manualmente grazie ai pacchetti kvm-source e module-assistant:
module-assistant auto-install --force kvm
Se si sta usando un kernel compilato in casa alla Debian way, il programma make-kpkg provvede a creare insieme al pacchetto del kernel anche il pacchetto con i moduli kvm-modules.
Vedere le istruzioni /usr/share/doc/kvm/README.Debian.
Dopo aver installato i moduli si caricano (esempio per processore AMD):
modprobe kvm modprobe kvm_amd
Configurazione host virtuale KVM
Installando la libreria libvirt si controllano in modo uniforme e trasparente macchine virtuali di tipo diverso: Qemu, KVM, Xen, ecc. La libreria fornisce tool grafici o testuali
Un host virtuale (detto anche dominio nella terminologia KVM) si configura in libvirt tramite un file .xml, la cui sintassi è documentata su libvirt.org.
Nella pagina Switching to libvirt managed QEMU instances sono documentati alcune funzioni di qemu/kvm e i corrispondenti comandi della virsh
e le opzioni di configurazione per il file .xml.
In questa pagina trovate alcuni esempi di configurazione.
Configurazione network
Esistono due modalità per il networking delle macchine guest (macchine virtuali). La modalità bridge è più potente e flessibile, ma richiede una configurazione speciale del networking sulla macchina host (macchina ospitante). La modalità network è invece più semplice da attivare, offre alle macchine guest un ambiente DHCP ed un NAT virtualizzato dalla macchina ospitante.
Modalità bridge
L'host (macchina ospitante) deve modificare la configurazione della propria scheda Ethernet (eth1 nel nostro esempio) in un bridge, mentre l'interfaccia eth1 rimane non configurata. Il tutto si ottiene con una entry di questo tipo in /etc/network/interfaces
:
auto br0 iface br0 inet static address 192.168.3.1 netmask 255.255.255.0 network 192.168.3.0 broadcast 192.168.3.255 bridge_ports eth1 bridge_stp off bridge_maxwait 10
Bisogna aver installato il pacchetto bridge-utils e si può consultare la man page di bridge-utils-interfaces(5)
per i vari parametri.
Un guest virtuale dovrà avere nella propria configurazione, nella sezione <devices>
, una sezione del tipo:
<interface type='bridge'> <model type='virtio'/> <mac address='52:54:00:12:34:65'/> <source bridge='br0'/> <target dev='tap65'/> <script path='no'/> </interface>
Quando la macchina virtuale verrà avviata, avrà a disposizione una scheda Ethernet virtuale con il MAC address specificato, tramite un'interfaccia tapX (univoca per ogni guest) sarà connessa al bridge virtuale br0 (condiviso da tutti i guest e dalla macchina host).
In questo modo le macchine virtuali si troveranno sulla stessa LAN della macchina ospitante e potranno usufruire dei servizi esistenti, tipo DHCP, default gateway, ecc. Per vedere quali interfacce sono state collegate al bridge virtuale br0 si esegue il comando:
# brctl show bridge name bridge id STP enabled interfaces br0 8000.002586e5fb2e no eth1 tap65
La scheda di rete emulata ha bisogno di opportuni driver nella macchina guest. Linux offre nativamente il supporto per tale scheda di rete (virtio-net), mentre con sistemi MS-Windows bisogna procurarsi i driver kvm-guest-drivers-windows-2.zip dal repository di Linux KVM.
Modalità network
Nella modalità network al guest viene offerto un servizio DHCP ed accesso alla rete dietro NAT offerto dall'host.
Bisogna attivare la configurazione di rete default definita in /etc/libvirt/qemu/networks/default.xml
:
virsh # net-start default
Oppure rendere tale configurazione attiva per default (questa azione crea un link simbolico in /etc/libvirt/qemu/networks/autostart/
):
virsh # net-autostart default
Con queste premesse un guest può avere la seguente sezione nel file .xml:
<interface type='network'> <source network='default'/> <mac address='52:54:00:00:03:41'/> </interface>
Anche questa configurazione comunque crea un'interfaccia virtuale vnet0 e la aggiunge ad un bridge virbr0. L'interfaccia bridge avrà indirizzo 192.168.122.1 e verrà usata per tutti gli host virtuali che invece apparterranno alla network 192.168.122.[2-254].
La configurazione dell'interfaccia virbr0 della macchina ospitante e le impostazioni del DHCP virtuale sono nel file /etc/libvirt/qemu/networks/default.xml
:
<network> <name>default</name> <bridge name="virbr0" /> <forward/> <ip address="192.168.122.1" netmask="255.255.255.0"> <dhcp> <range start="192.168.122.100" end="192.168.122.254" /> <host mac="52:54:00:00:03:11" name="omega.rigacci.org" ip="192.168.122.11" /> </dhcp> </ip> </network>
Dopo aver cambiato il file di configurazione non basta riavviare il servizio libvirt-bin, perché l'istanza di dnsmasq che gestisce il DHCP non viene riavviata. La procedura corretta dovrebbe essere quella di riavviare la rete virtuale default dalla virsh, con i comandi net-destroy default
e net-start default
, ma si deve fare attenzione alle macchine virtuali in esecuzione (perdono l'accesso alla rete?). È possibile killare il processo dnsmasq e riavviarlo con i parametri nuovi impostandoli manualmente.
Starting a KVM virtual machine on an headless host
NOTE: This is not the preferred way to handle a virtual machine. See the following paragraph about libvirt toolkit instaed. Anyway this method - which uses screen(1)
- requires very few resources on the host and on the guest machine; no VNC or X11 forwarding is required. To control the virtual host you have only a serial console, so you can disable consoles on tty[1-6] changing /etc/inittab
and using the console
kernel boot parameter.
We have a guest host without monitor (headless). After installing KVM on it, we prepared a Qemu disk image and installed it with a basic Debian system using debootstrap
.
The first run of the virtual machine will use the kernel and initrd files of the guest host. The virtual machine is operated via the console on the (virtual) serial line, attacched to the controlling terminal via the -nographic
option:
# Create a Qemu disk image with minimal Debian system: qemu-make-debian-root 3096 lenny http://ftp.us.debian.org/debian debian_lenny.img # Start KVM Qemu using the guest kernel/initrd. Console on the virtual serial line: kvm -nographic \ -kernel /vmlinuz \ -initrd /initrd.img \ -append "console=ttyS0,115200n8 root=/dev/hda1 ro" \ debian_lenny.img
The -nographic
option causes the program to run without Simple Direct Layer graphics and without the VNC server.
Default password for deboostrap Debian base system is root / root.
After this first install we logged into the new host and we installed the linux-image, grub and some other packages so it becomes a full featured installation. We prefer to have the virtual system to appear on the local network, so we used the bridge setup. Into /etc/network/interfaces
we have disabled eth0 and added br0:
# Bridge auto br0 iface br0 inet static address 192.168.2.7 netmask 255.255.255.0 network 192.168.2.0 broadcast 192.168.2.255 gateway 192.168.2.2 bridge_ports eth0 bridge_stp off bridge_maxwait 5 up /usr/sbin/ethtool -s eth0 wol g || true
Because we want to start the virtual machine in a non-interactive, headless mode, this is the script we need:
#!/bin/sh screen -d -m -S "virtual_lenny" \ kvm -m 384 -nographic \ -net nic,vlan=0,model=rtl8139 -net tap,vlan=0 \ debian_lenny.img
After the virtual host is running, use screen -r
to attach the console on the virtual serial line, or (better) do a remote login via ssh.
Libvirt to manage KVM hosts: install, start, stop
The libvirt toolkit allow to manage some virtualization systems (namely xen, qemu and kvm) in a consistent and uniform way. It provides an infrastructure to manage virtual machines: create, start, destroy, shutdown, …
Install the following Debian Lenny packages:
- libvirt-bin
- virt-viewer
- virtinst
The virt-install can be used to create a new virtual host, here it is an example:
virt-install \ --name virtual_lenny \ --virt-type kvm \ --memory 1024 \ --disk /home/kvm/virtual_lenny.img,size=3 \ --cdrom /var/lib/libvirt/images/debian-10.0.0-amd64-netinst.iso \ --os-variant auto \ --network bridge=br0 \ --vnc
The disk size is specified in Gibabytes, the network uses the bridge mode via the br0 interface. If you don't specify the --network option, it will use the network mode named default. You can also use the option --network none.
See the man page for using a CD-ROM boot image, etc. Now list the existing virtual machines and connect to the VNC console with the viewer (it requires X forward):
virsh list virt-viewer virtual_lenny
The virt-install creates the xml configuration file into /etc/libvirt/qemu/virtual_lenny.xml and creates the virtual disk file into /home/virt/virtual_lenny.img.
In the following example the orginal file created by virt-install
was partially modified by hand. See the syntax documentation.
<domain type='kvm'> <name>virtual_lenny</name> <uuid>e445f6a2-d358-f118-a4c3-7498702fb39f</uuid> <memory>393216</memory> <currentMemory>393216</currentMemory> <vcpu>1</vcpu> <os> <type arch='x86_64' machine='pc'>hvm</type> <boot dev='hd'/> </os> <features> <acpi/> </features> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>destroy</on_crash> <devices> <emulator>/usr/bin/kvm</emulator> <disk type='file' device='disk'> <source file='/home/kvm/virtual_lenny.img'/> <target dev='hda'/> </disk> <disk type='file' device='disk'> <source file='/home/kvm/home_partition.img'/> <target dev='hdc'/> </disk> <disk type='file' device='disk'> <source file='/home/kvm/data_partition.img'/> <target dev='hdd'/> </disk> <interface type='bridge'> <mac address='52:54:00:12:34:56'/> <source bridge='br0'/> <target dev='tap0'/> <script path='no'/> </interface> <graphics type='vnc' port='autoport' listen='127.0.0.1'/> <serial type="null"> </serial> </devices> </domain>
NOTICE: The attributes arch and machine of tag <os><type> are madatory with Libvirt 3.0.0 (provided by Debian 9 Stretch), they were instead not required in previous versions. To view the the list of supported machines, execute qemu-system-x86_64 -machine help
.
The VNC port can be assigned automatically (seting it to port='autoport'
), or assigned statically, e.g. port='5901'
.
The <os><type> and <cpu> tags of the XML configuration file, determines what CPU is offered to the guest machine. Here it is the default choosed by virt-install
on a Xeon host (Debian 10 Buster with libvirt 5.0):
<os> <type arch='x86_64' machine='pc'>hvm</type> </os> <cpu mode='host-model' check='partial'> <model fallback='allow'/> </cpu>
See the documentation about Operating system booting and CPU model and topology for more info about <os><type> and <cpu> tags.
You can use a specific option if you have an Intel CPU:
<cpu mode='custom' match='exact'> <model fallback='allow'>Skylake-Client</model> </cpu>
or this one if you have an AMD CPU:
<cpu mode='custom' match='exact'> <model fallback='allow'>Opteron_G3</model> </cpu>
Libvirt and ACPI
The nice thing is that you can control automatic start and stop of the virtual machines. Install the acpid package on the virtual host and load the button kernel module. Then you can start a shutdown sequence on the virtual host issuing the following command on the hosting machine:
virsh shutdown virtual_lenny
The default shutdown of the host machine, will perform a clean shutdown of the guest machines.
Connecting to the virtual host
Using graphical display
The virt-viewer
utility can display the graphical console of a virtual machine, it needs that the kvm emulation is started with the -vnc option and it needs a graphical display.
If you are connecting from a remote host you can export the DISPLAY (or do X11 forward via ssh), but performances will be poor. In this case it is preferable to use a vnc client, like krdc, and connect to the vnc port of the hosting machine. Check that the vnc server is listening on the public IP address, not just onto 127.0.0.1 loopback.
Using text only
NOTE: The following method (serial console on pty) unfortunately does not work. Bug #494831 blocks Qemu/Kvm startup, untill a client opens the pty. Another option shall be to connect the emulatad serial line to a telnet server, but as far I know there is no way to request this configuration via libvirt xml configuration file. The Qemu/Kvm relevant option is:
-serial telnet:0.0.0.0:4444,server,nowait,nodelay
If you don't want to access the graphical display (because you are on a slow connection), you can always setup an emulated serial console to be used via virsh. Change the serial section in the xml file, setting <serial type="pty">
, start the virsh
and issue the console
command:
virsh # console virtual_lenny
To disconnect from the console, hit Ctrl-]
.
Obviously you need that the virtual host is using the serial line for the console, this means starting the kernel with something like this (/boot/grub/menu.lst
):
kernel /vmlinuz console=tty0 console=ttyS0,38400n8 root=/dev/hda1 ro
and put a getty program on the serial line /etc/inittab
:
T0:2345:respawn:/sbin/getty 38400 ttyS0
Autostart
See the virsh(1)
man page for details. Example: let the lenny domain (virtual host) to autostart on boot:
# virsh autostart lenny Domain lenny marked as autostarted
This simply add a symbolic link to the domain xml file into the /etc/libvirt/qemu/autostart/
directory.
Poweroff
Attenzione, il comando /etc/init.d/libvirt-bin stop
termina il demone libvirtd
e tutte le macchine virtuali attivi senza inviare il segnale di poweroff. Come si fa a fare uno shutdown regolare?
Da riga di comando è semplice (installare la gestione dell'ACPI sulla macchina virtuale):
# virsh shutdown lenny Domain lenny is being shutdown
Per automatizzare lo shutdown di tutti i domini attivi al momento dello shutdown della macchina ospite si può aggiungere uno script /etc/init.d/libvirt-shutdown
, attivandolo in questo modo:
update-rc.d libvirt-shutdown stop 15 0 1 6 .
il numero di ordine 15 fa in modo che lo script venga eseguito prima di /etc/init.d/libvirt-bin
, i runlevel interessati sono 0, 1 e 6, cioè halt, single-user e reboot. Lo script è il seguente:
#!/bin/sh # # Send an ACPI poweroff event to each running virtual hosts. # # Add this script at runlevel 0, 1 and 6 with the command: # update-rc.d libvirt-shutdown stop 15 0 1 6 . # # Do NOT "set -e" NAME=$(basename $0) SHUTDOWN_TIMEOUT=30 # Max time for virtual domains shutdown. SHUTDOWN_EXTRA_WAIT=15 # Extra wait, to be safe. PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin case "$1" in stop) virsh list | grep '\brunning$' | awk '{print $2}' \ | xargs -r -n1 virsh shutdown I=0 echo -n "Wait for virtual domains to shutdown." while (virsh list | egrep -q '\b((running)|(shutdown))$'); do sleep 1 echo -n '.' I=$[ $I + 1 ] test $I -gt $SHUTDOWN_TIMEOUT && break done sleep $SHUTDOWN_EXTRA_WAIT if [ $I -gt $SHUTDOWN_TIMEOUT ]; then echo " FAILED" else echo " DONE" fi ;; *) echo "Usage: $NAME stop" ;; esac
Windows XP as a guest on libvirt KVM host
I had some problem installing Windows XP Professional as a guest system under KVM handled via Libvirt.
It turned out that kvm requires two extra parameters to complete the Windows installation: -win2k-hack
and -std-vga
, otherwise the process will hang indefinitely during peripheral probing.
This is the /etc/libvirt/qemu/winxp.xml
configuration file I used:
<domain type='kvm'> <name>winxp</name> <uuid>bb8db601-8184-f438-bb25-a2d6c97c9ec3</uuid> <memory>524288</memory> <currentMemory>393216</currentMemory> <vcpu>1</vcpu> <os> <type>hvm</type> <boot dev='cdrom'/> <boot dev='hd'/> </os> <features> <acpi/> </features> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>destroy</on_crash> <devices> <emulator>/usr/bin/kvm</emulator> <disk type='file' device='disk'> <source file='/home/kvm/winxp/rootfs.img'/> <target dev='hda'/> </disk> <disk type='file' device='cdrom'> <source file='/home/kvm/common/winxp.iso'/> <target dev='hdb'/> </disk> <interface type='bridge'> <mac address='52:54:00:12:34:70'/> <source bridge='br0'/> <target dev='tap6'/> <script path='no'/> </interface> <graphics type='vnc' port='autoport' listen='192.168.2.7'/> <serial type="null"> </serial> </devices> </domain>
To solve the installation problem I stopped the libvirt instance of winxp and started the kvm process manually adding the extra parameters:
#!/bin/sh /usr/bin/kvm -M pc -m 512 -smp 1 -name winxp -boot dc \ -drive file=/home/kvm/winxp/rootfs.img,if=ide,index=0,boot=on \ -drive file=/home/kvm/common/winxp.iso,if=ide,media=cdrom,index=1 \ -serial null -parallel none -usb -win2k-hack -std-vga
The reboot performed during the install process did not work, I had to restart manually the virtual machine a second time.
Once the installation was completed, I restarted the Windows XP guest using libvirt and adjusted the screen settings as needed. The emulated VGA card is a VESA 2.0 VBE when option -std-vga
is in use, a Cirrus Logic GD5446 otherwise.
I also got a mouse synchronization problem using the VNC console: the local pointer moves more than the emulated one, causing severe problem pointing objects at the edges of the emulated screen. I solved disabling Enhance pointer precision in Control Panel, mouse settings.
Changing CD-ROM image in a running KVM Qemu
With a modern and working libvirt it is possibile to eject or load a new image into a virtual CD-ROM drive with virsh
:
virsh attach-disk --type cdrom --mode readonly guestname "" hdb virsh attach-disk --type cdrom --mode readonly guestname "/home/kvm/common/disc2.iso" hdb
The following recipe uses the monitor interface of the qemu/kvm emulator instead. To swap CD-ROM image in a virtual host we need to access the host kvm/qemu monitor. Libvirt starts the KVM hypervisor with the -monitor pty
option, so we need to know which pty terminal was allocated for the monitor. Read the libvirt log:
cat /var/log/libvirt/qemu/domain.log /usr/bin/kvm -S -M pc -m 384 -smp 1 -name domain -monitor pty -boot c -drive file=... char device redirected to /dev/pts/1 info cpus
so the pseudo terminal is /dev/pts/1
in this case, we can use minicom
to attach to the monitor:
minicom -op /dev/pts/1
Now we can check which block devices are in use, eject a CD-ROM image and insert a new one:
(qemu) info block ide0-hd0: type=hd removable=0 file=/home/kvm/domain/rootfs.img ro=0 drv=raw ide0-cd1: type=cdrom removable=1 locked=0 file=/home/kvm/common/CentOS-4.5-i386-bin1of4.iso ro=0 drv=raw (qemu) eject ide0-cd1 (qemu) change ide0-cd1 /home/kvm/common/CentOS-4.5-i386-bin2of4.iso
Problema con KVM e disco NFS
Pare che ci sia un problema con KVM e i filesystem montati via NFS: in caso di intensa attività di rete si arriva ad un forte rallentamento fino allo stallo completo. Sulla macchina virtuale si possono notare messaggi di errore del tipo:
nfs: server 192.168.2.7 not responding, still trying
Il problema sembra non presentarsi se si utilizza come scheda di rete virtuale il model=virtio
(il modello predefinito dovrebbe essere rtl8139). Bisogna ovviamente che il sistema operativo ospite lo supporti, cosa che il kernel Linux fa, almeno dalla versione 2.6.26 di Debian Lenny.
Questo un estratto dal file di configurazione libvirt:
<interface type='bridge'> <model type='virtio'/> <mac address='52:54:00:12:34:70'/> <source bridge='br0'/> <target dev='tap70'/> <script path='no'/> </interface>
Riferimenti:
Problema di timeout su disco
Se la piattaforma ospitante è troppo carica (o forse se vengono effettuate operazioni di migrazione della macchina virtuale?), può accadere che il disco virtuale non risponda per diversi secondi. Ecco il messaggio registrato da dmesg
:
[100449.816153] ata1: lost interrupt (Status 0x50) [100467.710383] end_request: I/O error, dev sda, sector 43343336 [100467.710922] Aborting journal on device sda3-8. [100467.712097] EXT4-fs error (device sda3): ext4_journal_start_sb: Detected aborted journal [100467.712594] EXT4-fs (sda3): Remounting filesystem read-only [100469.754031] EXT4-fs error (device sda3) in ext4_da_writepages: IO failure [100469.754676] EXT4-fs (sda3): ext4_da_writepages: jbd2_start: 840 pages, ino 138323; err -30
In tal caso è possibile incrementare il timeout predefinito di 30 secondi:
echo 180 > /sys/block/sda/device/timeout
Per rendere permanente questa modifica in Debian si può installare il pacchetto sysfsutils e aggiungere questa riga al file /etc/sysfs.conf
:
block/sda/device/timeout = 180
C'è chi suggerisce addirittura timeout di 900 secondi.
Virtuozzo
Il software di virtualizzazione Virtuozzo viene utilizzato da alcuni provider di VPS. Si tratta di software non libero.
Limite regole iptables
La piattaforma di virtualizzazione pone dei limiti sul numero di regole netfilter che si possono attivare. Per vedere il limite attuale:
cat /proc/user_beancounters
Vedere il valore barrier e limit di numiptent. Solo l'amministratore Virtuozzo può modificare tale limite.
L'errore che si può verificare - ad esempio avviando il firewall Shorewall - è:
iptables-restore: line 129 failed
Virtualbox
Prove fatte su Ubuntu 11.10. Si installa il pacchetto linux-headers-*
relativo alla versione kernel in uso (uname -a
) e il pacchetto con i sorgenti del modulo kernel virtualbox-dkms
. Al termine dell'installazione dei sorgenti il modulo kernel dovrebbe risultare compilato e installato:
find /lib/modules/ | grep vboxdrv /lib/modules/3.0.0-30-generic-pae/updates/dkms/vboxdrv.ko /lib/modules/3.0.0-32-generic-pae/updates/dkms/vboxdrv.ko
In caso di aggiornamento del kernel bisogna ricordarsi di installare anche il pacchetto linux-headers-*
relativo, e tutto dovrebbe funzionare automaticamente.