Backup su nastro delle macchine virtuali di VMware Server
Parto con una premessa: sebbene una copia (o tar) "semplice" con la macchina virtuale in esecuzione funzioni, non è una strada che voglio seguire perché poi, nel momento del bisogno, i file che servono sono sistematicamente inconsistenti o sono stati copiati mentre il sistema li teneva aperti. Quindi un backup inutile.
A mio avviso il backup delle macchine virtuali, con VMware Server s'intende, deve avvenire con le stesse spente o sospese, senza però avere downtime lunghi tutta la notte.
La soluzione su cui ho lavorato consiste nel sospendere una ad una le macchine virtuali, farne una copia in un filesystem temporaneo, ripristinare lo stato ed eseguire il backup a partire dalla copia. Alla fine di tutto mi piace ricevere un'e-mail con l'esito dell'operazione.
La macchina di test è, come sempre, il server dell'ufficio a cui ho aggiunto:
Dopo qualche test non resta che aggiungere lo script al cron:
Ottenuto il contenuto del backup, il ripristino è davvero semplice:
A mio avviso il backup delle macchine virtuali, con VMware Server s'intende, deve avvenire con le stesse spente o sospese, senza però avere downtime lunghi tutta la notte.
La soluzione su cui ho lavorato consiste nel sospendere una ad una le macchine virtuali, farne una copia in un filesystem temporaneo, ripristinare lo stato ed eseguire il backup a partire dalla copia. Alla fine di tutto mi piace ricevere un'e-mail con l'esito dell'operazione.
La macchina di test è, come sempre, il server dell'ufficio a cui ho aggiunto:
- controller SCSI Adaptec
- DDS-4
- HD 250 GB SATA
sendmail.expect
Per quanto riguarda l'invio dell'e-mail da script ho preferito evitare di installare software quali mailx che richiedono alla base un sendmail o exim che sia. Telnet è più che sufficiente, comandato da expect:apt-get install telnet expect cd ~ touch sendmail.expect chmod +x sendmail.expectAll'interno di
sendmail.expect lo script per l'inivo dell'e-mail:
#!/usr/bin/expect
spawn telnet [lindex $argv 0] [lindex $argv 1]
expect "220"
send "HELO localhost.localdomain\n"
expect "250"
send "MAIL FROM: backup@localhost.localdomain\n"
expect "250"
send "RCPT TO: [lindex $argv 2]\n"
expect "250"
send "DATA\n"
expect "354"
send "From: \"Backup\" <backup@localhost.localdomain>\n"
send "To: \"Backup Operators\" <[lindex $argv 2]>\n"
send "Subject: Rapporto di Backup\n"
set fhandle [open [lindex $argv 3] r]
while {[gets $fhandle inline] >= 0} {
send "> $inline\n"
}
close $fhandle
send ".\n"
expect "250"
send "QUIT\n"
La sintassi:
./sendmail.expect [SMTPHOST] [SMTPPORT] [RECIPIENT] [FILE]Legge il contenuto di
[FILE] e lo invia a [RECIPIENT] utilizzando host e porta del server SMTP specificato.
~/.vmbackup
Soprattutto nel mio server ho delle macchine virtuali di test, o copie, di cui non voglio eseguirne il backup. Voglio poter decidere liberamente e senza alcun vincolo che cosa salvare. Per questo ho deciso di appoggiarmi al file.vmbackup nel quale andare a inserire i nomi delle directory da includere nel processo di backup:
cd ~ touch .vmbackup echo I3S01 > .vmbackup echo I3S02 >> .vmbackup
vmbackup.sh
Riporto a pezzi (e con qualche commento) lo script principale, che ho comunque zippato se volete scaricarlo interamente: VMbackup.#!/bin/sh # Configurazione virtualMachines=/var/lib/vmware/Virtual\ Machines/ tapeDevice=/dev/st0 tapeBlockSize=4 # * 512 tapeLabelName=$(date +%d%m%Y) logFile=/var/log/vmbackup.log tempFileSystem=/mnt/backuphd/ smtpHost=172.20.3.101 smtpPort=25 mailTo=Backup\ OperatorsNel dettaglio:
$virtualMachines: directory di VMware dove risiedono tutte le macchine virtuali;$tapeDevice: unità di backup;$tapeBlockSize: dimensione dei blocchi dell'unità di backup, 4 vuole dire blocco di 2048 bytes. Per sapere la dimensione del blocco dell'unità di backup:md -f /dev/st0 status
$tapeLabelName: nome da assegnare al nastro;$logFile: nome del file di log (temporaneo, a fine processo viene eliminato se tutto va a buon fine);$tempFileSystem: mountpoint del filesystem su cui verranno copiate le macchine virtuali prima di eseguire il backup;$smtpHost: hostname del server SMTP;$smtpPort: porta del server SMTP;$mailTo: recipient dell'e-mail;
# Verifica il nastro mt -f $tapeDevice status || exit 0 # Verifica il file di configurazione cd ~ test -e ".vmbackup" || exit 0Lo script esce qualora l'unità di backup non fosse pronta (o non ci fosse un nastro al suo interno) o il file di configurazione non dovesse esistere.
# Monta il filesystem temporaneo umount $tempFileSystem > /dev/null mount $tempFileSystem || exit 0Il filesystem temporaneo viene montato a inizio script e smontato al termine. A monte dev'essere aggiunta la riga relativa al filesystem nel
fstab.
# Log touch $logFile echo $(date +%b\ %d\ %H:%M:%S) Avvio... > $logFile echo >> $logFileRegistrazione sul file di log delle attività. Ovviamente integrabile a proprio piacimento.
# Legge VM
vms=
while read vm
do
if [ ${#vm} -gt 0 ]
then
# .vmx
cd "$virtualMachines$vm/"
vmxFile=$(ls *.vmx)
# Sospende la macchina virtuale
vmware-cmd "$virtualMachines$vm/$vmxFile" suspend
sleep 1
# Copia la VM nel filesystem temporaneo
mkdir "$tempFileSystem$vm/" > /dev/null
cd "$virtualMachines$vm/"
cp -v * "$tempFileSystem$vm/"
rm --force "$tempFileSystem$vm/*.log" > /dev/null
# Ripristina la VM
vmware-cmd "$virtualMachines$vm/$vmxFile" start
# Aggiunge la VM alla lista delle VM
vms="$vms$vm/ "
# Aggiunge VM al Log
echo $(date +%b\ %d\ %H:%M:%S) VM: $vm $vmxFile >> $logFile
fi
done < ~/.vmbackup
Questo è il cuore dello script. Brevemente, legge le directory definite nel file di configurazione e, per ciascuna, sospende la macchina virtuale, esegue la copia di tutti i file nel filesystem temporaneo (rimuove i log nella directory temporanea, personalmente non mi serve salvarli), ripristina la macchina virtuale, accoda alla variabile $vms il nome della directory e scrive nel log il riferimento della virtual machine che verrà salvata.
# Nessuna VM da salvare
if [ ${#vms} -le 0 ]
then
exit 0
fi
Se il while precedente non avesse dato risultati in termine di macchine da salvare, esce.
# Riavvolge e cancella il contenuto del nastro mt -f $tapeDevice rewind mt -f $tapeDevice eraseRipulisce il nastro.
# Esegue Backup echo >> $logFile echo $(date +%b\ %d\ %H:%M:%S) Backup in corso: $vms >> $logFile cd "$tempFileSystem" tar cpzvfbV $tapeDevice $tapeBlockSize "$HOSTNAME VMBackup $tapeLabelName" $vms echo $(date +%b\ %d\ %H:%M:%S) Backup terminato. >> $logFileEsegue il backup vero e proprio, la cui origine è la lista delle macchine virtuali lette in precedenza, e la destinazione è
$tapeDevice.
# Elimina VM dal filesystem temporaneo
while read vm
do
if [ ${#vm} -gt 0 ]
then
cd "$tempFileSystem"
rm --force -R "$vm/" > /dev/null
fi
done < ~/.vmbackup
Rimuove file e directory scritte nel filesystem temporaneo.
# Smonta il filesystem temporaneo cd ~ sleep 1 umount $tempFileSystem > /dev/null || echo $(date +%b\ %d\ %H:%M:%S) ATTENZIONE FileSystem temporaneo non smontato. >> $logFileSmonta il filesystem.
# Contenuto backup (per verifica) echo >> $logFile echo $(date +%b\ %d\ %H:%M:%S) Riepilogo Backup >> $logFile echo >> $logFile tar tzfb $tapeDevice $tapeBlockSize >> $logFileNel file di log è bene avere anche una contro-verifica di cosa risulti effettivamente scritto nel nastro.
# Riavvolge ed espelle il nastro (offline fa ambo le cose) sleep 5 mt -f $tapeDevice offlineRiavvolge ed espelle il nastro. Cinque secondi di attesa sono di precauzione, dato che
mt non digerisce bene operazioni in sequenza come in questo caso, evitiamo di cadere nell'errore "Device is busy".
# Log echo >> $logFile echo $(date +%b\ %d\ %H:%M:%S) Terminato. >> $logFile ./sendmail.expect $smtpHost $smtpPort $mailTo $logFile rm $logFileCompletamento del log e invio dell'e-mail.
Dopo qualche test non resta che aggiungere lo script al cron:
ln -s /root/vmbackup.sh /etc/cron.daily/vmbackup
Recupero
Già presente nello script,tar tzfb permette di avere una lista del contenuto del nastro, preceduta dal nome del nastro stesso ($tapeLabelName).
Ottenuto il contenuto del backup, il ripristino è davvero semplice:
tar zxvfb /dev/st0 4 I3S01/I3S01.vmxLa dimensione del blocco è necessaria in qualsiasi operazione di lettura/scrittura dal/sul nastro, al fine di evitare errori bloccanti o recuperare file in realtà inutilizzabili/illeggibili.

Commenta