Implementation
This is a summary of the steps needed to perform a backup of a virtual machine:
Bacula Director Daemon (backup01) instructs the Bacula Client Daemon to start a copy of virtual01.
- Bacula Client Daemon (production01) performs the snapshot of the virtual machine with the reflink command. There is no need to suspend or stop the virtual machine to make the copy.
- The copy is compressed, to reduce bandwidth and storage consumption.
- Then, Bacula Client Daemon (production01) instructs Bacula Storage Daemon (desarrollo01) to store the copy of virtual01 in storagebackup.
- Finally, if the copy has been correctly carried out, files created during this process will be deleted.
Now, we will detail the configuration of each component.
Configuration of Bacula Director Deamon
The backup process must be configured in the Bacula Director Deamon, hosted in backup01, in the file /etc/bacula-dir.conf
. Job is the Bacula term for the backup tasks that must be scheduled. To define a new Job, you have to add 3 new elements to that configuration file. The first one is the client that will perform the Job:
Client { Name = produccion01-fd Address = produccion01 # IP FDPort = 9102 Catalog = MyCatalog Password = "produccion01-fd.password" File Retention = 1 year Job Retention = 1 year AutoPrune = yes Maximum Concurrent Jobs = 10 }
The second one is the storage where the client will write the backup.
Storage { Name = "storage_virtual01_full" Address = desarrollo01 SDPort = 9103 Password = "desarrollo01-sd.password" Device = backup_erp01_full Maximum Concurrent Jobs = 10 Media Type = "file_virtual01_full" }
Schedule { Name = "schedule_virtual01_full" Run = Level=Full Pool=pool_mensual on 1,16 at 3:00 Run = Level=Full Pool=pool_quincenal sun-sat at 3:00 } FileSet { Name = "fileset_virtual01_full" Include { Options { signature = SHA1; onefs = yes; } File = /storage/virtual01-bak.gz } } Job { Name = "job_virtual01_full" Type = Backup Level = Full Client = produccion01-fd FileSet = "fileset_virtual01_full" Schedule = "schedule_virtual01_full" Storage = "storage_virtual01_full" Messages = Standard Pool = pool_anual Full Backup Pool = pool_mensual Incremental Backup Pool = pool_quincenal Priority = 11 Write Bootstrap = "/apps/bacula/opt/bacula/working/virtual01_full.bsr" ## Script running on client Client Run Before Job = "/apps/bacula/script/backup_full_guest.sh virtual01" Client Run After Job = "/apps/bacula/script/remove_backup_full_guest.sh virtual01" }
There are two things that are worth noting in that configuration. The first one is the file that is going to be copied, in section FileSet:
File = /storage/virtual01-bak.gz
The second one is the declaration of the scripts in charge of copying and compressing the virtual01 image, on one hand, and removing those files afterwards, on the other. This is done in section Job. Those scripts are detailed later on.
Client Run Before Job = "/apps/bacula/script/backup_full_guest.sh virtual01" Client Run After Job = "/apps/bacula/script/remove_backup_full_guest.sh virtual01"
If you want to know with more detail the rest of settings that have be configured, you can visit the Bacula documentation (www.bacula.org).
Configuration of Bacula Storage Daemon
Once the Job is defined in the Bacula Director Daemon, you must create a Device (place where the backup will be stored) in the Bacula Storage Daemon (desarrollo01). It is done in the configuration file /etc/bacula-sd.conf
, adding the following lines:
Device { Name = backup_virtual01_full Media Type = file_erp01_sql Archive Device = /backup/vm/virtual01 LabelMedia = yes; Random Access = Yes; AutomaticMount = yes; RemovableMedia = no; AlwaysOpen = no; Maximum Concurrent Jobs = 10 }
Configuration of Bacula Client Daemon
Finally, we need to define two scripts, to perform the snapshot of the virtual machine and remove it once it is transferred to storagebackup. These scripts will be stored in the Bacula Client Daemon (produccion01).
#!/bin/sh MACHINE=$1 [ -n "$MACHINE" ] || { echo Usage: ./backup_full_guest.sh guest_name exit 1 } LOGFILE=/apps/bacula/log/log_$MACHINE.log log() { echo $(date "+%d-%m-%Y %H:%M") "$@" >> $LOGFILE } log IMAGE="/storage/$MACHINE" [ -f "$IMAGE" ] || { log ERROR: GUEST $MACHINE DOES NOT EXIST exit 1 } BAK="$IMAGE-bak" log "---- Reflink ---- $MACHINE ----" if ! reflink "$IMAGE" "$BAK"; then log ERROR CREATING $MACHINE SNAPSHOT exit 1 fi log Reflink of $MACHINE succeeded. if ! gzip "$BAK"; then log ERROR COMPRESSING THE BACKUP exit 1 fi log Image compressed
#!/bin/sh MACHINE=$1 [ -n "$MACHINE" ] || { echo Usage: ./remove_backup_full_guest.sh guest_name exit 1 } LOGFILE=/apps/bacula/log/log_$MACHINE.log log() { echo $(date "+%d-%m-%Y %H:%M") "$@" >> $LOGFILE } log IMAGE="/storage/$MACHINE" BAK="$IMAGE-bak.gz" [ -f "$BAK" ] || { log ERROR: THE BACKUP OF $MACHINE DOES NOT EXIST exit 1 } log "---- Remove ---- $MACHINE ----" if ! rm -f "$BAK"; then log ERROR REMOVING $BAK exit 1 fi log Backup removed