Пример скрипта для создания резервной копии MySQL. Запуск скрипта резервного копирования. Интерфейс и меню резервного копирования

И так, краткая выжимка из теоритических знаний, которая нам потребуется:

Выполнять резервное копирование можно на сетевой ресурс или на отдельный том. Копирование на сетевой ресурс имеет пару существенных недостатков: во-первых, при возникновении проблем с сетью (во время выполнения архивирования) ваша резервная копия, очевидно, не будет создана, а, во-вторых, сетевая папка может содержать только одну единственную резервную копию (выполняя резервную копию в ту же сетевую папку, что и раньше, вы уничтожаете предыдущую резервную копию).

Копирование на отдельный том выполняется следующим образом: На целевом томе создается папка WindowsImageBackup\<ComputerName >\. В этой папке в свою очередь будут созданы виртуальные диски (по одному на каждый из бэкапируемых томов), на который и будет производится резервное копирование. По окончании копирования состояние виртуальных дисков, хранящих резервные копии, будет сохранено при помощи службы теневого копирования. При следующем архивировании будут произведены те же самые действия в результате получится, что каждый конкретный архив будет доступен при обращении к конкретной теневой копии. Причем с точки зрения программы архивирования каждый такой архив будет являться полным архивом, а с точки зрения используемого пространства – инкрементальным (теневая копия хранит информацию только об измененных блоках данных).

Информация о выполненном процессе архивирования хранится в нескольких местах ОС, которые, может так случиться, могут содержать рассогласованную информацию. Понятно, что реальное количество резервных копий, которое хранится локально на компьютере, не может быть больше, чем количество теневых копий тома, на который выполнялось резервное копирование. Посмотреть информацию о количестве теневых копий можно, например, в командной строке при помощи команды diskshadow (и ее подкоманд list shadows all ). Однако, теневые копии не содержат достаточное количество информации, необходимой для создания перечня резервных копий, поэтому эта информация берется из других мест. Так, например, ОС ведет учет архивных копий в глобальном каталоге архивов, а так же в журнале событий Windows Server Backup Log. Информация из этих источников отображается оснастке “Система архивации данных Windows Server”. В результате может сложиться такая ситуация, что оснастка будет демонстрировать нам противоречивую информацию, которая не имеет ничего общего с реальностью.

Посмотрите на скриншот. Он был сделан в системе, для которой на локальном диске хранилось всего два архива (существовало только две теневые копии) и не было создано ни одного сетевого архива. Однако, оснастка сообщает нам в разделе “Все архивы” о том, что у нас якобы имеется 6 архивов, а в окне сообщений мы видим отчет о создании только 3х архивов. Для того, чтобы заставить ОС отображать непротиворечивую информацию, соответствующую действительности, нам придется проинициализировать все компоненты системы архивации, которые хранят информацию о резервных копиях или сами резервные копии. Для этого нам нужно будет очистить windows backup log , удалить глобальный каталог архивов (при помощи команды wbadmin delete catalog ) и удалить все теневые копии (при помощи команды diskshadow delete shadows all ). По большому счету информация, хранящаяся в windows backup log, носит чисто информационный характер и никак не влияет на процесс восстановления информации из архива, если таковой потребуется выполнить, чего не скажешь об информации, хранящейся в глобальном каталоге. Если глобальный каталог поврежден, то восстановить информацию при помощи штатных средств архивирования ОС windows у нас не получится. Однако, поврежденный или удаленный глобальный каталог архивов можно восстановить из резервной копии, которая создается при каждом архивировании в папке WindowsImageBackup\<ComputerName >\. Для восстановления поврежденного глобального каталога архивов необходимо его сначала удалить (при помощи команды wbadmin delete catalog) , а затем восстановить из резервной копии (при помощи команды wbadmin restore catalog) .

Ну, а теперь, собственно, опубликую скрипт для резервного копирования:

