Скрипт для полного и дифференциального бэкапа через LVM-снапшоты

Материал из Linux Wiki
Перейти к навигацииПерейти к поиску

Первый скрипт, показанный ниже, используется мной для создания полного и дифференциального (разницей между последним полным и текущим состоянием - как разновидность инкрементного, где архивируется разница между текущим состоянием и предыдущим, каким бы оно не было - полным или инкрементным) бэкапа сервера с использованием LVM-снапшотов.

Для работы скрипта добавляем записи с ним в crontab рута:

# Полный бэкап
25      22      1,15        *       *           /root/bin/diffbackup.sh 2>>/var/log/sysbackup.log
# Дифференциальный бэкап
25      22      2-14,16-31  *       *           /root/bin/diffbackup.sh diff 2>>/var/log/sysbackup.log

В данном случае полный бэкап делается 2 раза в месяц - 1 и 15 числа, во все остальные дни в архив попадает только разница между последним полным бэкапом и текущим состоянием.

Для сжатия архивов используется параллельная версия bzip2 - pbzip2, которую необходимо предварительно установить.

Для восстановления раздела из бэкапа после создания файловой системы на новом диске (при необходимости) и монтирования раздела сначала переходим в точку монтирования и распаковываем архив с полным бэкапом, например:

tar xf rootfs_20111015_222612.full.tar.bz2

после чего в том же каталоге распаковываем архив за нужный день таким образом:

tar xf rootfs_20111019_222612.diff.tar.bz2 -g rootfs_20111019_222612.diff.inc


Собственно, сам скрипт:


#!/bin/bash

logfile='/var/log/sysbackup.log' # Файл, куда будут скидываться сообщения хода выполнения скрипта
backupdir='/storage/backup/' # Каталог для складирования архивов
smpdir='/tmp/snap/' # Каталог точки монтирования снапшотов

# Создаем временный каталог и каталог бэкапа
mkdir -p "${smpdir}" "${backupdir}"

# В строке ниже исключаем все LV, которые не нужно обрабатывать - своп, спул Сквида и прочее
ls -1 /dev/sysvg/ | grep -vE 'buildfs|swap|squidcachespace|repo|spyroot|tempvideo' |
while read lv
do
# Создаем временную метку
        tstamp="$(date +%Y%m%d_%H%M%S)"
#
        pref="${backupdir}${lv}_${tstamp}"
        echo "${tstamp}: Processing ${lv}" >> $logfile
# Создаем устройство снапшота размером 5 Гб
        /sbin/lvcreate -s -L5G -nbackupsnapshot /dev/sysvg/$lv
# Монтируем устройство снапшота
        mount /dev/sysvg/backupsnapshot "${smpdir}"
# Выбираем тип бэкапа
        case "${1}" in
                diff)
                # Делаем дифференциальный бэкап
# Находим последний полный бэкап
                lastfull="$(ls -1tr "${backupdir}${lv}"_*.full.inc | tail -n1)"
# Если не нашли - пишем ошибку в лог и выходим
                if [ -z "${lastfull}" ]
                        then
                                echo "Cant find last full backup for ${lv}" >> "${logfile}"
                        else
# Создаем новый файл изменений
                                cp "${lastfull}" "${pref}.diff.inc"
# Делаем дифференциальный бэкап, основываясь на файле изменений последнего полного бэкапа
                                tar c -C "${smpdir}" . --exclude="*/backups/*.tar.bz2" -g "${pref}.diff.inc" |
                                pbzip2 -9c > "${pref}.diff.tar.bz2"
                fi
                ;;
                *)
# Делаем полный бэкап данных, создавая полный файл изменений
# Бэкапим данные, эксклудя бэкапы доменов
                tar c -C "${smpdir}" . --exclude="*/backups/*.tar.bz2" -g "${pref}.full.inc" |
                pbzip2 -9c > "${pref}.full.tar.bz2"
                ;;
        esac
# Демонтируем снапшот
        umount "${smpdir}"
# Удаляем устройство снапшота
        /sbin/lvremove -f /dev/sysvg/backupsnapshot
        echo $(date) $lv done >> $logfile
done

if ! mountpoint -q "${smpdir}" ;
        then
        rm -rf "${smpdir}"
fi

# Заливаем бэкап на NAS && удаляем архивы на локальном диске
/root/bin/ftpb.sh && rm -f /storage/backup/*.diff.* /storage/backup/*.full.tar.bz2

В последней строке выполняется аплоад полученных архивов на NAS - в моем случае используется Packard Bell NetStore 3500 с аплоадом через FTP. Для этого используется второй скрипт:


#!/bin/bash

nasip='192.168.0.239' # IP NAS'a
auser='adminlogin' # admin-юзер для получения статистики
apass='adminpass' # пароль админ-юзера
ftpbmrk='nas01-gb' # название закладки в lftp для подключения к NAS'у
logfile='/var/log/sysbackup.log'

# Проверяем доступность NAS'a
netcat -w3 -z "${nasip}" 21 || exit 1

# Функция получения количества свободного места на NAS'e в Mb
ndf() {
    wget -qO- "http://${auser}:${apass}@${nasip}/status.htm" |
    awk '
    BEGIN {
        fs=0
        }

    /Free Size/{
        fs=1
        }

    /MB/{
        OFMT="%.f"
        if (fs=='1') print $1 ; fs=0
        }
        '
}

echo $(date): Starting upload files to NAS >> "${logfile}"

# Получаем размер бэкапа
bsize="$(du -s /storage/backup/ | cut -f-1)"

echo $(date): Backup size: "${bsize}" Kb >> "${logfile}"

# Преобразуем Килобайты в Мегабайты и делаем запас свободного места на NAS'е
bsize="$((${bsize}/1024+2048))"

# Если свободного места меньше заданного - удаляем один файл в каталоге
while [ "$(ndf)" -lt "${bsize}" ]
        do
# Получаем список файлов, сортируем, получаем самый старый файл
        rmfile="$(lftp -e 'ls;quit' "${ftpbmrk}" 2>/dev/null |
        awk '/_/{print $9}' |
        sed -r -e 's/[a-z]+_(.*)/& \1/g' |
        sort -nrk2 |
        awk '{print $1}' | tail -n1)"

echo $(date): NDF: "$(ndf)" MB >> "${logfile}"

echo $(date): Not enough free space on NAS, removing "${rmfile}" >> "${logfile}"

# Удаляем файл
        lftp -e "rm ${rmfile} ; quit" "${ftpbmrk}"
done

echo $(date): BEGIN of fileupload >> "${logfile}"

# Копируем файлы бэкапов на NAS
lftp -e 'lcd /storage/backup/ ; mirror -R . ; quit'  "${ftpbmrk}"

echo $(date): END of fileupload >> "${logfile}"

Для аплоада используется FTP-клиент lftp (почему-то NAS с ncftp работать отказался). Для подключения к NAS'у в FTP-клиенте используются закладки для предотвращения отображения пароля пользователя в списке процессов:

# cat .lftp/bookmarks 
 nas01-gb        ftp://uploaduser:uploaduserpass@192.168.0.239/in/goro_backup/

Скрипт отслеживает использование диска на NAS, для чего авторизуется на нем через web-интерфейс и получает значение свободного места. Если значение размера текущего бэкапа + 2 Гб (запас на всякий случай для уменьшения фрагментации и т.п.) больше, чем полученное значение свободного места - скрипт удаляет самые старые файлы на NAS'e - до тех пор, пока места не станет достаточно.