====== Virtualizzazione con Linux ======
Sistemi di virtualizzazione provati:
* [[qemu]]
* [[xen]]
* [[qemu_kvm]]
===== Linux kernel KVM =====
Una soluzione **più semplice** (perché integrata nel kernel) e **più performante** (perché realizzata in hardware) è costituita dal **[[http://kvm.qumranet.com/kvmwiki|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 **[[http://libvirt.org/formatdomain.html|libvirt.org]]**.
Nella pagina **[[http://wiki.libvirt.org/page/QEMUSwitchToLibvirt|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 ''%%%%'', una sezione del tipo:
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 {{.:software:kvm-guest-drivers-windows-2.zip|kvm-guest-drivers-windows-2.zip}} dal repository di [[http://sourceforge.net/projects/kvm/|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:
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''**:
default
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 [[http://www.libvirt.org/formatdomain.html|syntax documentation]].
virtual_lennye445f6a2-d358-f118-a4c3-7498702fb39f3932163932161hvmdestroyrestartdestroy/usr/bin/kvm
**NOTICE**: The attributes **arch** and **machine** of tag **%%%%** 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 **%%%%** and **%%%%** 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):
hvm
See the documentation about **[[https://libvirt.org/formatdomain.html#elementsOS|Operating system booting]]** and **[[https://libvirt.org/formatdomain.html#elementsCPU|CPU model and topology]]** for more info about **%%%%** and **%%%%** tags.
You can use a **specific option** if you have an **Intel CPU**:
Skylake-Client
or this one if you have an **AMD CPU**:
Opteron_G3
===== 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. [[http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=494831|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 **''%%%%''**, 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:
winxpbb8db601-8184-f438-bb25-a2d6c97c9ec35242883932161hvmdestroyrestartdestroy/usr/bin/kvm
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:
**Riferimenti:**
* [[http://www.mail-archive.com/kvm@vger.kernel.org/msg22090.html|rtl8139 and qemu-kvm-0.11.0-rc2: NFS not responding]]
* [[https://bugzilla.redhat.com/show_bug.cgi?id=517938| Cannot install KVM guests over NFS (rtl8139 emulation)]]
* [[http://www.linux-kvm.org/page/Virtio|Virtio]]
===== 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 [[wp>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.