Доброе время суток. Как-то давно я опубликовал статью о бэкапе в Dropbox. Настало время продолжить и даже развернуть тему немного в другую сторону. Сегодня я постараюсь описать метод резервного копирования более универсальный и гибкий, чем было мной ранее предложено. Статья довольно сложная и требует от вас хотя бы поверхностных знаний по администрированию unix-систем, ну, или большого желания и много времени. Хотя я постарался кое-что разжевать и перемолоть, чтобы совсем мозг не выносить юнным читателям. Приступим.
Речь сегодня пойдёт об утилите под названием Duplicity. Она предназначена специально для резервного копирования данных и обладает очень богатым функционалом. Она легко запакует указанные директории в формат tar, зашифрует, подпишет и загрузит результат своей работы куда вам угодно, будь то на локальный или удаленный файловый сервер. При этом для подписи и шифровки используется GnuPG, что даёт защиту от похищения и модификации. Также Duplicity делает инкрементальные бекапы используя библиотеку librsync, а это значит, что только первый архив содержит полностью все файлы, все последующие будут включать только изменённые файлы, что повзволит более эффективно использовать дисковое пространство и трафик.
Для передачи данных Duplicity поддерживает множество способов:
- локальные директории;
- ssh/scp;
- rsync;
- ftp;
- HSI;
- WebDAV;
- Tahoe-LAFS;
- Amazon S3.
В общем, утилитка очень гибкая и возможностей у ней уйма. К тому же присутствует она во всех репозиториях более менее распространённых дистрибутивов Linux. И чтобы её установить нужна всего одна команда, например, в Debian:
$ apt-get install duplicity
Генерация ключа
Поскольку для шифрования и подписи используется GnuPG, то сперва мы немного (много) поговорим о ключах и о их генерации. Но если вы и так всё знаете об этом, то можно этот пункт пропустить!
Вообще, теорию можете и в wiki почитать, а тут я только выдержку приведу для внесения ясности:
GnuPG шифрует сообщения, используя асимметричные пары ключей, генерируемые пользователями GnuPG. Открытыми ключами можно обмениваться с другими пользователями различными путями, в том числе и через интернет с помощью серверов ключей. Также GnuPG позволяет добавлять криптографическую цифровую подпись к сообщению, при этом целостность и отправитель сообщения могут быть проверены.
Думаю это ключевая фраза. Если что не понятно, то читаем самостоятельно на стороне. А наша задача на данный момент это сгенерировать подобные ключи. Для начала процесса генерации запустите следующую команду:
$ gpg --gen-key
Кстати, если оказалось, что данной команды у вас нет, то нужно установить пакет gnupg (в терминале apt-get install gnupg
). В процессе генерации вам зададут несколько вопросов о длине пароля, парольной фразе и др. Это думаю вы сами сообразите, ну, или подглядите у меня:
$ gpg --gen-key
gpg (GnuPG) 1.4.12; Copyright (C) 2012 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"
Real name: Home Server
Email address: root@homeserver
Comment: Home Server Backup
You selected this USER-ID:
"Home Server (Home Server Backup) <root@homeserver>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.
И тут настаёт самый важный момент: вас попросят ввести фразу-пароль. Введите, пожалуйста, что-то совсем невменяемое и желательно не на естественном языке т.к. в естественных языках не хватает энтропии и случайности. Даже замена символов в словах не подходит. Просто случайная строка из набора всех типов символов на клавиатуре. Желательно. Это ваша безопасность, потому что всё остальное, что так или иначе касается естественных языков, «легко» подбирается.
После ввода фразы начнётся непосредственно сама генерация gpg-ключей. Может так получиться, что в системе не будет хватать энтропии для генерации «случайных» значений. Если это произойдёт, то вывалится следующая надпись:
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
Для того, чтобы достичь нужного уровня энтропии необходимо чем-то загрузить процессор. Для этого откройте другую консоль этого же сервера и выполните следующую команду:
$ while true; do find / -type f; done
Пока бесконечный цикл бегает – энтропия растёт. И через некоторое время gpg-ключи уже будут сформированы. Ждите. По окончанию вывалится вся необходимая информация:
gpg: key 1731EA94 marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
pub 4096R/1731EA94 2014-01-31
Key fingerprint = 867B 4675 2693 CA7C 34D9 E394 FDF1 0274 1731 EA94
uid Home Server (Home Server Backup) <root@homeserver>
sub 4096R/79FA3B1E 2014-01-31
В данном примере, ключ 1731EA94 является публичным и будет использоваться для шифрования и подписания в Duplicity. Так же ещё его называют ID.
Это всё хорошо, но допустим самый плохой расклад: дата-центр с сервером сгорел после митиаритного дождя, который спровоцировал землетрясение, которое спровоцировало цунами, что потушило пожары, но в целом ситуацию не улучшило. После этого, если вы выжили, то скорее всего захотите восстановить свои фоточки с котиками, что ранее зарезервировали как раз на этот случай в том же Dropbox или Amazon S3. И делать это вы будете конечно же на другом компьютере, который не о ключах не о бэкапах не знает.
И тут надо понимать, что вы должны иметь на руках свой серкетный ключ для расшифровки бекапа. Обычно все подобные ключи (публичные и приватные) хранят в секретных местах, недоступных из сети, например, на диске/флешке в сейфе. Для переноса на носитель сперва их нужно экспортировать:
$ gpg --output mygpgkey_pub.gpg --armor --export 1731EA94
$ gpg --output mygpgkey_sec.gpg --armor --export-secret-key 1731EA94
После этого файлы с ключами копируете на носитель или на удалённый хост:
$ scp mygpgkey_pub.gpg mygpgkey_sec.gpg user@remotehost:~/keys/
И как только вам понадобятся ключи (вдруг метеориты, цунами и т.д.) вы их можете просто импортировать в любую другую систему:
$ gpg --import ~/keys/mygpgkey_pub.gpg
$ gpg --allow-secret-key-import --import ~/keys/mygpgkey_sec.gpg
После чего они могут быть использованы по назначению: для шифрования, дешифрования и подписания. Главное проверьте, чтобы они точно были:
$ gpg --list-keys
/root/.gnupg/pubring.gpg
------------------------
pub 4096R/1731EA94 2014-01-31
uid Home Server (Home Server Backup) <root@homeserver>
sub 4096R/79FA3B1E 2014-01-31
Правда, по большому счёту, все эти действия по переносу и пересылке закрытых ключей не секьюрны и делать это не желательно. Но все мы это делаем и никуда от этого не деться, но по возможности минимизируйте эти действия.
Ох, так много про ключи, наверно лучше даже отдельную статью про них написать. Если кто хочет, то в комментариях попросите – напишу. Заодно и это туда перенесу.
Резервное копирование файлов
Всё, у вас есть gpg-ключи и вы готовы приступить к созданию защищённых резервных копий с помощью Duplicity. Всё что вам нужно указать этой утилитке – это используемый вами ключ, директорию (-ии) для резервирования и конечную директорию, куда всё сложить:
$ duplicity --encrypt-key=1731EA94 --sign-key=1731EA94 /home/user/site file:///home/user/backup
Для шифрования и подписания вас попросят ввести фразу-пароль. После этого начнётся процесс бекапа, при этом прогресс никак не будет отображаться. А первоначальный бэкап может занять довольно большое время (в зависимости от исходных данных). Если вы хотите видеть хоть какой-то прогресс, то в соседнем терминале примените в конечной директории следующую команду:
$ watch du -sh
Она покажет в прямом эфире размер данной директории. Будете видеть, как она раздувается.
Все последующие бэкапы этой директории будут инкрементальными, и включат в себя только то, что изменилось с последнего раза. Так что, если вы добавите или измените только один файл, то будет зарезервирован только он. При этом в дальнейшем во время восстановления вы можете указать какую версию файла вы хотите восстановить.
В примере выше указано, как можно зарезервировать на локальный сервер, но в другую директорию. Это может понадобиться, если вы всё потом будете складывать в Dropbox, например. Но по большому счёту, потребуется удалённое складирование по протоколам sftp, ssh и др. Это всё очень просто делается, например:
$ duplicity –encrypt-key=1731EA94 –sign-key=1731EA94 /home/user/site sftp://user@backupserver.example.net/backup
Так можно использовать любой протокол. Но все примеры я приводить не буду, потому что вы сами можете почитать о них в документации и не забудьте глянуть примеры.
Восстановление резервной копии
Восстановить резервную копию так же просто, как и сделать её. Но для начала, вам может потребоваться взглянуть на список файлов в резервной копии. Для этого введите следующую команду:
$ duplicity list-current-files file:///home/user/backup
Вывалится список файлов с датами последнего обновления каждого. Убедившись, что всё в порядке и ваши самые нужные файлы присутствуют вы их можете легко и быстро все разом восстановить указав конечную папку:
$ duplicity restore file:///home/user/backup /home/user/restore
Вас попросят ввести фразу-пароль после чего восстановление будет начато. При этом, даже если целевая директория не была создана, то Duplicity обо всём позаботится.
А если вдруг понадобится какой-то конкретный файл или дочерняя директория (из /home/user/site) на момент 5-дневной давности, то нет ничего проще:
$ duplicity -t 5D --file-to-restore top/secret file:///home/user/backup /home/user/restore/secret_t5D
При этом, даже если сервер будет утерян безвозвратно, то с такой же лёгкостью бэкапы могут быть восстановлены на любом другом компьютере из удалённых хранилищ. Лишь бы приватный ключ был импортирован (о чём мы выше говорили).
Автоматизация резервного копирования
Теперь когда вы обо всём имеете хотя бы примерное представление пришло время автоматизировать весь процесс организации резервных копий. Автоматизация – это значит cron, потому хотелось бы уложить всё в одну команду. Но мы не можем одной командой выполнить резервирование т.к. у нас могут запрашиваться разные данные: фразу-пароль, ftp-пароль и др., в зависимости от цели резервирования. Для этого придётся написать небольшой bash-скрипт, в котором можно поместить необходимые данные в переменные среды. Например, если автоматизировать команду резервирования выше, то получиться следующий скрипт:
#!/bin/sh
export PASSPHRASE=gpgpassphrase
duplicity –encrypt-key=1731EA94 –sign-key=1731EA94 /home/user/site file:///home/user/backup
unset PASSPHRASE
exit 0
В переменной среды PASSPHRASE и находиться наша парольная фраза. Вроде всё хорошо. Но если захочется расширить функционал скрипта (сделать ему поддержку различных протоколов, удаление старых копий и др.), то получиться очередной велосипед, к тому же скорее всего не самый лучший. Но выход есть. Например, я использую bash-скрипт, что лежит тут на GitHub’е. Его соль в том, что сперва вы пишите свой конфиг, который содержит параметры резервирования (парольные фразы, пароли, настройки бэкапа и др.). После этого вызываете этот скрипт с указанием конфига. Как им пользоваться описано в репозитории и пример самого конфига там же есть. Но на всякий случай я приведу свой конфиг (без комментариев):
ENCRYPTION='yes'
PASSPHRASE="super_secret_pass_phrase"
GPG_ENC_KEY="1731EA94"
GPG_SIGN_KEY="1731EA94"
ROOT="/"
DEST="file:///home/user/backup"
INCLIST=( "/home" \
"/etc" \
"/var/log" \
)
STATIC_OPTIONS="--full-if-older-than 1M"
CLEAN_UP_TYPE="remove-all-but-n-full"
CLEAN_UP_VARIABLE="5"
LOGDIR="/home/user/logs/"
LOG_FILE="duplicity-`date +%Y-%m-%d_%H-%M`.txt"
LOG_FILE_OWNER="backup:backup"
VERBOSITY="-v3"
Далее вызывается сам bash-скрипт:
$ duplicity-backup.sh -c /etc/duplicity-backup.conf --backup
Указывается конфиг и задача. При этом задачи могут быть разные: создать бэкап, верифицировать бэкап, показать список файлов бэкапа и др. Этот скрипт поддерживает весь функционал Duplicity, фактически, это полноценная обёртка для него.
А вообще-то, подобных скриптов много. Хотя большая часть не такая функциональная. Можете сами поискать, вдруг чего лучше найдёте.
Вот казалось бы и всё: настроим конфиг и одну команду пихаем в крон. Но не стоит забывать про базы данных. Желательно сформировать дамп базы и разместить его так же в резервной копии. Базы данных можно паковать специальными утилитами или самописными bash-скриптами. Но для MySQL я обычно использую встроенную утилиту mysqldump. C помощью неё я собираю все базы данных MySQL и пакую в архив:
$ mysqldump --single-transaction --routines --events --triggers --add-drop-table --extended-insert -uroot -h127.0.0.1 -p1234 -A | gzip -9 > /home/dump/mysql/mysql_all_databases_$(date +"%H:%M_%d-%m-%Y").sql.gz
Также вы можете, например, ещё запаковать базу из MongoDB в отдельный файл:
$ mongodump --host 127.0.0.1:28017 --db database --username user --password pass --out - | gzip -9 > /home/dump/mongodb/mongodb_database_$(date +"%H:%M_%d-%m-%Y").gz
В общем, смысл в том, чтобы сделать дамп для своей базы и расположить его в той директории, которая попадёт в резервную копию.
А теперь к сути, чтобы произвести всё резервное копирование я просто объединяю три команды: удаление предыдущего дампа базы, создание нового дампа и непосредственно само резервирование. Пихаю это всё в cron. Получается нечто подобное:
* 3 * * * rm -f /home/dump/mysql/* && /usr/bin/mysqldump --single-transaction --routines --events --triggers --add-drop-table --extended-insert -uroot -h127.0.0.1 -p1234 -A | gzip -9 > ~/backup/mysql_all_databases_$(date +"%H:%M_%d-%m-%Y").sql.gz && /shell/duplicity-backup.sh -c /etc/duplicity-backup.conf --backup
Каждый раз удаляя предыдущий дамп базы я экономлю место, в противном случае каждый бэкап содержал бы повтоные дампы. А так, на один бекап создаётся один актуальный дамп. И волки сыты и овцы целы.
И ещё, поскольку конфиг /etc/duplicity-backup.conf содержит все пароли и явки, то я рекомендую как минимум установить жёсткие права на этот файл, чтобы доступ и исполнение имел только тот кто выполняет резервирование, например, для root:
$ chown root: /etc/duplicity-backup.conf
$ chmod 700 /etc/duplicity-backup.conf
Кстати, если у вас Gnome Desktop и хочется графическую оболочку для этой приблуды, то она есть такая – Déjà Dup. Возможности примерно те же плюс составление расписаний (вместо cron).
Заключение
Прошу прощение, за сумбурное изложение и поток необузданного сознания. Давно не писал и немного потерял хватку. Но как вам утилитка? Замечательная, не так ли? Она круче всего, что я видел до этого и всего, что я делал. Очень гибкая и функциональная! Тот кто её писал явно съел целый выводок собак на этом. Плюс этот замечательный bash-костыль и совсем хорошо. Duplicity – то что доктор прописал.
На этом у меня всё. И да, само собой Duplicity можно использовать и без шифрования, но это не наш путь. Нужна надёжность и секьюрность. Так что, ни шагу назад! И да прибудут с вами бэкапы!