Быстрая реализация инкрементального бэкапа на Amazon S3

:

После переезда моего сайта с shared-хостинга на виртуальный сервер в облаке вплотную встал вопрос об архивации данных: если раньше о ежедневном бэкапе беспокоился хостер, то теперь эти заботы целиком легли на плечи администратора. Так как хранить большие архивы на своем сервере не только небезопасно, но и (иногда) накладно, было решено копировать основную массу файлов на сервис S3 от Amazon. Под катом описывается мой способ реализации инкрементального бэкапа. Способ достаточно нубовский, но желающие повторить его без труда найдут пути тонкой настройки под свои нужды.

Сначала определимся с задачами


Нам необходимо:
1. Делать ежедневные архивы веб-серверов (каталоги сайтов и базы данных). Необходимо хранить архивы за последний месяц.
2. Делать инкрементальные архивы — для экономии дискового пространства. Делать полный архив еженедельно, потом 6 архивов измененных файлов, потом цикл повторить.
3. Хранить копии архивов на стороннем сервере (Amazon S3). На локальном сервере будем оставлять архив за неделю, остальные архивы будут присутствовать только на сервере.
Мой сервер работает под ОС Debian, для других операционных систем, возможно, нужно будет внести соответствующие поправки в команды установки и пути файлов.

Необходимые компоненты


backupninja: программа служит удобной оберткой для других утилит, позволяет централизованно управлять процессом архивации.
Установка: apt-get install backupninja

duplicity: утилита для создания инкрементальных бэкапов. Умеет работать с удаленными серверами.
Установка: apt-get install duplicity

boto: API для работы с сервисами Amazon Web Services. Используется duplicity для архивации напрямую на сервис AWS S3
Установка: apt-get install python-boto

s3cmd: утилита для работы с сервисом Amazon S3 из командной строки.
Установка: apt-get install s3cmd

Реализация


Начать необходимо с регистрации на AWS. Процесс не представляет никаких сложностей, хорошо описан maxout в топике Быстрая реализация резервного копирования в Amazon S3. В Урюпинске регистрация прошла на ура с картой местного отделения сбера, значит и в других городах и селах проблем не возникнет.

Далее настраиваем backupninja. Главный конфигурационный файл программы — /etc/backupninja.conf Все опции в файле очевидны, приводить их здесь нет смысла. В простейшем случае там даже не нужно ничего менять, разве что настроить уровень записи в логи (от фатальных ошибок до отладочной информации) и состав отчета о выполненных заданиях, отсылаемого на почту админу.

Настройки для каждого отдельного задания backupninja хранит в отдельных файлах в каталоге /etc/backup.d (по умолчанию). Имени файла предшествует числовой префикс, задающий порядок выполнения задания. Задания в файлах без префикса и с префиксом 0 выполняться не будут. Задания в файлах с одинаковым префиксом будут выполняться параллельно, каждое задание с префиксом больше чем у предыдущего будет выполняться после завершения заданий с меньшим префиксом. Таки образом мы имеем возможность, задавая префикс файла, контролировать очередность выполнения заданий.

Кроме префикса, файлы заданий должны иметь расширение, соответствующее типу задания.

Backupninja имеет оболочку для настройки и тестирования конфигурации заданий ninjahelper. Мне кажется, что создавать и изменять задания удобнее в текстовом редакторе, а тестировать — из оболочки.

Итак, файл конфигурации задания архивации баз данных. Я архивирую БД в два шага: сначала делаю дампы всех баз, затем из дампов делаю инкрементальные архивы. Шаг первый, файл 20-all.mysql (я копировал болванки файлов из /usr/share/docs/backupninja/examples и вносил в них необходимые изменения)

### backupninja MySQL config file ###

# hotcopy = < yes | no > (default = no)
# make a backup of the actual database binary files using mysqlhotcopy.
hotcopy = no

# sqldump = < yes | no > (default = no)
# make a backup using mysqldump. this creates text files with sql commands
# sufficient to recontruct the database.
#
sqldump = yes

# sqldumpoptions = <options>
# (default = --lock-tables --complete-insert --add-drop-table --quick --quote-na
# arguments to pass to mysqldump
# sqldumpoptions = --add-drop-table --quick --quote-names

# compress = < yes | no > (default = yes)
# if yes, compress the sqldump output.
compress = yes

# dbhost      = <host> (default = localhost)

# backupdir = <dir> (default: /var/backups/mysql)
# where to dump the backups. hotcopy backups will be in a subdirectory
# 'hotcopy' and sqldump backups will be in a subdirectory 'sqldump'
backupdir = /home/backups/mysql

# databases = < all | db1 db2 db3 > (default = all)
# which databases to backup. should either be the word 'all' or a
# space separated list of database names.
databases = all

