Backup su storage remoto dei dump
Normalmente io preferisco che la macchina con PVE esegua i backup su un disco locale piuttosto che su uno storage montato da remoto. Il motivo di questa scelta è presto detto: il disco locale di solito è più veloce e meno prono ad avere problemi di disconnessioni. Usando backup diretto su storage remoti in NFS mi è capitato di avere dei piantamenti (morte del server NFS sotto carico) durante il backup che provocano il piantamento della VM che sto backuppando e questo non mi piace. So bene che il server NFS non dovrebbe morire, ma siccome lo fa, ho imparato ad adattarmi al problema e girarci intorno, installando un disco interno per i backup. Una volta terminato il backup (con vzdump, ovvero con il sistema di backup presente dentro PVE) sul disco interno, questo script permette di fare una seconda copia su un disco esterno, senza che questa operazione impatti sulle VM in esecuzione anche in caso di problemi al disco esterno.
Questo script si "aggancia" al sistema di backup interno di PVE (non parliamo di PBS, parliamo della funzione di dump contenuta in PVE), allo scopo di fare una seconda copia dei dump delle VM su uno storage esterno (smb, nfs, usb, qualsiasi cosa si possa montare). Questo script cosi` come e` fatto tiene 6 backup giornalieri e 4 settimanali, quindi sono 10 backup. Tenete bene conto dello spazio necessario! Ad ogni esecuzione di un job di backup, una volta eseguiti i dump di tutte le VM, questo script copia tutti i dump sullo storage remoto, dopo aver archiviato quelli precedenti dentro le directory "daily" e "weekly".
Nella nuova versione (che trovate qui sotto) ho aggiunto una funzione che crea un hard link dell'ultimo file creato nel backup su un file con un nome fissato. In altri termini, impostando la variabile "hardlink" a un path (che deve esistere e deve trovarsi sullo stesso disco fisico che contiene i backup) lo script crea un hard link (che non consuma spazio ulteriore) dal file backuppato da PVE (che ha un nome non prevedibile in quanto contiene data e ora) dentro alla directory definita nella variabile "hardlink" con un nome fisso, sovrascrivendo, se c'e`, il file con il medesimo nome. Questo "trucco" permette di eseguire un backup remoto in un secondo tempo in modalità "pull", usando backuppc o rsnapshot o altri sw di backup che fanno storicizzazione e deduplica, potendosi così proteggere meglio dai ransomware o da un attacco al server PVE, usando dei backup storicizzati non accessibili a meno che non venga compromesso anche il server di backup.
NOTA BENE: PVE6 e 7 usano variabili diverse. Per PVE6 usare $TARFILE al posto di $TARGET nello script
Prima di tutto, creare lo script e renderlo eseguibile. Io lo chiamo /root/pve-remote-backup.sh.
#!/bin/bash # Impostazioni varie: # dove salvo il file con l'elenco dei files da backuppare listfile="/tmp/pve-remote-backup-filelist.txt" # dove monto il disco dello storage remoto o removibile mountpoint="/usbdisk" # dove vengono creati gli hard link che verranno poi usati # da un sistema di backup pull remoto (backuppc / rsnapshot) # NOTA BENE: il path deve essere nello stesso disco fisico dove si trovano # i backup di PVE, deve esistere, ed e` meglio che sia diverso da quello # che contiene i backup (che di solito e` "dumps") # Se non voglio usare questa funzione lo imposto a "NONE" o commento via la riga hardlink="/backupdisk/hardlinks" # all'inizio del job, mi assicuro di cancellare # la lista dei files if [ "$1" == "job-start" ]; then echo "JOB-START: cancello la lista dei files" [ -f $listfile ] && rm $listfile exit 0 fi # alla fine del singolo backup mi segno il nome # del file che e` stato creato, mi servirà dopo per # sapere cosa devo copiare. if [ "$1" == "backup-end" ]; then echo "BACKUP-END: salvo il nome del file" echo $TARGET >> $listfile # echo $TARFILE >> $listfile fi # alla fine del job, # se la funzione hardlink è richiesta, la eseguo, poi # monto lo storage remoto, ruoto i vecchi backup se necessario, # e copio tutti i files del backup attuale sullo storage remoto if [ "$1" == "job-end" ]; then # se la variabile hardlink non e` vuota, non contiene la stringa "NONE" # ed e` una directory che esiste, allora procediamo a creare gli hard link if [ ! -z $hardlink ] && [ "$hardlink" != "NONE" ] && [ -d $hardlink ] ; then echo "JOB-END: Creo i link per il backup a mezzo di rsnapshot" while IFS= read -r line do nopath=`echo $line | awk 'END{ n=split ($NF,a,"/"); print a[n]}'` destination=`echo $nopath | awk -F[-.] '{ print $1 "-" $2 "-" $3 "." $6 "." $7}'` if [[ -z "${line// }" ]] ; then echo "JOB-END: ERRORE, trovata una linea vuota nell'elenco di input - la ignoro" else echo "JOB-END: creo hardlink da $line su $hardlink/$destination" ln -f $line $hardlink/$destination fi done <"$listfile" fi # fine della procedura degli hard link, procediamo con le copie sullo storage remoto echo "JOB-END: Monto lo storage remoto" # MODIFICARE QUI PER IL MOUNT mount -L usbbackup $mountpoint if mountpoint -q $mountpoint; then echo "JOB-END: Storage remoto montato" # Leggo la lista dei files da copiare e li copio rinominandoli # in modo da togliere il timestamp. while IFS= read -r line do nopath=`echo $line | awk 'END{ n=split ($NF,a,"/"); print a[n]}'` destination=`echo $nopath | awk -F[-.] '{ print $1 "-" $2 "-" $3 "." $6 "." $7}'` if [[ -z "${line// }" ]] ; then echo "JOB-END: ERRORE, trovata una linea vuota nell'elenco di input - la ignoro" else echo "JOB-END: Salvo lo storico per $mountpoint/$destination" if [[ $(date +%u) -eq 7 ]] ; then # se e` domenica salvo in weekly e ne tengo 4 savelog -c4 -l -r weekly $mountpoint/$destination else # se e` un altro giorno salvo in daily e ne tengo 6 savelog -c6 -l -r daily $mountpoint/$destination fi echo "JOB-END: Copio $line su $mountpoint/$destination" cp $line $mountpoint/$destination fi done <"$listfile" # Fine della copia, smonto e ho finito. echo "JOB-END: Smonto lo storage remoto" umount $mountpoint exit 0 else echo "JOB-END: ERRORE, storage remoto non accessibile" exit 1 fi fi
- modificare lo script in modo da fare il mount del vostro storage remoto preferito
- impostare il path per gli hardlink (se volete) oppure impostarlo a "NONE" per disattivare la funzione relativa
Per finire, modificare il file /etc/vzdump.conf inserendo una riga che dice di usare lo script durante i job di backup. In questo modo il nostro script casalingo verrà richiamato dalla procedura di backup interna di PVE. Questa seconda versione dello script non si incasina se viene richiamato due volte in due procedure di backup diverse che eseguono i backup di VM diverse, in quanto ogni invocazione dello script va a modificare SOLO i files relativi alle VM che vengono incluse nel backup in esecuzione. In altri termini, se ho 4 VM e ne backuppo due alla mattina e due al pomeriggio, lo script non va ad archiviare sul disco di backup esterno le VM che non sono parte del backup in corso. Tuttavia, se decido di backuppare la stess VM tre volte in un giorno, allora occorre rivedere le logiche di archiviazione "daily" e "weekly" perchè queste logiche sono pensate per UN SOLO BACKUP al giorno di ogni VM.
script: /root/pve-remote-backup.sh