This is an old revision of the document!


Laborator 8. Virtualizare nativă

Cunoștințe și abilități ce vor fi dobândite

  • Prezentarea unei soluții de virtualizare nativă: KVM
  • Administrarea mașinilor virtuale ce rulează folosind un hypervisor KVM
  • Multiplicarea mașinilor virtuale folosind paradigma copy-on-write (cow)
  • Modalități de interconectarea a mașinilor virtuale
  • Soluții de administrarea centralizată a mașinilor virtuale

Pregătire infrastructură de laborator

  • Pentru a pregăti configurația de laborator, pe mașina fizică folosiți comenzile următoare din contul utilizatorului root (puteți da copy/paste la comenzi în terminal):
    root@saisp:~# wget http://elf.cs.pub.ro/saisp/res/lab08.zip
    root@saisp:~# unzip lab08.zip

Exerciții

01. [15p] Kernel-based Virtual Machine (KVM)

Virtualizarea este folosită pe scară largă în centrele de date întrucât oferă flexibilitate foarte mare în managementul resurselor. Pentru a nu afecta perfomanța, producătorii de procesoare au introdus facilități de virtualizare pentru a permite sistemelor de operare să ruleze nemodificate. Entitatea software care folosește aceste facilități se numește hypervisor. KVM este un hypervisor ce oferă suport pentru virtualizarea nativă (implementează facilități de virtualizare). În continuare vom prezenta modul de lucru cu soluția implementată de KVM.

Trebuie să verificăm dacă hardware-ul are suport pentru virtualizare nativă (mai poartă denumirea și de extensie de virtualizare). Numele extensiilor de virtualizare diferă de la un producător la altul astfel:

  • INTEL - vmx (Virtual Machine eXtensions)
  • AMD - svm (Secure Virtual Machine)

Pentru a verifica prezența extensiilor de mai sus trebuie să ne uităm în /proc/cpuinfo dacă câmpul Flags conține numele extensiei (vmx pentru Intel sau svm pentru AMD):

root@saisp:~$ cat /proc/cpuinfo |grep vmx
flags           : ... ds_cpl **vmx** smx...

Pentru a folosi KVM trebuie să instalăm pachetul qemu-kvm, qemu fiind utilitarul din userspace ce porneste mașinile virtuale și transmite parametri doriți hypervisorului:

root@saisp:~# apt-get install qemu-kvm
[...]

Înainte de a porni o mașina virtuală bazată pe KVM, trebuie să verificăm dacă modulul de kernel este încărcat:

root@saisp:~# lsmod|grep kvm
kvm_intel             121968  0
kvm                   287572  1 kvm_intel

Observați în acest caz folosirea unei arhitecturi Intel. Pentru fiecare arhitectură există un modul separat. Încărcarea modului de kernel atrage după sine crearea unui device /dev/kvm prin care se controlează modulul de kernel folosind operații de tip ioctl:

root@saisp:~# ls -l /dev/kvm
crw-rw---T 1 root kvm 10, 232 Jan  5 21:34 /dev/kvm

Pentru a porni o mașină virtuală vom folosi comanda kvm. Utilizatorul care execută comanda (dorește să pornească o mașină virtuală) trebuie să fie cel privilegiat (root) sau să facă parte din grupul setat ca owner pe device-ul /dev/kvm (în cazul de fată kvm). În cadrul laboratorului vom lucra cu utilizatorul privilegiat, dacă nu se specifică altfel.

Vom crea o mașină virtuală având 256MB RAM (parametrul -m), 2 procesoare (numărul este dat de parametrul -smp) și va avea ca dispozitiv de stocare o imagine virtuală denumită base.qcow2 (mai multe detalii în exercițiul următor), specificată cu parametrul -hda:

root@saisp:~# kvm -hda base.qcow2 -m 256 -smp 2

În acest moment se va deschide o fereastră în care se va afișa output-ul consolei mașinii virtuale (veți vedea cum bootează). Verificați că resursele mașinii virtuale coincid cu parametri trimiși comenzii kvm inspectând sistemul de fișiere /proc.

Deschidem o nouă consolă și vom afișa numărul de thread-uri kvm prezente în sistem:

root@saisp:~# ps -eLf |grep kvm

Opriți rularea mașinii virtuale rulând Ctrl+c în consola unde ați rulat comanda kvm. Porniți-o din nou cu 4 procesoare și 512MB RAM.

Deschidem o nouă consolă și vom afișa numărul de thread-uri kvm prezente în sistem:

root@saisp:~# ps -eLf |grep kvm

Observați că fiecare nou procesor adăugat în mașina virtuală crește numărul thread-urilor kvm în sistemul gazdă (numărul de thread-uri este mai mare decât numărul de procesoare din cauza existenței unor thread-uri de management necesare procesului kvm).

Exportare display prin VNC

De cele mai multe ori nu dorim deschiderea unei console în sesiunea curentă ci dorim rularea mașinii în background, iar la nevoie să putem accesa consola acesteia. Acest lucru este posibil folosind parametrul -vnc al comenzii kvm care va porni un server de VNC prin care se va exporta consola mașinii virtuale:

root@saisp:~# kvm -hda base.qcow2 -m 512 -smp 4 -vnc :1

Observați în continuare că procesul kvm nu a intrat în background. Pentru acest lucru trebuie să mai adăugăm parametroul -daemonize:

root@saisp:~# kvm -hda base.qcow2 -m 512 -smp 4 -vnc :1 -daemonize

Parametrul -vnc :1 activează serverul VNC pe portul 1 al protocolului. Pentru a afla portul TCP pe care ascultă serverul de VNC prin care este exportată consola trebuie să adunați 5900 la numărul pe care l-ați pus parametrului -vnc, în cazul nostru 5901. Pentru a verifica acest lucru executați comanda netstat:

root@saisp:~# netstat -ntpl

În acest moment mașina virtuală KVM rulează în background, singura modalitate de interacțiune cu aceasta fiind prin consola VNC. Ne vom conecta la portul 5901 folosind utilitarul vncviewer (instalați-l dacă este cazul folosind apt-get install xtightvncviewer):

root@saisp:~# vncviewer localhost:5901

Închideți mașina virtuală executând comanda poweroff în consola acesteia. Porniți-o din nou având 256MB RAM și 2 procesoare, tot în background (-daemonize). Găsiți o modalitate de a opri mașina virtuală executând o comanda pe mașina fizică (cea pe care lucrați voi).

02. [10p] Copy-on-write virtual storage

La punctul anterior am pornit o mașină virtuală ce avea o imagine a disk-ului deja construită. Ați observat extensia specifică a imaginii .qcow2 (QEMU Copy-on-write). Acest tip de imagine virtuală ne permite să multiplicăm o mașină virtuală folosind o imagine de bază read-only. Pentru fiecare mașină virtuală pornită se va crea un fișier doar cu modificările aduse de aceasta imaginii de bază. Mai multe despre multiplicare vom vedea în următoarele exerciții

În continuare vom crea o imagine .qcow pe care vom porni instalarea unui sistem de operare. Utilitarul cu ajutorul căruia se crează astfel de imagini este qemu-img (dacă nu există, instalați-l folosind comanda apt-get install qemu-utils):

root@saisp:~# qemu-img create -f qcow2 virtualdisk.qcow2 1G
Formatting 'virtualdisk.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 

Se observă că utilitarul qemu-img primește ca prim parametru o comandă (create). Pentru comanda create am specificat tipul dorit de imagine (qcow2), numele disk-ului virtual și dimensiunea maximă a acestuia (1G).

Dorim să instalăm un sistem de operare folosind un CD de instalare (fomat .iso). Comanda kvm ne permite să adăugăm un nou dispozitiv de tip cdrom în care să fie încărcată. Folosiți imaginea CD-ului Debian din arhiva descărcată (fișierul debian-7.3.0-amd64-netinst.iso) și porniți o mașină virtuală cu disk-ul virtual creat anterior și un dispozitiv de tip cdrom:

root@saisp:~# kvm -hda virtualdisk.qcow2 -cdrom debian-7.3.0-amd64-netinst.iso -m 256 -smp 2

Mașina virtuala va porni de pe CD întrucât nu va găsi nici un bootloader pe disk-ul virtual. Porniți instalarea sistemului de operare folosind pașii impliciți. Din acest punct instalarea decurge ca în cazul unui sistem fizic obișnuit.

