Software: powerbackup

Simple and flexible incremental backup

Design

This script was designed for using from cron for daily server backup. So, there was several design decisions:

Reliability and Simplicity
We don't need bugs in backup system, so it must be really simple and well-tested.
Consistency
It have a little sense to backup MySQL database files as is without flushing/locking, for example. So, it should be possible to flush/lock database while backup, and locks shouldn't be kept longer than really needed. Other installed projects may require another custom pre/post backup actions — if you wanna be sure they'll work after restoring from backup, of course.
Speed
Backups should be fast and not affect overall system performance. Thus we need incremental backup at least, and also manual tuning of what and how to backup for different things should be possible.
Format
tar and gzip are good enough. For encryption gnupg can be used. Or other standard tools. So there is no needs in inventing own format for backup files.
Interface
It should provide enough information for further tuning of backup speed/size from one view and useful in cron scripts (i.e. don't bother admin with useless emails with script output when everything is ok) from another.
Flexibility
It should be ease to process backups in any way (encrypt, upload using scp, etc.) and parse script output for some monitoring system.

Implementation

For creating incremental backups GNU Tar is used. Only full and level one backups will be created, so to restore from backup at most two files will be required. It's recommended to read 5.2 Using tar to Perform Incremental Dumps and 5.3 Levels of Backups sections from tar manual to find out how to handle created backup files and how to restore from backup (there no powerrestore tool, usual GNU tar can be used to restore from backups).

Overall server backup is split into several independent backup tasks. Each task has own include and exclude file lists for backup and own hooks. This make it possible, for example, make MySQL database backup separate task and setup hooks to flush/lock database only for that task (so database will not be locked while doing backup of other system parts).

For the sake of implementation simplicity include and exclude file lists parsed by (include) bash and (exclude) tar. While tar have support for "include" file lists (option -T) it doesn't support pathname expansion so it's fairly useless. That result in different parsing rules for these files, which increase administration complexity and generally should be considered an architectural flaw. Luckily, bash pathname expansion behaviour are nearly same as tar behaviour with options --wildcards --no-wildcards-match-slash (used in powerbackup), so in practice it's enough to keep in mind only rule: never add last slash to directory names in exclude file.

There two possible hooks: tar and archive.

tar hook
Default: /bin/tar. Used to create .tar-file. It executed with many parameters which should be given to GNU tar. Custom hooks allow you to do something before/after /bin/tar execution — flush/lock MySQL, etc.
archive hook
Default: /bin/gzip. Used to post-process .tar-file. It executed with single parameter — .tar-file name. Custom hooks allow you to replace gzip'ing with something else — encrypting/uploading backup, or doing bzip2 -9, etc.

Backups are created in current directory. Also in current directory powerbackup will create taskname.snap files for each task, which will be used to create incremental (level one) backups on next powerbackup execution in this directory. If current directory does not contain taskname.snap file (because powerbackup is executing first time in this directory or because they was manually removed) the full backup will be created.

Tasks are configured in /etc/powerbackup/. Also this directory contain log.filter file (used for filtering tar/gzip stderr), optional global tar and archive hooks, and other helper scrips (hooks) with their configuration files (few of them included in powerbackup distribution as examples).

Configuration

To set up backup task you should create a subdirectory in /etc/powerbackup/ and put there include file. Also this directory may contain optional exclude and optional executable scripts tar and/or archive. Directory name become backup task's name. cd /etc/powerbackup mkdir config echo '/etc/' >> config/include echo '/proc/config.gz' >> config/include echo '/usr/src/*/.config' >> config/include mkdir users echo '/home/' >> users/include echo '/home/*/.maildir' >> users/exclude ln -s archive.encrypt_gpg users/archive mkdir mysql echo '/var/lib/mysql/' >> mysql/include ln -s tar.lock_mysql mysql/tar

The /etc/powerbackup/archive.encrypt_gpg and /etc/powerbackup/tar.lock_mysql are example hooks distributed with powerbackup. Before using, they should be configured too: cd /etc/powerbackup echo 'my password' > gpg.pass mysql -u root -p mysql mysql> GRANT RELOAD ON *.* TO _backup@localhost IDENTIFIED BY "my password"; echo '_backup' > mysql.user echo 'my password' > mysql.pass

You can setup global hook for all tasks (except tasks which define own hook). cd /etc/powerbackup # encrypt all backups ln -s archive.encrypt_gpg archive # or just disable default behaviour (gzip'ing) ln -s /bin/true archive

Usage example

If you've tasks configured as shown in previous section (expect global archive hook) you can create full backups. # mkdir /var/powerbackup # cd /var/powerbackup # powerbackup Backuping config ... 999999 bytes, 0.999 sec Backuping users ... 9999999 bytes, 9.999 sec Backuping mysql ... 999999999 bytes, 99.999 sec # ls -1 config.full.20080601_211050.tar.gz config.snap mysql.full.20080601_211050.tar.gz mysql.snap users.full.20080601_211050.tar.gpg users.snap

Next execution in same directory will create incremental backups. # cd /var/powerbackup # powerbackup Backuping config ... 100000 bytes, 0.100 sec Backuping users ... 1000000 bytes, 1.000 sec Backuping mysql ... 100000000 bytes, 10.000 sec # ls -1 config.full.20080601_211050.tar.gz config.incr.20080601_211200.tar.gz config.snap mysql.full.20080601_211050.tar.gz mysql.incr.20080601_211200.tar.gz mysql.snap users.full.20080601_211050.tar.gpg users.incr.20080601_211200.tar.gpg users.snap

You can select which tasks to backup. Also you don't have to keep previous backups to create incremental backup — only taskname.snap file is required. # cd /var/powerbackup # rm *.{full,incr}.* # powerbackup config mysql Backuping config ... 100000 bytes, 0.100 sec Backuping mysql ... 100000000 bytes, 10.000 sec # ls -1 config.incr.20080601_211406.tar.gz config.snap mysql.incr.20080601_211406.tar.gz mysql.snap users.snap

Remove taskname.snap to force full backup. # cd /var/powerbackup # rm users.snap # powerbackup Backuping config ... 100000 bytes, 0.100 sec Backuping users ... 9999999 bytes, 9.999 sec Backuping mysql ... 100000000 bytes, 10.000 sec # ls -1 config.incr.20080601_211406.tar.gz config.incr.20080601_212015.tar.gz config.snap mysql.incr.20080601_211406.tar.gz mysql.incr.20080601_212015.tar.gz mysql.snap users.full.20080601_212015.tar.gpg users.snap

Known limitations

It creates single archive file, without volume splitting — so it's impossible to have more than 4GB in single file on FAT32.

Download