Write-Verbose "Начали..." #Сохраняем значение переменной окружения $VerbosePreference $tmpVerbpref=$VerbosePreference $VerbosePreference="Continue" #Путь к сетевой папке, в которую будем копировать архив $NetworkBackupPath="\\SRV66\Backup$\SRV02\BMR" #Имя раздела, на котором будем создавать архив $VolumeTarget="D:" # Количество копий бэкапа, которые необходимо сохранить на локальном носителе $BackupQuantity=3 # Количество копий бэкапа, которые необходимо сохранить на сетевом носителе $NetBackupQuantity=5 #Путь к файлу-списку бэкапов $csvFile="D:\Backup\ProfileBackup.csv" #Путь к папке, в котой будем создавать архив 7zip $Path2Arc="D:\Backup" # подключаем оснастку Server Backup Add-PSSnapin Windows.Serverbackup -ErrorAction SilentlyContinue # создаём задание бэкапа $policy = New-WBPolicy <# # создаём и добавляем в задание бэкапа о бэкапируемых файлах $source = New-WBFileSpec -FileSpec "C:\Users" Add-WBFileSpec -Policy $policy -FileSpec $source #> # #Get list of critical volumes $VolSources = Get-WBVolume -CriticalVolumes #Add volumes to be backed up Add-WBVolume -Policy $policy -Volume $VolSources #Define VSS Backup Otions Set-WBVssBackupOptions -policy $policy -VssCopyBackup #Enable SystemState backup Add-WBSystemState -policy $policy #Enable Bare Metal Recovery Add-WBBareMetalRecovery -Policy $policy # # указываем локальный том, на который будет копироваться архив $target = New-WBBackupTarget -VolumePath $VolumeTarget Add-WBBackupTarget -Policy $policy -Target $target Write-Verbose "Начинаем процесс создания backup"а" # выполняем бэкап Start-WBBackup -Policy $policy # проверяем код возврата с результатом выполнения бэкапа if ((Get-WBSummary).LastBackupResultHR -eq 0) { # переименовываем архив в более понятное имя $newname = "_Backup_$(Get-Date -f yyyyMMddHHmm)" Write-Verbose "Переименовываем папку с только что созданным архивом в $newname ..." Ren $VolumeTarget\WindowsImageBackup -NewName $newname # Запаковываем архив при помощи 7zip $arc="C:\Program Files\7-Zip\7z.exe" $arc_params="a -t7z -m0=LZMA2 -mmt -mx9" $arc_source="$VolumeTarget\$newname" $arc_dest="$Path2Arc\$newname.7z" Write-Verbose "Запаковываем папку $newname при помощи 7zip в $newname.7z" Start-Process $arc -ArgumentList "$arc_params $arc_dest $arc_source" -Wait # копируем архив в сетевую папку #copy $VolumeTarget\$newname $NetworkBackupPath -Recurse Write-Verbose "Копируем файл $arc_dest в сетевую папку..." copy "$arc_dest" $NetworkBackupPath if ($?) { #если копирование прошло без ошибок, удаляем файл-архива и папку, которая была запакована в этот архив del "$arc_dest" -Force -Verbose del $VolumeTarget\$newname -Recurse -Force #-Verbose } # удаляем старые архивы из сетевой папки, за исключением последних $BackupQuantity архивов $NetBackups=dir $NetworkBackupPath | ?{$_.Name -match "_.+(\d)+\.7z$"} $NetBackupsCount=$NetBackups.count if (($NetBackupsCount - $NetBackupQuantity) -gt 0) { $NetBackups | sort lastwritetime | select -First ($NetBackupsCount - $NetBackupQuantity) | del -Force -Verbose #-Recurse -WhatIf } # читаем наш собственный каталог бэкапов $csv=@() if (Test-Path $csvFile) {$csv = @(Import-Csv $csvFile)} # считываем данные о последнем бэкапе $current = Get-WBBackupSet | select -Last 1 | select VersionID, SnapshotId # и добавляем его в массив объектов действующих бэкапов $csv += $current # чтобы не было путаницы, снова сортируем объекты и пишем обратно в CSV файл $csv | sort @{Expression={($_.VersionId)}}| select -Last $BackupQuantity | Export-Csv $csvFile -NoTypeInformation # и считаем сколько там записей $count = $csv.count # если записей больше BackupQuantity, то считаем сколько лишних архивов нужно удалить. # если меньше BackupQuantity записей, то ничего удалять не надо и просто добавляем новую запись if ($count -gt $BackupQuantity) { $old = $count - $BackupQuantity # генерируем случайное имя для скрипта, который будет использоваться в diskshadow $file = ::GetRandomFileName() # выбираем все лишние архивы и пропускаем их по конвейеру на удаление $csv | sort @{Expression={($_.VersionId)}}| select -First $old | %{ #Read-Host "Press Enter to continue..." | Out-Null #Write-Verbose $file ##Read-Host "Press Enter to continue..." | Out-Null # записываем команду во временный файл "delete shadows ID {$($_.SnapshotID)}"|Out-File -FilePath $Env:TEMP\$file -Encoding OEM #gc $Env:TEMP\$file #Read-Host "Press Enter to continue..." | Out-Null # и запускаем diskshadow в режиме скрипта diskshadow /s $Env:TEMP\$file | Out-Default } del $Env:TEMP\$file } } else { # ругаемся, что бэкап не был завершён успешно Write-Verbose "Ошибка выполнения бэкапа" } Write-Verbose "Скрипт закончил работу" #Восстанавливаем значение переменной окружения $VerbosePreference $VerbosePreference=$tmpVerbpref

