Уже было много постов о резервном копировании, особенно много для ОС Linux. Озаботился и я настройкой резервного копирования.
Требовалось создавать бэкапы системы, данных с примонтированного раздела и LVM томов (диски виртуальных машин). Были мысли использовать Bacula, т.к. знаком с ней, но поскольку дома только 1 компьютер клиент-серверная архитектура только создавала-бы дополнительные сложности при восстановлении в случае повреждения системы. Значит систему и данные просто копируем, образ LVM раздела создаем с помощью dd. Хотелось делать резервную каждый день (хотя-бы данных) и хранить минимум 14 дней. Но поиски готовых и простых решений, удовлетворяющих всем потребностям не увенчались успехом. А значит берем в руки bash и пишем свой велосипед. В этой статье я делюсь тем, что вышло.
Disclaimer: при написании скриптов не было цели написать монстров, которые делают все. Нужен был простой и надежный способ бэкапа. Буду благодарен за указание неточностей и узких мест скриптов (тех, где могут возникнуть ошибки). Статья расчитана больше на новичков в Linux, которые ищут готовое решение и на лентяев, :) которым лень писать самим.
Исходные условия:
- ОС: Arch Linux
- Корневая файловая система (/): btrfs, копировать нужно все файлы.
- Раздел с данными (/mnt/data/): btrfs.
- LVM тома (/dev/virt_image_array/*).
- Раздел для бэкапов (/mnt/backup/: etx4, сюда будут складываться резервные копии.
- Необходимые утилиты (кроме входящих в базовый дистр): rsync, btrfs-progs (для управления btrfs).
Было решено раз в неделю делать полную копию всего и каждый день создавать снапшот разделов с btrfs. Можно так-же создавать снапшоты LVM томов, но для меня потеря данных за неделю не критична, поэтому хватит еженедельных копий.
Итак, скрипт № 1, создает копию файлов корневого раздела в /mnt/backup/root/«номер дня»/.
#!/bin/bash
set -e
echo "Date_start: `date +%Y-%m-%d-%H-%M-%S`"
#Дата для удобного чтения логов
### Vars ###
#Количество дней от точки отсчета (1970 год)
day=$((`date +%s` / (60*60*24)))
#Сколько дней хранить бэкапы
dayexp=21
#Что копируем
path="/"
#Откуда копируем (путь до снапшота)
spath="/snapshots/backup_script/"
#Куда копируем
dpath="/mnt/backup/root/"
### Delete Old Backups ###
#Удаляем старые бэкапы
find $dpath -type d 2>/dev/null| awk '{FS="/"} {print $5}'| sort|uniq | while read ONE_OF_LIST
do
if [[ "$ONE_OF_LIST" -lt "$day - $dayexp" ]] && [[ -n "$ONE_OF_LIST" ]]
then
echo "remove: $dpath$ONE_OF_LIST"
rm -rf $dpath$ONE_OF_LIST
fi
done
### Check exist snapshot ###
#Проверяем наличие снапшота, удаляем, если находим
if (( "`btrfs subvolume list / | grep backup_script |wc -l`" > 0 ))
then
echo "Warning: Snapshot exist, deleting"
btrfs subvolume delete $spath
fi
### Create snapshot ###
#Делаем снапшот
btrfs subvolume snapshot / $spath
### Rsync ###
#Копируем данные из снапшота
rsync -aAXv $spath $dpath$day
### Delete snapshot ###
#Удаляем снапшот
btrfs subvolume delete $spath
echo "Backup succesful complete"
echo "Date_end: `date +%Y-%m-%d-%H-%M-%S`"
exit 0
Скрипт № 2, создает снапшоты корневой ФС (скрипт логикой очень похож на 1й, поэтому коментировать буду только отличия). Снапшот имеет имя auto_«номер дня».
#!/bin/bash
set -e
echo "Date_start: `date +%Y-%m-%d-%H-%M-%S`"
### Vars ###
day=$((`date +%s` / (60*60*24)))
dayexp=14
path="/"
spath="/snapshots/"
### Delete Old Backups / Check existing snapshot ###
#Старые бэкапы удаляем, если находим сегодняшний снапшот выходим
btrfs subvolume list / |grep auto |sed -e '1,$ s/.*_//g'| while read ONE_OF_LIST
do
if [[ "$ONE_OF_LIST" -lt "$day - $dayexp" ]]
then
echo "remove: $spath"auto_"$ONE_OF_LIST"
btrfs subvolume delete $spath"auto_"$ONE_OF_LIST
fi
if [[ "$ONE_OF_LIST" -eq "$day" ]]
then
echo "Eroor: snapshot auto_$ONE_OF_LIST exist. Stop script execution."
exit 1
fi
done
### Create snapshot ###
btrfs subvolume snapshot / $spath"auto_"$day
### End ###
echo "Snapshot succesful created"
echo "Date_end: `date +%Y-%m-%d-%H-%M-%S`"
exit 0
Скрипт № 3, создает копию LVM тома:
#!/bin/bash
set -e
echo "Date_start: `date +%Y-%m-%d-%H-%M-%S`"
### Vars ###
day=$((`date +%s` / (60*60*24)))
dayexp=21
#Имя копируемого LVM тома
path="/dev/virt_image_array/win_home_system"
spath="/dev/virt_image_array/backup_lvm1"
dpath="/mnt/backup/lvm1/"
### Delete Old Backups ###
find $dpath -type d 2>/dev/null| awk '{FS="/"} {print $5}'| sort|uniq | while read ONE_OF_LIST
do
if [[ "$ONE_OF_LIST" -lt "$day - $dayexp" ]] && [[ -n "$ONE_OF_LIST" ]]
then
echo "remove: $dpath$ONE_OF_LIST"
rm -rf $dpath$ONE_OF_LIST
fi
done
### Check exist snapshot ###
#Проверяем отсутвие снапшота, удаляем, если находим
if (( "`ls /dev/virt_image_array |grep backup_lvm1|wc -l`" > 0 ))
then
echo "Warning: Snapshot exist, deleting"
lvremove --autobackup y -f $spath
fi
### Create snapshot ###
#Создаем снапшот, если на том идет активная запись, то можно увеличить место на снапшоте. Я сделал 10 Gb.
lvcreate --size 10G --snapshot --name backup_lvm1 /dev/virt_image_array/win_home_system
#Если у вас при создании снапшота спрашивает подтверждения на вайп сигнатуры используйте вариант с echo
#echo "y"| lvcreate --size 10G -A y --snapshot --name backup_lvm1 /dev/virt_image_array/win_home_system
### DD ###
#Можно поиграться с bs, у меня быстрей всего работает с 16M
dd if=$spath of=$dpath$day bs=16M
### Delete snapshot ###
lvremove --autobackup y -f $spath
echo "Backup succesful complete"
echo "Date_end: `date +%Y-%m-%d-%H-%M-%S`"
exit 0
Поскольку скрипты, бэкапящие данные из /mnt/data аналогичны скриптам 1 и 2 думаю нет необходимости их писать.
Добавляем в crontab и определяем, как часто создавать бэкапы (в моем примере бэкап создается раз в неделю, снапшоты раз в день).
20 01 * * 1 /usr/bin/backup_root.sh >> /var/log/backup_root.log 2>&1
50 01 * * 1 /usr/bin/backup_lvm1.sh >> /var/log/backup_lvm.log 2>&1
20 01 * * * /usr/bin/snapshot_root.sh >> /var/log/snapshot_root.log 2>&1
Что еще можно прикрутить:
- Если нужно создавать больше бэкапов, а места нет, то можно поставить ФС с дедупликацией (например Opendedup), но снизится надежность хранения данных.
- В качестве хранилища может выступать папка подключенная по NFS или sshfs.
- Если нужно создавать бэкапы или снапшоты чаще, чем раз в день можно считать не дни с 1970 года, а часы (костыль, будет еще непонятней за какую дату бэкап).
Автор: larrabee