Скрипт инкрементального и полного бэкапов

У меня недавно на работе была задача, придумать бэкап для файлового сервера с документами, фотками, презентациями и прочей фигней. Система на которой расположен файловый сервер, не обычный Linux, а точнее вообще не Linux, это FreeNas. Это очень переработаная и урезаная версия Фряхи подогнанная для одной простой цели, быстро и удобно разворачивать Storage-хранилища, все это дело работает на файловой системе ZFS. Кстати не в тему, но все же, FreeNas очень хорош, особенно когда нужно развернуть сетевое хранилище в короткие сроки, все плюшки из коробки SSH, NFS, SAMBA, LDAP + Web-инетрфейс и удобная командная строка как всегда под рукой. Так вот, вернемся к нашему бэкапу. Я сначала начал смотреть в сторону готовых решений, типа Bacula или Obnam, но их не так просто поставить на сильно урезанном FreeNas, к тому же времени просто не было на это.

В связи с этим, я начал искать готовые скрипты, ну и тут все не то (напоминаю это связано с ограничениям самой системы FreeNas). Короче я на все плюнул, и закатал свой скрипт. Так как срипт должен уметь делать инкрементальный бэкап, я смотрел в сторону tar, rdiff-backup и rsync. В итоге остановился на rsync.

Теперь к делу, задача:
– Бэкап должен проходить так: раз в день инкрементальный, раз в неделю полный, и раз в месяц полный.
– В любой момент времени должно быть четыре копии полного бэкапа.
– Бэкап должен литься на другой физический диск и не в коем случае не в сеть
– Должны быть логи.

Решение, сначала приведу пример папок необходимых для хранения копий:

[alexander@files /mnt/files2]$ ls -la
total 16
drwxrwxrwx+ 6 root  wheel    11 Jun 14 14:59 .
drwxr-xr-x  5 root  wheel   512 Jun 21 17:16 ..
drwxr-xr-x  2 root  wheel     3 Jun 27 15:23 FullMonth
drwxr-xr-x  2 root  wheel     2 Jun 27 12:04 FullWeelky
drwxr-xr-x  2 root  wheel     2 Jun 27 12:04 IncrementBackup
-rwxrwxrwx+ 1 root  wheel  3229 Jun 27 12:09 backRsync.sh
-rw-r--r--  1 root  wheel    17 Jun 27 12:04 backup_exclude.lst
-rw-r--r--  1 root  wheel    11 Jun 27 12:06 backup_include.lst
-rw-r--r--  1 root  wheel    11 Jun 13 16:01 backup_src.lst
drwxr-xr-x  2 root  wheel     3 Jun 27 15:23 temp
[[email protected] /mnt/files2]$ ls -la
total 16
drwxrwxrwx+ 6 root  wheel    11 Jun 14 14:59 .
drwxr-xr-x  5 root  wheel   512 Jun 21 17:16 ..
drwxr-xr-x  2 root  wheel     3 Jun 27 15:23 FullMonth
drwxr-xr-x  2 root  wheel     2 Jun 27 12:04 FullWeelky
drwxr-xr-x  2 root  wheel     2 Jun 27 12:04 IncrementBackup
-rwxrwxrwx+ 1 root  wheel  3229 Jun 27 12:09 backRsync.sh
-rw-r--r--  1 root  wheel    17 Jun 27 12:04 backup_exclude.lst
-rw-r--r--  1 root  wheel    11 Jun 27 12:06 backup_include.lst
-rw-r--r--  1 root  wheel    11 Jun 13 16:01 backup_src.lst
drwxr-xr-x  2 root  wheel     3 Jun 27 15:23 temp

Думаю тут все понятно, ибо имена я старался давать читабельные, все эти папки живут на том же диске что и бэкапы /mnt/files

Сам скрипт:

[alexander@files /mnt/files2]$ vi backRsync.sh
#!/bin/sh
# cron: 0 3 * * * root /root/adm/backup.sh
# Script for Incremential and Full backup of files
 
# Where to put backup files
BACKUP_DIR=/mnt/files2/IncrementBackup
WEEKLY_BACKUP=/mnt/files2/FullWeelky
MONTH_BACKUP=/mnt/files2/FullMonth
 
# List with options exclude, include
# And lit of dirictories that need to backup
FILES_SRC=/mnt/files2/backup_src.lst
INCLUDE_FILES_PATTERN=/mnt/files2/backup_include.lst
EXCLUDE_FILES_PATTERN=/mnt/files2/backup_exclude.lst
 
# LOGS
LOG="/mnt/files/LOGS/archive.log"
ERRORLOG="/mnt/files/LOGS/archive_error.log"
#BIGLOG="/mnt/files/LOGS/big.log"
 
# TIME VARIABLES
TIMESTAMP=`date '+%Y-%m-%d_%H:%M:%S'`
DAY=`date '+%d'` # Day of week for INCREMENTIAL backup
DOW=`date '+%u'` # Day of week for Weekley backup (1..7); 1 is Monday, 7 is Sunday
DATE=`date '+%d-%m-%y_%H:%M'` # For FULL backup
DOM=`date +%d` # For Month backup
 