Обновлено: 21.07.2017 Опубликовано: 15.08.2016

Данный скрипт написан на Unix Shell под управлением операционной системы CentOS . Он будет работать на большинстве систем семейств Linux и BSD.

Пример скрипта

Скрипт будет создавать для каждой базы свой дамп. Это необходимо для быстрого восстановления данных.

  1. #!/bin/bash
  2. PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
  3. destination="/backup/mysql"
  4. userDB="backup"
  5. passwordDB="backup"
  6. fdate=`date +%Y-%m-%d`
  7. find $destination -type d \(-name "*-1[^5]" -o -name "*-?" \) -ctime +30 -exec rm -R {} \; 2>&1
  8. find $destination -type d -name "*-*" -ctime +180 -exec rm -R {} \; 2>&1
  9. mkdir $destination/$fdate 2>&1
  10. for dbname in `echo show databases | mysql -u$userDB -p$passwordDB | grep -v Database`; do
  11. case $dbname in
  12. information_schema)
  13. continue ;;
  14. mysql)
  15. continue ;;
  16. performance_schema)
  17. continue ;;
  18. test)
  19. continue ;;
  20. *) mysqldump --databases --skip-comments -u$userDB -p$passwordDB $dbname | gzip > $destination/$fdate/$dbname.sql.gz ;;
  21. done;

Описание скрипта

1 Указываем на путь к интерпретатору.
2 Задаем системные переменные, чтобы не пришлось в скрипте прописывать полные пути до исполняемых файлов.
4 - 7 Задаем переменные.
4 Каталог, в котором будем сохранять резервные копии.
5 Учетная запись для подключения к базе данных.
6 Пароль для подключения к базе данных.
7 Дата, когда запускается скрипт.
9 Находим все резервные копии, которые старше 30 дней и удаляем их. Оставаляем для архива файлы на 15 число.
10 Удаляем все резервные копии старше 180 дней.
11 Создаем каталог, в который будем сохранять резервные копии. В качестве имени каталога используем дату запуска скрипта в формате ГГГГ-MM-ДД.
13 - 25 Подключаемся к базе данных и вытаскиваем список всех баз данных. Для каждой делаем резервную копию.
15 - 22 Пропускаем служебные базы information_schema, mysql, performance_schema, test.
23 Делаем резервную копию для баз.

Подготовка системы

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

