ganeti: gestore di cluster di macchine virtuali
Ganeti è un software scritto in Python, sviluppato e mantenuto da Google dal 2007, per gestire in maniera semplice e ridondata cluster di macchine virtuali.
Si basa sul concetto di ridondanza N+1, utilizzando DRBD per la replica dei dischi delle macchine virtuali.
Caratteristiche
- utilizza come hypervisor KVM o Xen (PVM e HVM)
- macchine virtuali in HA N+1
- gestione dei dischi delle vm tramite LVM (consigliato) o file disco (raw o qcow2)
- live migration (se si utilizza DRBD)
- migrazione automatica in base a diversi parametri (ram disponibile, carico del nodo, ecc)
- accesso diretto tramite VNC o virtual serial console
- media scalabilità (è consigliato un numero di nodi non superiore a 40)
Una considerazione importante da fare è che l’HA di ganeti riguarda esclusivamente lo storage.
Al momento della creazione di una macchina virtuale ridondata, bisogna specificare il nodo primario e il secondario.
Nel primario sarà avviata l’istanza della vm, nel secondario verrà fatto un backup, tramite DRBD (protocollo C), dei dischi collegati alla vm. Quindi se il nodo in cui è avviata l’istanza cade, vengono fermate tutte le vm che avevano quel nodo come primario, e bisogna far partire manualmente le vm nel nodo secondario.
Purtroppo ganeti non prevede alcuna automazione in merito. Anche se è sempre possibile affiancargli un sistema come peacemaker o heatbeat.
Un’altra caratteristica importante del progetto è che gode di una comunità abbastanza attiva, anche se a volte un po’ rigida (vedi ad esempio il supporto a DRBD protocollo A).
Questo post è composto da vari appunti che ho preso nell’arco dell’utilizzo di questo ottimo programma. Il suo scopo è descriverne, a grandi linee, il suo funzionamento. Se si vuole approfondire è necessario leggere la documentazione ufficiale.
Installazione
L’architettura che creeremo è composta da un piccolo cluster ridondato, formato da 2 nodi:
- nodo1 - sarà il nodo master dell’intero cluster
- nodo2 - un nodo normale, configurato in modo da prendere il posto del nodo master, in caso di fault di quest’ultimo.
Come sistema operativo dei vari nodi utilizzeremo Debian squeeze GNU/Linux.
Entrambi i nodi dispongono di 1 HD da 1TB, così partizionato:
- 20 GB - per l’OS dell’host (partizionato a piacimento)
- 16 GB (o più) - per lo swap dell’host e dei vari guest, tramite l’overcommitting di kvm
- 200 GB - per i template ed i backup
- il resto - LVM per i dischi delle vm
Le seguenti operazioni vanno effettuate su tutti i nodi.
Assicuriamoci di avere come locale predefinito *en_US.UTF-8*, e di utilizzare lo stesso timezone in tutti i nodi.
dpkg-reconfigure locales
dpkg-reconfigure tzdata
Installazione dei pacchetti base
apt-get install qemu-kvm drbd8-utils lvm2 ssh bridge-utils iproute iputils-arping \
python python-pyopenssl openssl \
python-pyparsing python-simplejson \
python-pyinotify python-pycurl socat \
build-essential python-paramiko \
dump kpartx
Configurazione del modulo drbd
Assicuriamoci di avere un kernel con il supporto per drbd, e disabilitiamo l’helper di default:
echo "drbd minor_count=128 usermode_helper=/bin/true" >> /etc/modules
depmod -a
modprobe drbd
Configurazione della rete
In questo post adotteremo una classica configurazione con bridge virtuali, per poter semplicemente instradare il traffico alle vm. Per una configurazione avanzata è consigliabile utilizzare delle VLAN.
Per prima cosa dobbiamo impostare tutti gli ip e gli hostname che verranno utilizzati nel nostro cluster. Ganeti per i nomi host utilizza il “fully qualified host name”, in modo da evitare la chiamata di sistema alla libreria del resolver. Questo è fondamentale, ad esempio, se si virtualizza all’interno dell’infrastruttura il/i server DNS che verranno utilizzati dalla stessa.
nodo1:
- file: /etc/hostname
nodo1.ganeti.test
nodo2:
- file: /etc/hostname
nodo2.ganeti.test
Inoltre bisogna impostare un hostname per il cluster di ganeti, in modo che se cambiamo il ruolo del nodo2, da normale a master, il sistema configurerà automaticamente un alias dell’interfaccia di rete, del nodo2, con l’ip del cluster.
Impostiamo il file hosts in entrambi i nodi:
file: /etc/hosts
127.0.0.1 localhost.localdomain localhost
10.0.0.1 cluster.ganeti.test cluster
10.0.0.11 nodo1.ganeti.test nodo1
10.0.0.12 nodo2.ganeti.test nodo2
10.0.0.101 vm1.ganeti.test vm1
10.0.0.102 vm2.ganeti.test vm2
10.0.0.250 template.ganeti.test template
Dopodiché è necessario configurare il bridge virtuale.
file: /etc/network/interfaces
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet manual
auto vbr0
iface vbr0 inet static
address 10.0.0.11
netmask 255.255.255.0
network 10.0.0.0
broadcast 10.0.0.255
bridge_ports eth0
bridge_stp off
bridge_fd 0
Stessa cosa per il nodo2, cambiando solamente l’ip.
Reinizializziamo le interfaccie e la configurazione di rete:
/etc/init.d/networking restart
/etc/init.d/hostname.sh start
Configurazione LVM
Per poter sfruttare la ridondanza sui deschi delle vm, è necessario configurare LVM:
# inizializziamo una partizione per l'utilizzo di LVM
pvcreate /dev/sdb1
# aggiungiamo la partizione ad un VG
vgcreate ganeti /dev/sdb1
Assicuriamoci di aggiungere i device drbd alla direttiva filter:
file: /etc/lvm/lvm.conf
filter = ["r|/dev/cdrom|", "r|/dev/drbd[0-9]+|" ]
Installazione di ganeti
Dopo tutte le operazioni preliminari, possiamo passare all’installazione del software:
cd /usr/local/src wget http://ganeti.googlecode.com/files/ganeti-2.4.5.tar.gz tar zxf ganeti-2.4.5.tar.gz cd ganeti-2.4.5 ./configure --localstatedir=/var --sysconfdir=/etc make && make install # assicuriamoci di creare tutte le directory necessarie mkdir -p /etc/ganeti /srv/ganeti/os /srv/ganeti/export # copiamo tutti i file *accessori* nelle giuste directory cp doc/examples/ganeti.default /etc/default/ganeti cp doc/examples/ganeti.initd /etc/init.d/ganeti cp doc/examples/ganeti-kvm-poweroff.initd /etc/init.d/ganeti-kvm-poweroff cp doc/examples/ganeti.cron /etc/cron.d/ganeti cp doc/examples/gnt-config-backup /etc/cron.daily/ cp doc/examples/bash_completion /etc/bash_completion.d/ganeti chmod +x /etc/init.d/ganeti /etc/init.d/ganeti-kvm-poweroff /etc/cron.daily/gnt-config-backup # attiviamo gli script di init update-rc.d ganeti defaults 20 80 update-rc.d ganeti-kvm-poweroff defaults 20 70
Per fare il deployment delle vm, ganeti mette a disposizione un tool esterno (ganeti-instance-debootstrap), basato su debootstrap, che permette di installare vm con un sistema debian minimale, per poi clonarlo per la varie vm.
Noi invece utilizzeremo un tool diverso, ganeti-instance-image, che ci permette di lavorare più facilmente con le vm, indipendentemente dall’OS utilizzato.
Questo tool utilizza il programma qemu-img per lavorare con le immagini delle vm, visto che in Debian il pacchetto kvm installa il programma con il nome kvm-img, è sufficiente creare un alias per risolvere il problema:
ln -s /usr/bin/kvm-img /usr/local/bin/qemu-img
Installiamo ganeti-instance-image:
cd /usr/local/src wget http://code.osuosl.org/attachments/download/2163/ganeti-instance-image-0.5.1.tar.gz tar zxf ganeti-instance-image-0.5.1.tar.gz cd ganeti-instance-image-0.5.1/ ./configure --prefix=/usr --localstatedir=/var \ --sysconfdir=/etc \ --with-os-dir=/srv/ganeti/os make && make install # copiamo il file della configurazione predefinita cp defaults /etc/default/ganeti-instance-image # creiamo un link su /usr/share per evitare qualche # script con scolpito il path sbagliato ln -s /srv/ganeti /usr/share/ganeti
Configurazione
Ganeti utilizza diversi comandi per gestire i vari aspetti dell’architettura. I più importanti sono:
- gnt-cluster - per gestire il cluster ganeti
- gnt-node - per gestire i nodi
- gnt-instance - per gestire le instanze delle vm
- gnt-backup - per importare ed esportare la vm (dati e configurazione)
- gnt-os - per gestire i tool esterni che si occupano del deploy dell vm
Iniziamo a configurare il cluster.
Ganeti permette di avere un solo nodo con privilegi di cluster manager, in grado di gestire tutti gli aspetti dell’architettura, ed N nodi come suoi “backup”.
Scegliamo il nodo1 come cluster master ed inizializziamo il cluster:
gnt-cluster init --vg-name ganeti --master-netdev eth0 --nic-parameters link=vbr0 \
--enabled-hypervisors=kvm --maintain-node-health yes \
--hypervisor-parameters kvm:vnc_bind_address=0.0.0.0,kernel_path=,initrd_path= \
--backend-parameters vcpus=2,memory=512M \
cluster.ganeti.test
Analizziamo i vari parametri:
- vg-name ganeti : impostiamo il VG da utilizzare, quello predefinito è “xenvg”.
- master-netdev eth0 : l’interfaccia sulla quale attivare l’ip per l’host cluster.ganeti.test (tramite alias). Ogni nodo impostato come “slave” dovrà utilizzare l’interfaccia, con quel nome, in modo da poterlo utilizzare in caso di failover del nodo master.
- nic-parameters link=vbr0 : impostiamo il tipo (bridge, in modo predefinito) ed il nome dell’interfaccia del nodo.
- enabled-hypervisors kvm : utilizziamo solamente kvm come hypervisor.
- maintain-node-health yes : abilitiamo la manutenzione automatica, ad esempio alla disattivazione di un link drbd viene automaticamente spenta l’istanza associata.
- hypervisor-parameters … : impostiamo i valori predefiniti dell’hypervisor. Disabilitiamo il path del kernel e dell’initrd, in modo da caricare il kernel dalla vm e non dall’hypervisor.
- backend-parameters … : impostiamo i valori predefiniti per le vm.
- cluster.ganeti.test : hostname riservato al nodo master del cluster.
Adesso dovremmo avere i processi ganeti-noded, ganeti-masterd, ganeti-confd e ganeti-rapi attivi.
Aggiungiamo il nodo2 al cluster, specificando che potrà prendere il posto del nodo master:
gnt-node add --master-capable=yes zeniba2.libreit.org
Controlliamo che tutto sia andato liscio e che ganeti abbia configurato correttamente il device eth0:0 sul nodo1 con:
gnt-cluster verify
ifconfig eth0:0
Creazione di una vm come template
Se non abbiamo in precedenza realizzato un template della vm, con virtualbox, vagrant o qualsiasi altro sistema, possiamo farlo direttamente da ganeti.
Utilizziamo il tool ganeti-instance-image per creare la vm che useremo come template. Modifichiamo il file /etc/ganeti/instance-image/variants.list aggiungendo la voce “template” e creiamo il file template.conf:
file: /etc/ganeti/instance-image/variants/template.conf
ARCH="x86_64"
IMAGE_NAME="template"
IMAGE_TYPE="qemu"
IMAGE_DEBUG=1
Copiamo i file appena modificati su tutti i nodi utilizzando il comando:
gnt-cluster copyfile /etc/ganeti/instance-image/variants.list
gnt-cluster copyfile /etc/ganeti/instance-image/variants/template.conf
Assicuriamoci di aver aggiunto in modo corretto la nostra configurazione dell’os:
gnt-os list
Installazione del template
Creiamo una nuova istanza, ed impostiamo il boot da cdrom passandogli l’iso che vogliamo utilizzare:
gnt-instance add -t plain -n nodo1.ganeti.test -o image+template --no-install \
--disk 0:size=5G --net 0:ip=10.0.0.250
-H kvm:boot_order="cdrom",cdrom_image_path="/isos/debian-6.0.3-amd64-netinst.iso" \
template.ganeti.test
I vari parametri sono abbastanza autoesplicativi, quelli più importanti sono:
- -t indica il tipo di backend utilizzato per il disco della vm, con “plain” utilizziamo un volume LVM non replicato. Altre opzioni sono “drbd” (LVM replicato), “file” e “diskless”.
- -o indica la il tool per il deploy della vm da utilizzare, con la relativa configurazione separata da “+”.
- -n indica il nodo in cui verrà eseguita l’instanza e creato il disco (se è una vm ridondata vanno inseriti 2 host, separati da “:“).
- –no-install serve per non far partire il deploy automativo di ganeti-instance-image. Anziché usare questo parametro avremmo potuto aggiungere la direttiva CDINSTALL nel file template.conf.
Avviamo la vm e vediamo le informazioni relative all’istanza:
gnt-instance start template.ganeti.test
gnt-instance info template.ganeti.test
Colleghiamoci al guest tramite VNC alla porta riportata dal comando gnt-instance info, alla voce “Allocated network port”:
vncviewer cluster.ganeti.test:11001
Installiamo regolarmente il guest, non impostando la partizione di swap.
Una volta che il nostro template è pronto possiamo creare l’immgine:
/srv/ganeti/os/image/tools/make-qemu-img template.ganeti.test
Utilizziamo il formato qcow2 e non dump, per il salvataggio dell’immagine, perché è più semplice da trattare (è come se usassimo un dispositivo raw) e non ci limita nel partizionamento della vm. Con questo formato, però, il deploy delle vm diventa sensibilmente più lento e soprattutto poco personalizzabile (ip, hostname, ecc). Se si vogliono utilizzare altri formati (dump, tar) si consulti la documentazione.
Adesso che abbiamo l’immagine possiamo creare le nostre macchine virtuali.
deploy delle virtual machine
Modifichiamo il file di configurazione predefinito di ganeti-instance-image:
file: /etc/default/ganeti-instance-image
ARCH="x86_64"
IMAGE_NAME="template"
IMAGE_TYPE="qemu"
NOMOUNT="yes"
Proviamo a creare una vm:
gnt-instance add -t drbd -n node1.ganeti.test:node2.ganeti.test -o image+default \
--disk 0:size=5G --net 0:ip=10.0.0.101 vm1.ganeti.test
Se tutto è andato bene adesso possiamo avviare dei test più approfonditi includendo anche lo storage ridondato (drbd):
# rimuoviamo la vm di prova
gnt-instance remove vm1.ganeti.test
# avviamo il test utilizzando un tool incluso con ganeti
/usr/local/lib/ganeti/tools/burnin -v -o image+default -t drbd \
-n node1.ganeti.test:node2.ganeti.test --disk-size=5G \
vm{1,2}.ganeti.test
Importare macchine virtuali
Ganeti ci permette di importare facilmente vm provenienti da altri ambienti. L’importante è che abbiamo i dischi salvati in un formato supportato da qemu-img.
Come esempio, importiamo una vm windows con 16 GB di disco, nella nostra bella architettura con storage ridondato:
# creiamo la configurazione per la vm, senza far partire il deploy
# ed utilizzando il nodo2 come primario
gnt-instance add -t drbd -n node2.ganeti.test:node1.ganeti.test -o image+default \
--no-install --no-start --disk 0:size=16G --net 0:ip=10.0.0.102 \
vm2.ganeti.test
# recuperiamo l'id del disco associato alla vm, nella voce "Disks" -> "on primary"
gnt-instance info vm2.ganeti.test
# copiamo l'immagine del disco nel dispositivo ridondato
kvm-img convert -f qcow2 -O host_device /tmp/winzoz-x86_64.img \
/dev/ganeti/9259bb19-f0ed-4c1a-9d0e-864477605e39.disk0
# se nel sistema operativo non sono installati i driver virtio
# sarà necessario riconfigurare l'istanza per utilizzare i driver ide
gnt-instance modify -H disk_type=ide -B memory=2048 w.libreit.org
# avviamo l'istanza
gnt-instance start vm2.ganeti.test
Tuning
Per migliorare le prestazioni delle vm, è possibile istruire kvm ad utilizzare la cpu dell’host così com’è, senza emularne caratteristiche aggiuntive.
# informiamo APT che stiamo rinominando il binario di kvm
dpkg-divert --add --rename --divert /usr/bin/kvm.real /usr/bin/kvm
# creiamo un wrapper
cat <<EOF > /usr/bin/kvm
#!/bin/sh
/usr/bin/kvm.real -cpu host "$@"
EOF
# e lo rendiamo eseguibile
chmod +x /usr/bin/kvm
Un ulteriore miglioramento, di circa il 6%, si ottiene semplicemente disabilitando la console VNC:
gnt-instance modify -H vnc_bind_address= vm{1,2}.ganeti.test
Altre caratteristiche
Ganeti offre molte altre caratteristiche non descritte in questo post, le più importanti, a mio avviso, sono:
- gnt-backup - permette di effettuare i backup dei dischi e della configurazione associata ad una vm. Una limitazione di questo tool è che mantiene solo 1 backup per vm.
-
- comodo sistema per eseguire tool esterni in base ai vari stati del
cluster, nodo, vm.
gnt-instance console vm - abilitando nel guest una console fisica (solitamente nel file /etc/inittab), è possibile utilizzarla al posto della, spesso scomoda, console VNC.
Conclusione
Ganeti rimane uno dei pochi gestori di macchine virtuali a non adottare i paradigmi del cloud computing.
Nei prossimi post cercheremo di trattare anche quelli.