# DIRS VARIABLES
FULL_BACKUP_DIR=$BACKUP_DIR/current
INC_BACKUP_DIR=$BACKUP_DIR/$DAY\_$TIMESTAMP
 
echo "$(date +%F_%R:%S) #################### Start script ####################" >> $LOG
echo "" >> $LOG
echo "$(date +%F_%R:%S) #################### Start script ####################" >> $LOG
echo "" >> $LOG
 
# MONTHLY FULL BACKUP
if [ $DOM = "27" ]; then
        echo "$(date +%F_%R:%S) START OF MONTH BACKUP" >> $LOG
        echo "" >> $LOG
                if /usr/bin/tar -pczf /mnt/files2/temp/month1.tgz /mnt/files >> $LOG
                ls -lSh /mnt/files2/temp/month1.tgz >> $LOG
                mv /mnt/files2/FullMonth/month2.tgz /mnt/files2/FullMonth/month3.tgz >>$LOG
                mv /mnt/files2/FullMonth/month1.tgz /mnt/files2/FullMonth/month2.tgz >> $LOG
                mv /mnt/files2/temp/month1.tgz $MONTH_BACKUP/month1.tgz >> $LOG
                        then
                        echo "$(date +%F_%R:%S) MONTHLY ARCHIVING WAS DONE SUCCESFULL" >> $LOG
                        echo "" >> $LOG
                fi
fi
 
# WEEKLY FULL BACKUP
if [ $DOW = "3" ]; then
        echo "$(date +%F_%R:%S) START WEEKLY BACKUP" >> $LOG
        echo "" >> $LOG
                if /usr/bin/tar -pczf /mnt/files2/temp/week1.tgz /mnt/files >> $LOG
                ls -lSh /mnt/files2/temp/week1.tgz >> $LOG
                mv /mnt/files2/FullWeelky/week2.tgz /mnt/files2/FullWeelky/week3.tgz >> $LOG
                mv /mnt/files2/FullWeelky/week1.tgz /mnt/files2/FullWeelky/week2.tgz >> $LOG
                mv /mnt/files2/temp/week1.tgz $WEEKLY_BACKUP/week1.tgz >> $LOG
                        then
                        echo "$(date +%F_%R:%S) WEEKLY ARCHIVING WAS DONE SUCCESFULL" >> $LOG
                        echo "" >> $LOG
                fi
fi
 
rm -f -R $BACKUP_DIR/$DAY\_* >> $LOG
 
# INCREMENTIAL BACKUP WITH RSYNC
echo "$(date +%F_%R:%S) START INCREMENTAL BACKUP" >> $LOG
echo "" >> $LOG
nice -n 10 rsync -r --force --ignore-errors --delete --delete-excluded -av  \
--backup --backup-dir=$INC_BACKUP_DIR \
--exclude-from=$EXCLUDE_FILES_PATTERN \
--include-from=$INCLUDE_FILES_PATTERN \
--files-from=$FILES_SRC \
/ $FULL_BACKUP_DIR >> $LOG
 
rm -f $BACKUP_DIR/current\_*.tar.gz >> $LOG
cd $BACKUP_DIR >> $LOG
nice -n 10 tar -zcf $BACKUP_DIR/current\_$TIMESTAMP.tar.gz * >> $LOG
 
#IAM NOT SURE ABOUT MAIL
#mail -s "SVN backup log" [email protected] < /mnt/files2/temp/backup.log
 
echo "" >> $LOG
echo "$(date +%F_%R:%S) ##################### End script #####################" >> $LOG
 
echo "" >> $ERRORLOG
echo "$(date +%F_%R:%S) ##################### End script #####################" >> $ERRORLOG
[[email protected] /mnt/files2]$ vi backRsync.sh
#!/bin/sh
# cron: 0 3 * * * root /root/adm/backup.sh
# Script for Incremential and Full backup of files

# Where to put backup files
BACKUP_DIR=/mnt/files2/IncrementBackup
WEEKLY_BACKUP=/mnt/files2/FullWeelky
MONTH_BACKUP=/mnt/files2/FullMonth

# List with options exclude, include
# And lit of dirictories that need to backup
FILES_SRC=/mnt/files2/backup_src.lst
INCLUDE_FILES_PATTERN=/mnt/files2/backup_include.lst
EXCLUDE_FILES_PATTERN=/mnt/files2/backup_exclude.lst

# LOGS
LOG="/mnt/files/LOGS/archive.log"
ERRORLOG="/mnt/files/LOGS/archive_error.log"
#BIGLOG="/mnt/files/LOGS/big.log"

# TIME VARIABLES
TIMESTAMP=`date '+%Y-%m-%d_%H:%M:%S'`
DAY=`date '+%d'` # Day of week for INCREMENTIAL backup
DOW=`date '+%u'` # Day of week for Weekley backup (1..7); 1 is Monday, 7 is Sunday
DATE=`date '+%d-%m-%y_%H:%M'` # For FULL backup
DOM=`date +%d` # For Month backup