> GRANT SELECT, SHOW VIEW, RELOAD, REPLICATION CLIENT, EVENT, TRIGGER, LOCK TABLES ON *.* TO backup@localhost IDENTIFIED BY "backup";

* в данном примере мы создаем учетную запись backup с паролем backup .

Создаем каталог, в котором будут храниться резервные копии:

mkdir -p /backup/mysql

Сохранение данных на удаленном компьютере

Резервные копии необходимо создавать на удаленном компьютере или внешнем диске, чтобы они были доступны при выходе из строя сервера. В данном примере используется общая папка на удаленном сервере, в которой будут размещаться файлы с backup.

Чтобы упростить процесс монтирования сетевой папки, откроем на редактирование следующий файл:

и добавим в него следующую строчку:

//192.168.0.1/backup /mnt cifs user,rw,noauto,credentials=/root/.smbclient 0 0

* в данном примере выполняется монтирование общей папки backup на сервере с IP-адресом 192.168.0.1 в каталог /mnt . В качестве сетевой файловой системы используется cifs (протокол SMB: сервер samba или общая папка Windows). Параметры для подключения — user : позволяет выполнить монтирование любому пользователю, rw : с правом на чтение и запись, noauto : не монтировать автоматически при старте системы, credentials : файл, в котором написаны логин и пароль для подключения к общей папке.

Теперь создадим файл с логином и паролем:

# vi /root/.smbclient

и приведем его к следующему виду:

username=backup
password=backup

* username : имя пользователя, password : пароль. Само собой, в вашем случае указываются свои данные.

Теперь введите следующую команду.

Бэкап важной информации - каждый системный администратор сталкивается с такой задачей. Задача казалось бы тривиальная и у многих читателей интереса не вызовет. Но, например, мне бы такая статья в определенный момент помогла бы весьма сильно, поэтому считаю, что этой статье быть.

Задача: Бэкап данных в локальную директорию и на отдельный сервер, с использованием минимума стороннего ПО, логированием и оповещением администратора в jabber при сбоях. Все основные функции большинства ПО для автоматического бэкапа, но без установки оного, а следовательно без его багов (что, собственно, и привело к подобной идее).

А теперь к делу.

Для начала создадим и откроем скрипт
nano backup-script
Теперь в скрипте добавим строку
#!/bin/bash
Объявим некоторые переменные.
TN - TASKNAME - имя задания.Используется для вывода в лог и определения названия файла.
Так как заданий несколько (ежемесячное, еженедельное, ежедневное) и писать на каждый случай скрипт было лень, я создал универсальный, в котором надо просто раскомментить нужные строки. Наименование заданий писать надо без пробелов, желательно в латинице, если не хотите проблем с кодировкой и неправильными параметрами команд.
TN=docs-monthly
#TN=docs-weekly
#TN=docs-daily
OF - Output File - имя выходного файла. Получается из переменной TN, то есть имени задания.
OF=$TN.tar.gz
Объявляем переменную с путем к файлу лога, и далее все сообщения об ошибках и остальном будем выводить в лог.
LOGFILE=/var/log/backup.log
Сделаем запись в лог о начале бэкапа (дата, время, имя задания)
echo >>$LOGFILE echo "=====================================================" >>$LOGFILE echo "$(date +"%d-%b-%Y %R")" >>$LOGFILE echo "Задание \"$TN\" запущено..." >>$LOGFILE
Есть проблема в том что если указывать в параметрах команд (напр. tar) имена каталогов с пробелами, скрипт срабатывает с ошибкой. Решение найдено на просторах интернета - операционная система linux использует пробел в качестве стандартного разделителя параметров команды. Переопределим стандартный разделитель (хранится в переменной $IFS) отличным от пробела, например \n – знаком переноса строки.
Запоминаем старое значение стандартного разделителя
OLD_IFS=$IFS
Заменяем стандартный разделитель своим
IFS=$"\n"
SRCD - SouRCe Directory - каталог с данными для бэкапа
Теперь можно перечислять несколько каталогов, разделителем будет перенос строк как мы сами указали строкой выше
SRCD="/mnt/source/folder_1 /mnt/source/folder_2 /mnt/source/folder_N"
TGTD - TarGeT Directory - каталог в который будут складываться бэкапы
TGTD="/var/backups/"
Естественно мы понимаем что хранить важные бэкапы только на источнике как минимум легкомысленно. Поэтому оставим копию и на удаленном ресурсе, который будем отдельно монтировать с помощью mount и fstab. Сразу поясню почему я использовал mount и fstab, а не один mount - я монтирую этот каталог и в других своих скриптах, а как сказал один из знакомых программистов - хороший программист не будет писать один и тот же код дважды (как-то так, дословно не помню, но надеюсь смысл донес).
TGTD2="/mnt/archive/"
Сам процесс архивирования в варианте "Создать новый архив"
tar -czf $TGTD$OF $SRCD &>>$LOGFILE
и в варианте "Обновить файлы в старом архиве"
tar -u -f $TGTD$OF $SRCD &>>$LOGFILE
Во втором случае лучше вместо $OF использовать конктретное имя файла потому что у меня например ежедневно апдэйтится еженедельный архив, а их $TN (имена задания) не совпадают, соответственно и $OF.