user = root

В конфигурации я указал что:
— необходимо делать дамп с помощью mysqldump;
— дамп необходимо сжать;
— сжатые файлы сохранить в каталоге /home/backups/mysql
— необходимо сделать бэкап всех баз данных

После выполнения задания в каталоге /home/backups/mysql появятся файлы с именами баз данных, сжатые gzip’ом.

Следующим заданием мы делаем инкрментальный архив баз с помощью duplicity, файл 30-databases.dup (я приведу лишь измененные мною опции; вам необходимо скопировать файл конфигурации полностью из /usr/share/docs/backupninja/examples/example.dup и сделать изменения в нем, иначе задание не выполнится)

## дополнительные опции для duplicity
## я не шифрую архив, увеличиваю размер тома до 512 мегабайт, 
## задаю путь и имя для кэща duplicity
options = --no-encryption --volsize 512 --archive-dir /home/backups/duplicity --name vds1.databases

## временный каталог. учтите, что backupninja требует на диске 
## свободное место не менее чем размер тома
tmpdir = /home/backups/tmp

[source]
## что включаем в бэкап. можно задать несколько источников, по одному в каждой строке
include = /home/backups/mysql/sqldump

## если необходимо что-то исключить из архива -указываем здесь
#exclude = /www/urup.ru/sxd/backup

[dest]
## инкрементальный бэкап (это значение по умолчанию)
incremental = yes

## Сколько дней делать инкрементальные бэкапы перед тем как опять сделать полный бэкап
increments = 7

## Сколько всего дней хранить бэкапы. Мы храним на локальном сервере архивы за 7 последних дней.
keep = 7

## Куда складывать бэкапы. duplicity умеет сохранять на разные сервисы,
## в том числе напрямую на AWS, но нам нужно хранить часть архивов на
## локальном диске, поэтому копировать файлы на Amazon будем 
## в отдельном задании
desturl = file:///home/backups/mysql

Еще раз замечу, что я привел только измененные строки конфигурационного фала. Для того чтобы задание работало необходимо скопировать конфигурацию полностью из /usr/share/docs/backupninja/examples/example.dup и уже в этом файле сделать необходимые изменения.

Аналогичным образом делаем задания для архивации директорий веб-серверов. Не забываем о возможности задавать несколько источников для включения в архив и несколько для исключения, по одному на строчку конфигурации. Я архивирую каждый сайт в отдельном задании, каждый архив складываю в отдельный каталог с именем сайта в /home/backups/files/www/

При создании архивов, если для вас это важно, вы можете зашифровать файлы с помощью GnuPG. В этом случае необходимо убрать опцию --no-encryption.

Последнее задание будет копировать созданные файлы архивов на сервер AWS S3. Файл называется 50-upload.sh и представляет из себя обычный shell-скрипт:

#!/bin/sh

# синхронизируем локальные копии архивов с копиями на амазоне
s3cmd sync \
 --bucket-location=EU \
 --exclude 'sqldump/*' \
 /home/backups/files \
 /home/backups/mysql \
 s3://vds1.backup

# удаляем архивы старше 30 дней на амазоне
duplicity --no-encryption --s3-use-new-style --archive-dir /home/backups/duplicity --name vds1.databases.s3 --force remove-older-than 30D s3+http://vds1.backup/mysql

Для корректной работы duplicity с сервисами амазона необходим установить и настроить boto. Настройка заключается в указании учетных данных в файле /etc/boto.cfg
[Credentials]
aws_access_key_id = *
aws_secret_access_key = *

Восстановление из архивов


Получаем сведения об архиве:
duplicity --no-encryption --s3-use-new-style collection-status s3+http://vds1.backup/mysql

Распаковываем локальный архив:

duplicity --no-encryption file:////home/backups/mysql /home/backups/mysql/sqldump

Первый параметр — URL архива, второй — каталог, в который будут распакованы файлы. Существующие файлы не будут перезаписаны, если только не указана опция --force

Распаковываем архив с сервера Amazon:

duplicity --no-encryption --s3-use-new-style s3+http://vds1.backup/mysql /home/backups/mysql/sqldump

Извлекаем один файл из архива.

duplicity --no-encryption --file-to-restore home/backups/mysql/sqldump/mysql.sql.gz --force file:///home/backups/mysql /home/backups/mysql/sqldump/mysql1.sql.gz

Файл, который необходимо распаковать, указывается ключом --file-to-restore вместе с полным относительным путем (без лидирующего слэша). Первый параметр — URL архива, второй — полный путь к распаковываемому файлу. Если файл уже существует то он не будет перезаписан, если только не указана опция --force