# DIRS VARIABLES
FULL_BACKUP_DIR=$BACKUP_DIR/current
INC_BACKUP_DIR=$BACKUP_DIR/$DAY\_$TIMESTAMP

echo "$(date +%F_%R:%S) #################### Start script ####################" >> $LOG
echo "" >> $LOG
echo "$(date +%F_%R:%S) #################### Start script ####################" >> $LOG
echo "" >> $LOG

# MONTHLY FULL BACKUP
if [ $DOM = "27" ]; then
        echo "$(date +%F_%R:%S) START OF MONTH BACKUP" >> $LOG
        echo "" >> $LOG
                if /usr/bin/tar -pczf /mnt/files2/temp/month1.tgz /mnt/files >> $LOG
                ls -lSh /mnt/files2/temp/month1.tgz >> $LOG
                mv /mnt/files2/FullMonth/month2.tgz /mnt/files2/FullMonth/month3.tgz >>$LOG
                mv /mnt/files2/FullMonth/month1.tgz /mnt/files2/FullMonth/month2.tgz >> $LOG
                mv /mnt/files2/temp/month1.tgz $MONTH_BACKUP/month1.tgz >> $LOG
                        then
                        echo "$(date +%F_%R:%S) MONTHLY ARCHIVING WAS DONE SUCCESFULL" >> $LOG
                        echo "" >> $LOG
                fi
fi

# WEEKLY FULL BACKUP
if [ $DOW = "3" ]; then
        echo "$(date +%F_%R:%S) START WEEKLY BACKUP" >> $LOG
        echo "" >> $LOG
                if /usr/bin/tar -pczf /mnt/files2/temp/week1.tgz /mnt/files >> $LOG
                ls -lSh /mnt/files2/temp/week1.tgz >> $LOG
                mv /mnt/files2/FullWeelky/week2.tgz /mnt/files2/FullWeelky/week3.tgz >> $LOG
                mv /mnt/files2/FullWeelky/week1.tgz /mnt/files2/FullWeelky/week2.tgz >> $LOG
                mv /mnt/files2/temp/week1.tgz $WEEKLY_BACKUP/week1.tgz >> $LOG
                        then
                        echo "$(date +%F_%R:%S) WEEKLY ARCHIVING WAS DONE SUCCESFULL" >> $LOG
                        echo "" >> $LOG
                fi
fi

rm -f -R $BACKUP_DIR/$DAY\_* >> $LOG

# INCREMENTIAL BACKUP WITH RSYNC
echo "$(date +%F_%R:%S) START INCREMENTAL BACKUP" >> $LOG
echo "" >> $LOG
nice -n 10 rsync -r --force --ignore-errors --delete --delete-excluded -av  \
--backup --backup-dir=$INC_BACKUP_DIR \
--exclude-from=$EXCLUDE_FILES_PATTERN \
--include-from=$INCLUDE_FILES_PATTERN \
--files-from=$FILES_SRC \
/ $FULL_BACKUP_DIR >> $LOG

rm -f $BACKUP_DIR/current\_*.tar.gz >> $LOG
cd $BACKUP_DIR >> $LOG
nice -n 10 tar -zcf $BACKUP_DIR/current\_$TIMESTAMP.tar.gz * >> $LOG

#IAM NOT SURE ABOUT MAIL
#mail -s "SVN backup log" [email protected] < /mnt/files2/temp/backup.log

echo "" >> $LOG
echo "$(date +%F_%R:%S) ##################### End script #####################" >> $LOG

echo "" >> $ERRORLOG
echo "$(date +%F_%R:%S) ##################### End script #####################" >> $ERRORLOG

Разобраться в работе скрипта просто, он вроде хорошо прокомментирован.
Некоторые пояснения:

– в файле backup_exclude.lst пишем директории которые хотим исключить и не бэкапить
– в файле backup_include.lst пишем директории которые хотим включить в бэкап (только если они не содержаться в файле backup_src.lst)
– в файле backup_src.lst пишем директорию которую хотим бэкапить

например у меня /mnt/files
соответственно все что будет там, будет качественно забэкапено, само сабой rsync работает в скрипте рекурсивно, как и tar. Там еще есть строчка, которая может отправлять лог по почте, мне эта функциия не пригодилась, но на всякий случай я ее не убрал.

Вчера забыл написать, добавлю сегодня, запускать скрипт желательно только в bash, т.е. в FreeNas это так:

/usr/local/bin/bash backRsync.sh
/usr/local/bin/bash backRsync.sh

Спасибо за комментарии, но я за ранее прошу прощения за балаган что я тут устроил. У меня вообще нет времени следить за блогом, но я постараюсь при первой же возможности все поправить. Тот факт, что в скрипте есть такие строчки как ERROR LOG или mail говорит только о том, какая изначально было задумка, скрипт писался в течении 10 минут, ошибок в коде нет, но все что не нужное я просто закоментил.