В переменной "?" ханится статус выполнения последней команды. Сохраним его, чтобы воспользоваться позже.
STATUS=$?
Возвращаем стандартный разделитель к исходному значению
IFS=$OLD_IFS
Теперь добавим условие - если процесс упаковки в архив tar закончился с ошибкой, отправляем сообщение админу, удаляем неудачный файл бекапа. Иначе продолжаем дальше - монтируем сетевую шару и кидаем в нее копию архива. После каждой операции проверяем результат выполнения, пишем логи, и либо продолжаем, либо извещаем админа и прерываем процедуру.
if [[ $STATUS != 0 ]]; then rm $TGTD$OF &>>$LOGFILE echo "###########################################" >>$LOGFILE echo "### Произошла ошибка! Бэкап не удался. ###" >>$LOGFILE echo "###########################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не создан" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE else echo "Файл бэкапа сохранен как \"$TGTD$OF\"" >>$LOGFILE echo "Бэкап успешно завершен в $(date +"%R %d-%b-%Y")!" >>$LOGFILE echo "Монтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE mount $TGTD2 &>>$LOGFILE if [[ $? != 0 ]]; then echo "#############################################################" >>$LOGFILE echo "### Произошла ошибка при монтировании резервного ресурса ###" >>$LOGFILE echo "#############################################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE exit fi echo "Начато копирование файла на резервный ресурс" >>$LOGFILE cp -f $TGTD$OF $TGTD_archive$OF &>>$LOGFILE if [[ $? != 0 ]]; then echo "#############################################################" >>$LOGFILE echo "### Произошла ошибка при копировании на резервный ресурс ###" >>$LOGFILE echo "#############################################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE else echo "Копирование файла успешно завершено в $(date +"%R %d-%b-%Y")!" >>$LOGFILE echo "Файл скопирован как \"$TGTD_archive$OF\"" >>$LOGFILE fi echo "Размонтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE umount $TGTD2 &>>$LOGFILE echo "Все операции завершены успешно!" >>$LOGFILE fi exit

В процессе мы копируем архив из локального хванилища в удаленное. Естественно, проверяем, что каждая операция успешно завершена, и пишем все в логи.
Для отсылки сообщения администратору я использую XMPP сообщение, так как в организации поднят Jabber-сервер, и я больше люблю получить быстрое сообщение о сбое, чем лезть в почту, вбивая пароли, тыкая на ссылки, и ожидая пока браузер мне все отобразит. В любом случае никто не мешает вам использовать sendmail вместо sendxmpp.
Файл /usr/local/etc/XMPP_settings следующего содержания:

#логин_отправителя@домен;IP_jabber_сервера:порт_jabber_сервера пароль_отправителя login@domen;127.0.0.1:5222 password
В файле fstab строка описывающая подключение шары Windows
//192.168.0.250/arhiv /mnt/archive cifs noauto,rw,iocharset=utf8,cp866,file_mod=0666,dir_mod=0777,noexec,_netdev,credentials=/root/.passwd_to_archive_directory 0 0
Теперь осталось только добавить задание в cron. Это можно сделать с помощью файла /etc/crontab, но я, в силу привычки к GUI, оставшейся в наследство от виндовс, пользую вэб-интерфейсы для таких случаев. Команда должна выполняться с правами рута, то бишь, к примеру, sudo bash backup_script. Добавляя команду в cron можно определить что она будет сразу выполняться от имени root`а

В ходе обсуждений затронули проблему разрастания логов. Пошел по простейшему (на мой взгляд) пути: будем хранить только последние N строк лога, например 300. В скрипт добавятся две строки, в которых мы сохраним последние 300 строк лога во временный файл, потом затрем им лог
tail -n 300 $LOGFILE >/tmp/unique_fantastic_filename.tmp mv -f /tmp/unique_fantastic_filename.tmp $LOGFILE
Приведу полный текст скрипта:
#!/bin/bash TN=docs-monthly #TN=docs-weekly #TN=docs-daily OF=$TN.tar.gz LOGFILE=/var/log/backup.log echo >>$LOGFILE echo "=====================================================" >>$LOGFILE echo "$(date +"%d-%b-%Y %R")" >>$LOGFILE echo "Задание \"$TN\" запущено..." >>$LOGFILE OLD_IFS=$IFS IFS=$"\n" SRCD="/mnt/source/folder_1 /mnt/source/folder_2 /mnt/source/folder_N" TGTD="/var/backups/" TGTD2="/mnt/archive/" tar -czf $TGTD$OF $SRCD &>>$LOGFILE #tar -u -f $TGTD$OF $SRCD &>>$LOGFILE STATUS=$? IFS=$OLD_IFS if [[ $STATUS != 0 ]]; then rm $TGTD$OF &>>$LOGFILE echo "###########################################" >>$LOGFILE echo "### Произошла ошибка! Бэкап не удался. ###" >>$LOGFILE echo "###########################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не создан" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE else echo "Файл бэкапа сохранен как \"$TGTD$OF\"" >>$LOGFILE echo "Бэкап успешно завершен в $(date +"%R %d-%b-%Y")!" >>$LOGFILE echo "Монтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE mount $TGTD2 &>>$LOGFILE if [[ $? != 0 ]]; then echo "#############################################################" >>$LOGFILE echo "### Произошла ошибка при монтировании резервного ресурса ###" >>$LOGFILE echo "#############################################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE exit fi echo "Начато копирование файла на резервный ресурс" >>$LOGFILE cp -f $TGTD$OF $TGTD_archive$OF &>>$LOGFILE if [[ $? != 0 ]]; then echo "#############################################################" >>$LOGFILE echo "### Произошла ошибка при копировании на резервный ресурс ###" >>$LOGFILE echo "#############################################################" >>$LOGFILE echo "$(date +"%d-%b-%Y %R%nФайл") бекапа $OF не скопирован на резервный ресурс" | sendxmpp -t -f /usr/local/etc/XMPP_settings логин_получателя@домен &>>$LOGFILE else echo "Копирование файла успешно завершено в $(date +"%R %d-%b-%Y")!" >>$LOGFILE echo "Файл скопирован как \"$TGTD_archive$OF\"" >>$LOGFILE fi echo "Размонтирование файловой системы для резервного архива $TGTD_archive" >>$LOGFILE umount $TGTD2 &>>$LOGFILE echo "Все операции завершены успешно!" >>$LOGFILE fi tail -n 300 $LOGFILE >/tmp/unique_fantastic_filename.tmp mv -f /tmp/unique_fantastic_filename.tmp $LOGFILE exit

Всем спасибо за внимание!



Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: