Привет.
Тут я расскажу о самом простом способе создания бекапов БД на сервере, о выгрузке их в Яндекс.Диск. Я написал скрипт, который всё это выполняет.
Он приведён поэтапно, можешь скопировать пункты 4.1-4.5, убрав оттуда заголовки, и получишь готовый скрипт. Или можешь скачать, ссылка будет в конце. А лучше прочитать пост и вникнуть в суть происходящего.
ОС на сервере — CentOS 6.7
Версия СУБД — MySQL 5.5 (да, знаю, старая)
Скрипт будет вертеться на сron, конечно же. Это чтобы само всё. Но это в конце.
Монтирование Я.Диска в систему.
1.1 Ставим davfs2 систему:
yum install davfs2
1.2 Создаём папку, в которую у нас будет монтироваться удалённое хранилище:
mkdir /mnt/yadisk
1.3 В файл /etc/davfs2/secrets пишем:
/mnt/yadisk полныйадресemail@yandex.ru пароль
1.4 В файле /etc/fstab указываем настройки монтирования хранилища (в одну строку, конечно):
https://webdav.yandex.ru/ /mnt/yadisk davfs user,rw,_netdev,file_mode=600,dir_mode=700 0 1
В конце файла должна быть пустая строка.
Разгадку этого заклинания можно разобрать вот тут: rus-linux.net (отлично всё расписано)
1.5 Тестируем:
mount /mnt/yadisk # монтирование
df -h /mnt/yadisk # проверка свободного места
В результате должно отобразиться свободное место на Яндекс.Диске, типа того:
[root@server ~]# mount /mnt/yadisk
[root@server ~]# df -h /mnt/yadisk
Filesystem Size Used Avail Use% Mounted on
https://webdav.yandex.ru/
10G 1,8G 8,3G 18% /mnt/yadisk
По факту мы имеем обычную с виду директорию, куда можно писать всякое.
umount /mnt/yadisk # Размонтируем диск
Три-четыре. Закончили упражнение.
Делаем дампы базы данных
Дамп базы данных создаётся штатной утилитой mysqldump, которая идёт в комплекте с MySQL. Подробнее о ней можно прочесть здесь: MySQL.ru. Я же покажу здесь только необходимое мне самому.
Синтаксис всей команды, например, таков:
mysqldump --host=localhost --user=root --password=1234 -q --default-character-set=utf8 mybigdatabase > /home/mybigdatabase.sql
Разберёмся с этой командой:
—user — Имя пользователя БД
—password — Его пароль
—host — Адрес базы данных (скорее всего это localhost)
—default-character-set — Кодировка текста дампа (скорее всего, это будет utf8)
-q — Вывод текста дампа непосредственно на стандартный вывод stdout без буферизации запроса. Вообще, этот ключик нам необязателен, ибо у нас будет прямая запись вывода в файл. Но без него оно нафиг не надо, а с ним пусть будет.
mybigdatabase — Имя базы данных
> — Перенаправление вывода с перезаписью
/home/mybigdatabase.sql — …например, в этот файл
Можешь поиграться, чего-нибудь подампить, если есть чего.
Упаковка дампа
Используем команду gzip таким простым образом:
gzip /home/mybigdatabase.sql
В этой же папке образуется файл mybigdatabase.sql.gz, который меньше исходного на порядки.
Можно использовать tar, но придётся вносить правки в скрипт. Если хочешь заморочиться — пожалуйста, но особой разницы не будет.
tar -czf mybigdatabase.tar.gz /home/mybigdatabase.sql
Всё.
Объединение вышеописанного
Теперь определяемся что и зачем будет делать наш скрипт. Всё очень просто:
- Инициализация — готовим переменные, параметры, пути, адреса;
- Создание дампа — собственно, бекапа БД;
- Упаковка дампа — для экономии места;
- Отправка бэкапа в облака — на случай смерти локального файла:
- Монтирование хранилища;
- Копирование файла в хранилище;
- Размонтирование хранилища;
- Завершение — выводим сообщения с результатами и итогами работы скрипта.
Дальше я буду описывать это уже самими командами.
Создаём файл db_backup.sh там, где душе угодно. Мне угодно в домашней папке рута.
Пишем в него нижеследующее.
4.1 Инициализация:
#!/bin/bash
# Данные для работы с БД
DBHOST=localhost # Адрес БД
DBUSER=root # Имя пользователя базы данных
DBPASSWD=1234 # Пароль от базы данных
DBNAME=mybigdatabase # Имя базы данных для резервного копирования
DBCHARSET=utf8 # Кодировка базы данных (utf8)
# Даты
DATE=`date +%F` # Префикс для структурирования бекапов (формат: 2017-05-22)
DATETIME=`date +%F-%H-%M-%S` # Полная текущая дата и время (формат: 2017-05-22-12-23-34)
# Локальное хранилище
LOCALDIR=/root/db_backup # Полный путь к каталогу, где будут храниться резервные копии
LOCALPATH=$LOCALDIR/$DATE # Полный путь к папке за сегодня
LOCALFILE=$LOCALPATH/$DBNAME-$DATETIME.sql # Полный путь к файлу дампа
LOCALFILEGZ=$LOCALFILE.gz # Полный путь к архиву дампа
# Путь к бекапу будет выглядеть так:
# /root/db_backup/2017-05-22/mybigdatabase-2017-01-01-12-23-34.sql.gz
# Облачное хранилище
CLOUDUSE=1 # Копировать ли в облако? Закомментировать строку, если не надо
CLOUDMNT=/mnt/yadisk # Точка монтирования облака относительно корня
CLOUDDIR=db_backup # Папка в облаке, куда будут лететь файлы (внутри папки CLOUDMNT, т.е. без / в начале)
CLOUDPATH=$CLOUDMNT/$CLOUDDIR/$DATE # Полный путь к папке текущей даты в облаке относительно корня
CLOUDFILE=$CLOUDPATH/$DBNAME-$DATETIME.sql # Полный путь к файлу дампа в облаке
CLOUDFILEGZ=$CLOUDFILE.gz # Полный путь к архиву в облаке
# Путь к бекапу на примонтированном хранилище будет выглядеть так:
# /mnt/yadisk/db_backup/2017-05-22/mybigdatabase-2017-01-01-12-23-34.sql.gz
# Начало процесса
echo "[-----------------------------[`date +%F-%H-%M-%S`]-----------------------------]"
echo "[`date +%F-%H-%M-%S`] Starting backup"
4.2 Создание дампа:
if ! [[ -d $LOCALPATH ]]; then # Если нет папки за сегодня
mkdir $LOCALPATH 2> /dev/null # создаём её, ошибки игнорируем
fi
echo "[`date +%F-%H-%M-%S`] Generate a database dump: '$DBNAME'..."
mysqldump --user=$DBUSER --host=$DBHOST --password=$DBPASSWD -q --default-character-set=$DBCHARSET $DBNAME > $LOCALFILE
if [[ $? -gt 0 ]]; then
# если дамп сделать не удалось (код завершения предыдущей команды больше нуля) - прерываем весь скрипт
echo "[`date +%F-%H-%M-%S`] Dumping failed! Script aborted."
exit 1
4.3 Упаковка дампа:
else # иначе - упаковываем его
echo "[`date +%F-%H-%M-%S`] Dumping successfull! Packing in GZIP..."
gzip $LOCALFILE # Упаковка
if [[ $? -ne 0 ]]; then # Если не удалась
echo "[`date +%F-%H-%M-%S`] GZipping failed! SQL-file will be uploaded."
GZIP_FAILED=1 # Создаём флажок, что упаковка сорвалась
else
echo "[`date +%F-%H-%M-%S`] Result file: $LOCALFILEGZ"
fi
4.4 Отправка в облака:
if [[ $CLOUDUSE -eq 1 ]]; then # Если задано копирование в облако - делаем всякое такое
mount | grep "$CLOUDMNT" > /dev/null # Проверяем примонтировано ли уже у нас облако (вывод не важен)
if [[ $? -ne 0 ]]; then # Если нет
mount $CLOUDMNT # значит монтируем
fi
if [[ $? -eq 0 ]]; then # если монтирование успешно - копируем туда файл
echo "[`date +%F-%H-%M-%S`] Cloud: successfully mounted at $CLOUDMNT"
echo "[`date +%F-%H-%M-%S`] Cloud: copying started => $CLOUDFILEGZ"
if ! [[ -d $CLOUDPATH ]]; then # Если в облаке нет папки за сегодня
mkdir $CLOUDPATH 2> /dev/null # создаём её, ошибки игнорируем
fi
if [[ -f $LOCALFILEGZ && GZIP_FAILED -ne 1 ]]; then # Если у нас архивирование выше не сорвалось
cp -R $LOCALFILEGZ $CLOUDFILEGZ # Копируем архив
else
cp -R $LOCALFILE $CLOUDFILE # Иначе - копируем большой тяжёлый дамп
fi
if [[ $? -gt 0 ]]; then # Если не скопировался - просто сообщаем
echo "[`date +%F-%H-%M-%S`] Cloud: copy failed."
else # Если скопировался - сообщаем и размонтируем
echo "[`date +%F-%H-%M-%S`] Cloud: file successfully uploaded!"
umount $CLOUDMNT # Размонтирование облака
if [[ $? -gt 0 ]]; then # Сообщаем результат размонтирования (если необходимо)
echo "[`date +%F-%H-%M-%S`] Cloud: umount - failed!"
fi # Конец проверки успешного РАЗмонтирования
fi # Конец проверки успешного копирования
else # если монтирование НЕуспешно - сообщаем
echo "[`date +%F-%H-%M-%S`] Cloud: failed to mount cloud at $CLOUDMNT"
fi # Конец проверки успешного монтирования
fi # Конец проверки необходимости выгрузки в облако
4.5 Завершение
fi # Конец проверки успешного выполнения mysqldump
echo "[`date +%F-%H-%M-%S`] Stat datadir space (USED): `du -h $LOCALPATH | tail -n1`" # вывод размера папки с бэкапами за текущий день
echo "[`date +%F-%H-%M-%S`] Free HDD space: `df -h /home|tail -n1|awk '{print $4}'`" # вывод свободного места на локальном диске
echo "[`date +%F-%H-%M-%S`] All operations completed!"
exit 0 # Успешное завершение скрипта
5. Устанавливаем задачу в cron
Из под root запускаем crontab -e. Подробности по работе с crontab можно найти здесь: Codenet.ru | Ubuntu.ru
В окне запустившегося редактора пишем нижеследующее:
# в качестве командного интерпретатора использовать /bin/sh
SHELL=/bin/sh
# результаты работы отправлять по этому адресу
MAILTO=example@site.com
# Запуск скрипта дампа боевой БД и запись в лог
0 8,20 * * * bash ~/db_backup.sh >> ~/db_backup/db_backup.log
Важна последняя команда:
- 0 — в ноль минут 8,20 — в 8 часов утра и 20 часов вечера (без пробела) * — каждый день * — каждой недели * — каждого месяца;
- запускается интерпретатор bash;
- который получает путь к скрипту ~/db_backup.sh (а равно /root/db_backup.sh, если всё происходит под рутом);
- выполняет его;
- а вывод дописывается (>>) в файл лога ~/db_backup/db_backup.log
Сразу разъясню простой момент с угловыми скобками:
- > (равносильно 1> ) — перенаправление всего вывода в указанное место с перезаписью. Существующий файл перезаписывается полностью, отсутствующий — создаётся.
- 2> — перенаправление вывода ошибок stderr в указанное место. Если отправить в /dev/null, то сообщений об ошибках в выводе на экране не окажется.
- >> — перенаправление вывода без перезаписи. Если файла нет — он создаётся, если файл есть — результат дописывается в его конец. Подробнее о перенаправлениях выводов можно прочесть здесь: OpenNET.ru. Там очень богатый функционал и синтаксис.
Пример конечного лога
[-----------------------------[2017-01-01-17-40-50]-----------------------------]
[2017-01-01-17-40-50] Run the backup script...
[2017-01-01-17-40-50] Generate a database backup: 'mybigdatabase'...
[2017-01-01-17-44-17] Dumping successfull! Packing in GZIP...
[2017-01-01-17-47-36] Result file: /root/db_backup/2017-01-01/mybigdatabase-2017-01-01-17-40-50.sql.gz
[2017-01-01-17-47-38] Cloud: successfully mounted at /mnt/yadisk.
[2017-01-01-17-47-38] Cloud: copying started => /mnt/yadisk/db_backup/2017-01-01/mybigdatabase-2017-01-01-17-40-50.sql.gz
[2017-01-01-17-48-58] Cloud: file successfully uploaded!
[2017-01-01-17-48-58] Stat datadir space (USED): 666M /root/db_backup/2017-01-01
[2017-01-01-17-48-58] Free HDD space: 100500G
[2017-01-01-17-48-58] All operations completed!
Заключение
На этом пока всё.
В планах сделать лимиты на объём папок с бекапами. При превышении заданного лимита — удалять старые бекапы.
Это будет во второй версии. Когда-нибудь.
Принимаю инфу об ошибках, критику и предложения.