O dată începută instalarea, închideți mașina virtuală folosind una din metodele găsite/prezentate anterior și ștergeți imaginea nou creată.

03. [10p] Adăugare resurse la o mașină virtuală KVM

O configurație uzuală a unei mașini virtuale este formată de obicei dintr-un disk virtual principal de dimensiuni reduse unde este instalat sistemul de operare și un disk virtual secundar unde se stochează datele efective.

Creați un nou disk virtual în format qcow2 de dimensiune 1G pe care să îl atașați unei mașini virtuale ce are ca disk principal base.qcow2 (unde se află sistemul de operare). Mașina virtuală va avea 256MB RAM și 2 procesoare. Hint: -hdb.

Observați că dimensiunea fișierului qcow2 este foarte mică acesta extinzându-se pe măsură ce se vor scrie date:

root@saisp:~# ls -hl nume_fisier.qcow2

După ce ați pornit mașina virtuală, verificați existența disk-ului secundar adăugat folosind comanda ls /dev/sdb. Creați 2 partiții de câte 500MB fiecare și formatațile folosind sistemul de fișiere ext4. Montați partițiile noi create și scrieți câte un fișier de 100MB pe acestea.

Verificați dimensiunea imaginii create și observați că a crescut.

Închideți mașina virtuală și stergeți imaginea creată.

04. [10p] Multiplicare mașini virtuale folosind o singură image de bază

Folosind imaginea base.qcow2 dorim să pornim două mașini virtuale fără a crea două copii ale acesteia. Pentru acest lucru putem folosi conceptul copy-on-write specific acestui de tip de imagini (qcow2).

Pentru a crea o nouă imagine ce reține doar diferențele față de imaginea de bază folosim comanda create a utilitarului qemu-img cu parametrul -b care va specifica baza de la care va porni noua imagine:

root@saisp:~# qemu-img create -f qcow2 -b base.qcow2 sda-vm1.qcow2
Formatting 'sda-vm1.qcow2', fmt=qcow2 size=2147483648 backing_file='base.qcow2' encryption=off cluster_size=65536
root@saisp:~# ls -lh sda*
-rw-r--r-- 1 root root 1.4G Jan 29 19:01 base.qcow2
-rw-r--r-- 1 root root 193K Jan 29 19:01 sda-vm1.qcow2

Afișați dimensiunea ambelor imagini.

Porniți o nouă mașină virtuală folosind imaginea sda-vm1.qcow2.

Creați un fișier pe 100 MB în mașina virtuală. Afișați dimensiunea imaginilor (base.qcow2 și sda-vm1.qcow2) și observați faptul că base.qcow2 a rămas constant , iar sda-vm1.qcow2 a crescut).

Închideți mașina virtuală și ștergeți imaginea creată (sda-vm1.qcow2).

05. [10p] Conversie disk virtual între diferite formate

O altă comandă des folosită a utilitarului qemu-img este convert. Avem la dispozitie o imagine in format .qcow2 și dorim obținerea unei imagini în formatul .vmdk (format specific mașinilor virtuale VMware) sau .vdi (format specific mașinilor virtuale VirtualBox), fără a fi nevoiți să reinstalăm sistemul de operare pe o nouă imagine:

root@saisp:~# qemu-img convert -O vdi base.qcow2 base.vdi

Parametrul -O specifică formatul imaginii obținute (vdi). Observați că nu a fost necesară specificarea formatului imaginii de intrare (-f), qemu-img fiind capabil să detecteze acest lucru.

Creați o nouă mașină virtuală folosind VirtualBox și configurați folosirea disk-ului obținut anterior.

06. [15p] Interconectare mașini virtuale

Creați 2 imagini de disk pornind de la imaginea de baza base.qcow2 cu numele sda-vm1.qcow2 și sda-vm2.qcow2.

Până în acest moment am creat mașini virtuale fără nici o legătură către Internet. Dorim să asigurăm accesul la Internet pentru acestea. Pentru acest lucru trebuie să adăugăm la crearea mașinii virtuale o interfață de rețea cu ajutorul parametrului '-net':

root@saisp:~# kvm -hda sda-vm1.qcow2 -m 256 -smp 2 -net nic,model=e1000,macaddr=00:11:22:33:44:55 -net tap,ifname=tap-vm1

Obligatoriu trebuie să porniți mașina virtuală ca utilizator privilegiat pentru a putea să fie create interfețele de tip tap.

Ignorați warning-ul referitor la tap.

Cu ajutorul primei opțiuni -net nic specificăm proprietățile interfeței din mașina virtuală (în cazul de față se dorește emularea unei interfațe Intel e1000 cu adresa MAC 00:11:22:33:44:55).

Toate opțiunile adăugate nu sunt obligatorii (dacă nu se specifică se folosesc valori implicite). A doua opțiune -net tap specifică tipul interfeței virtuale din mașina fizică ce are corespondență 1 la 1 cu interfața din mașina virtuală (tot traficul trimis pe interfața eth0 de pe masina virtuala ajunge pe interfața tap-vm1 în mașina fizică). De asemenea toți parametri sunt opționali.

Porniți o a doua mașină virtuală folosind imaginea sda-vm2.qcow2 și adăugați-i o interfață de rețea cu adresa MAC AA:11:22:33:44:55 ce are corespondență în mașina fizică o interfață de tip tap cu numele tap-vm2.

root@saisp:~# kvm -hda sda-vm2.qcow2 -m 256 -smp 2 -net nic,model=e1000,macaddr=AA:11:22:33:44:55 -net tap,ifname=tap-vm2

Modificați hostname-urile mașinilor la VM1, respectiv VM2:

root@VM:~# hostname VM1
root@VM:~# su -
root@VM1:~# 
 
root@VM:~# hostname VM2
root@VM:~# su -
root@VM2:~# 

Logați-vă din nou ca root pentru a se modifica prompt-ul.

În acest moment am creat 2 legături virtuale între instanțele KVM și mașina fizică. În mod uzual se dorește ca mașinile virtuale și mașina fizică să aparțină aceleiași rețele. Pentru acest lucru avem nevoie de un switch virtual în care să conectăm legăturile create anterior (tap-vm1 și tap-vm2) împreună cu mașina fizică. Switch-ul virtual poate fi emulat folosind conceptul de bridge din kernelul de Linux.

Vom crea bridge-ul/switch-ul virtual denumit brX, unde X va fi 0 (br urmat de un index):

root@saisp:~# brctl addbr br0
root@saisp:~# ip link set dev br0 up

Întotdeauna, nu uitați să ridicați nivelul 2 al bridge-ului

Vom conecta cele două interfețe virtuale tap-vm1 și tap-vm2 in bridge:

root@saisp:~# brctl addif br0 tap-vm1
root@saisp:~# brctl addif br0 tap-vm2

Configurați pe interfața br0 adresa IP 192.168.1.1/24, iar pe mașinile virtuale adresele IP 192.168.1.2/24, respectiv 192.168.1.3/24. Verificați conectivitatea între cele 3 adrese IP folosind comanda ping.

În acest moment avem conectivitate între toate cele host-uri (saisp, VM1, VM2). Pentru a asigura conectivitatea la Internet trebuie să activăm rutarea și translatarea de adrese (NAT) pe mașina fizică:

root@saisp:~# echo 1 > /proc/sys/net/ipv4/ip_forward
root@saisp:~# iptables -t nat -A POSTROUTING -o ethX -j MASQUERADE

unde ethX este placa de retea de pe masina fizica.

Ne mai rămâne să configurăm ruta implicită și serverul de DNS pe mașinile virtuale. Conectați-vă folosind SSH la mașinile virtuale și adăugați ca rută implicită adresa 192.168.1.1 (mașina fizică) și ca server de DNS 8.8.8.8. Verificați cu ajutorul comenzii ping că site-ul www.google.ro răspunde la cereri.

Scoatem interfețele tap-vm1 și tap-vm2 din bridge, după care îl ștergem pe acesta:

root@saisp:~# brctl delif br0 tap-vm1
root@saisp:~# brctl delif br0 tap-vm2
root@saisp:~# ip link set dev br0 down
root@saisp:~# brctl delbr br0

Închideți mașinile virtuale și ștergeți imaginile create (sda-vm1.qcow2 și sda-vm2.qcow2).

07. [10p] Conectarea mașinilor virtuale la rețeaua publică

Un scenariu uzual este reprezentat de cazul în care pe mașinile virtuale se activează diverse servicii publice (exemplu: WEB). În acest caz nu este suficient să activăm translatarea de adrese pe mașina fizică, ci trebuie să conectăm mașina virtuală direct la rețeaua publică.

Porniți o nouă mașină virtuală KVM având o interfață de rețea cu adresa MAC 00:11:22:33:44:XX, unde XX reprezintă numărul vostru din catalogul de SAISP.

Pe mașina fizică, creați un nou bridge br1 în care adăugați interfața tap-vm și interfața eth0. Pe mașina virtuală executați comanda dhclient eth0. Observați adresa IP obținută direct din rețeaua facultății.

Pentru a avea în continuare acces la Internet pe mașina fizică executați comenzile ip addr flush dev eth0 (șterge adresa IP de pe interfață) și dhclient br1 întrucât interfața principală este acum conectată în bridge la nivel 2 și nu mai poate oferi și servicii de nivel 3 (IP).

Intrebați pe unul din colegi adresa IP obținută pe mașina virtuală și conectați-vă la aceasta prin SSH. Observați că practic vă puteți conecta la orice mașină virtuală a oricărui coleg.

Eliminați din bridge interfațele tap-vm și eth0, ștergeți bridge-ul br1, executați comanda dhclient eth0 și închideți mașina virtuală:

root@saisp:~# brctl delif br1 tap-vm
root@saisp:~# brctl delif br1 eth0
root@saisp:~# ip link set dev br1 down
root@saisp:~# brctl delbr br1
root@saisp:~# dhclient eth0

08. [15p] Managementul mașinilor virtuale KVM folosind virsh

Pentru a ușura managementul mașinilor virtuale a fost dezvoltată o bibliotecă de interacțiune cu acestea ce poartă denumirea de libvirt. Această bibliotecă oferă o interfață de programare comună pentru mai multe tehnologii (e.g.: KVM, LXC) fiind folosită de majoritatea tehnologiilor open-source de Cloud (e.g.: OpenStack, oVirt).

Pentru administratorii de rețea a fost dezvoltată o consolă numită virsh ce folosește interfața oferită de libvirt pentru interacțiunea cu mașinile virtuale.

Pentru a putea folosi facilitățile oferite de libvirt trebuie să instalăm pachetele libvirt-bin, virtinst, virt-viewer și virt-top. De asemenea dacă utilizatorul e diferit de cel privilegiat trebuie adăugat în grupul libvirtd (ca si la kvm). În exemplul următor vom folosi utilizatorul privilegiat root.

În primul pas trebuie să activăm serviciul de networking al libvirt:

root@saisp:~# virsh -c qemu:///system net-start default

Pentru a crea o mașină virtuală folosim utilitarul virt-install:

root@saisp:~# virt-install --connect qemu:///system --name VM1 --hvm --ram 256 --disk path=base.qcow2,format=qcow2 --network network=default --vnc --import

Semnificația parametrilor este după cum urmează:

   * ''--connect qemu:///system''  - conectarea la sistemul local
   * ''--name VM1'' - numele mașinii virtuale
   * ''--hvm'' - să se folosească virtualizarea hardware (altfel se face emulare folosind QEMU, fără KVM)
   * ''--ram 256'' - cantitatea de memorie
   * ''--disk path=base.qcow2,format=qcow2'' - discul folosit și formatul acestuia
   * ''--network network=default'' - adăugare interfață de rețea cu proprietățile implicite
   * ''--vnc'' - să export consola VNC
   * ''--import'' - să folosească imaginea deja creată ''base.qcow2'', să NU creeze alta

În acest moment s-a creat un fișier de configurație XML al mașinii virtuale care poate fi vizualizat în /etc/libvirt/qemu/VM1.xml.

Consola mașinii virtuale s-a deschis, programul virt-inst rămânând să ruleze. Folositi CTRL+C pentru a incheia instalarea masinii virtuale.

