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.

1
2
dpkg-reconfigure locales
dpkg-reconfigure tzdata

Installazione dei pacchetti base

1
2
3
4
5
6
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:

1
2
3
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:

/etc/hostname
1
nodo1.ganeti.test

nodo2:

/etc/hostname
1
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:

/etc/hosts
1
2
3
4
5
6
7
8
9
10
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.

/etc/network/interfaces
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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:

1
2
/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:

1
2
3
4
5
# 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:

/etc/lvm/lvm.conf
1
filter = ["r|/dev/cdrom|", "r|/dev/drbd[0-9]+|" ]

Installazione di ganeti

Dopo tutte le operazioni preliminari, possiamo passare all’installazione del software:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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:

1
ln -s /usr/bin/kvm-img /usr/local/bin/qemu-img

Installiamo ganeti-instance-image:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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:

1
2
3
4
5
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:

1
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:

1
2
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:

/etc/ganeti/instance-image/variants/template.conf
1
2
3
4
ARCH="x86_64"
IMAGE_NAME="template"
IMAGE_TYPE="qemu"
IMAGE_DEBUG=1

Copiamo i file appena modificati su tutti i nodi utilizzando il comando:

1
2
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:

1
gnt-os list

Installazione del template

Creiamo una nuova istanza, ed impostiamo il boot da cdrom passandogli l’iso che vogliamo utilizzare:

1
2
3
4
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:

1
2
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”:

1
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:

1
/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:

/etc/default/ganeti-instance-image
1
2
3
4
ARCH="x86_64"
IMAGE_NAME="template"
IMAGE_TYPE="qemu"
NOMOUNT="yes"

Proviamo a creare una vm:

1
2
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):

1
2
3
4
5
6
7
# 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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 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.

1
2
3
4
5
6
7
8
9
10
11
# 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:

1
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.
  • hooks - 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.

Risorse utili.