Pentru a controla mașina virtuală vom folosi consola virsh. Ne conectăm la daemon-ul local cu ajutorul lui virsh și vom afișa mașinile virtuale existente folosind comanda list:

root@saisp:~# virsh --connect qemu:///system
[...]
virsh> list
 Id Name                 State
----------------------------------
  2 VM1                  running

Observați starea mașinii virtuale și Id-ul acesteia (2). Pe baza Id-ului veți realiza toate operațiile.

Dorim să aflăm portul VNC al mașinii virtuale cu ajutorul comenzii vncdisplay urmat de Id-ul mașinii virtuale:

virsh # vncdisplay 2
:0

Deschideți o nouă consolă și conectați-vă la aceasta prin VNC folosind utilitarul vncviewer:

root@saisp:~# vncviewer :0

Inchideți consola. ATENTIE: Mașina virtuala va continua să ruleze în background!

Opriți mașina virtuală cu ajutorul comenzii shutdown urmată de Id-ul acesteia:

virsh # shutdown 2
Domain 2 is being shutdown
 
virsh # list
 Id Name                 State
----------------------------------
  2 VM1                  running
 
virsh # list
 Id Name                 State
----------------------------------

Pentru a afișa toate mașinile virtuale indiferent de starea lor folosiți opțiunea –all a comenzii list:

virsh # list --all
 Id Name                 State
----------------------------------
  - VM1                  shut off

Vom porni mașina virtuală VM1 folosind comanda start urmată de numele mașinii:

virsh # start VM1
Domain VM1 started
 
virsh # list
 Id Name                 State
----------------------------------
  3 VM1                  running

Observați că Id-urile se alocă la pornirea mașinilor virtuale.

Executați comanda destroy pe Id-ul mașinii virtuale. Observați că mașina virtuală s-a închis, NU s-a șters.

virsh # destroy 3
Domain 3 destroyed
virsh # list --all
 Id Name                 State
----------------------------------
  - VM1                  shut off

În echipe de câte doi, faceți schimb de adrese IP și asigurați accesul SSH fără parolă între calculatoarele voastre, folosind utilizatorul privilegiat root.

Conectați-vă cu virsh la calculatorului colegului și listați mașinile virtuale disponibile. La adresa de conectare folosiți parametrul:

qemu+ssh://$ADRESA_IP_COLEG/system

Porniți mașina creată de el și conectați-vă prin VNC la aceasta. Acesta este unul dintre cele mai utilizate cazuri în care aveți un server cu suport de virtualizare și doriți să rulați de la distanță mai multe mașini virtuale.

Ștergeți mașina virtuală definită folosind comanda undefine urmată de numele mașinii virtuale:

virsh # undefine VM1
Domain VM1 has been undefined
virsh # list
 Id Name                 State
----------------------------------
  6 VM1                  running

Observați că mașina virtuală încă mai rulează. Ea va dispare complet după ce o închidem:

virsh # shutdown 6
Domain 6 is being shutdown
virsh # list --all
 Id Name                 State
----------------------------------

09. [5p] Rularea mașinilor virtuale de către un utilizator neprivilegiat

Creați un nou grup în sistem kvm-users și un utilizator ce aparține acestui grup. Configurați sistemul astfel încât utilizatorii din grupul kvm-users să poate rula mașini virtuale KVM. (Hint: 01. [15p] Kernel-based Virtual Machine (KVM))

10. [BONUS - 10p] Migrarea mașinilor virtuale între noduri

În echipe de câte doi, dorim să realizăm migrarea unei mașini virtuale (live migration) de pe o mașină fizică pe alta. Unul dintre voi va fi sursa, iar celălalt destinația.

Pe calculatorul sursă creați directorul /vm și exportați-l prin NFS. Pe calculatorul destinație montați directorul exportat tot în /vm și asigurați-vă că îl puteți accesa.

Pe calculatorul sursă copiați imaginea base.qcow2 în directorul /vm și porniți o mașină virtuală KVM în background (-daemonize), având o consolă VNC. Realizați migrarea acesteia către destinație urmărind tutorialul de aici.

saisp/labs/08.1391031987.txt.gz · Last modified: 2014/01/29 23:46 by mihai.carabas
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0