Автоматизация резервного копирования с помощью s3cmd

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

Процесс отправки копий данных в удаленное место был серьезной проблемой логистики. Но с появлением облачных сервисов хранения данных (таких как Crashplan и Dropbox) и объектов реализовать это стало намного проще. Однако создание резервных копий и их загрузка по-прежнему может вызывать трудности.

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

Требования

Также может пригодиться опыт написания сценариев оболочки и навыки работы с планировщиком cron.

Читайте также:

Написание сценария для резервного копирования

Существует множество инструментов, которые можно использовать для автоматической загрузки файлов резервных копий в хранилище объектов через определенные промежутки времени. Однако их может быть сложно настроить и, возможно, они не очень гибкие. Простой сценарий оболочки может быть гораздо более изящным и простым решением для автоматизации резервного копирования.

В данном мануале мы напишем базовый сценарий bash, который создает резервную копию файла или каталога с помощью tar, а затем выгружает копию в удаленное хранилище объектов с помощью утилиты s3cmd.

Для начала перейдите в домашний каталог:

cd ~

После этого создайте пустой файл для сценария:

nano bkupscript.sh

Теперь можно начинать писать сценарий. Рассмотрим его по частям.

Начало сценария

Итак, перед вами пустой файл bkupscript.sh. Чтобы компьютер вызывал исполняемый файл в виде команд, нужно начать сценарий с шебанга. Шебанг – это директива интерпретатора, которая позволяет запускать сценарии или файлы данных в виде команд.

В данном случае строка будет выглядеть так:

#!/bin/bash

Теперь оболочка знает, как нужно запускать команды.

Объявление переменных

Теперь нужно передать сценарию переменные, которые будут обеспечивать его работу. Добавьте эти строки сразу после шебанга:

...
DATETIME=`date +%y%m%d-%H_%M_%S`
SRC=$1
DST=$2
GIVENNAME=$3

Рассмотрим эти переменные подробнее:

  • DATETIME: эта переменная содержит временную метку, которая прикрепляется к полученному имени файла, благодаря чему все файлы в удаленном хранилище имеют уникальные имена. Эта временная метка создается путем вызова команды date и форматирования вывода, где отображаются две последние цифры года (%y), две цифры месяца (%m), две цифры дня (%d), час (%H), минуты (%M) и секунды (%S).
  • SRC: это исходный путь к файлу или каталогу, резервную копию которого нужно создать. $1 указывает, что это значение берется из первого параметра, передаваемого сценарию.
  • DST: определяет цель файла. В данном случае здесь нужно указать имя вашего хранилища. Имя хранилища передается сценарию с помощью второго параметра, как говорит $2.
  • GIVENNAME: эта переменная содержит выбранное пользователем имя целевого файла. В результате имя файла составляется из значений GIVENNAME и DATETIME. Это имя передается с помощью третьего параметра ($3).

Добавление подсказок

При написании сценариев важно добавлять подсказки или советы, чтобы помочь пользователям устранить ошибки и неполадки.

Добавьте в сценарий функцию showhelp(). Она выведет ряд сообщений, которые помогут пользователю устранить возникшие неполадки. Синтаксис функции в bash выглядит так:

...
showhelp(){
}

Эта функция предоставит пользователю справочную информацию. Каждая инструкция должна быть представлена в виде строки, заключенной в двойные кавычки. В примере ниже вы увидите, что в начале или в конце некоторых строк стоит \t или \n. Это escape-символы, которые предоставляют конкретные инструкции о том, как должна отображаться строка в выводе сценария:

  • \t указывает на табуляцию,
  • \n указывает на разрыв строки.

Вы можете добавить любые рекомендации по использованию сценария, которые кажутся вам полезными, в фигурные скобки (просто помните, что такие строки нужно начинать с echo). Например, можно добавить следующее:

echo "\n\n############################################"
echo "# bkupscript.sh                            #"
echo "############################################"
echo "\nThis script will backup files/folders into a single compressed file and will store it in the current folder."
echo "In order to work, this script needs the following three parameters in the listed order: "
echo "\t- The full path for the folder or file you want to backup."
echo "\t- The name of the Storage where you want to store the backup at."
echo "\t- The name for the backup file (timestamp will be added to the beginning of the filename)\n"
echo "Example: sh bckupscript.sh ./testdir testStorage backupdata\n"<^>

В итоге функция showhelp будет выглядеть так:

...
showhelp(
echo "\n\n############################################"
echo "# bkupscript.sh                            #"
echo "############################################"
echo "\nThis script will backup files/folders into a single compressed file and will store it in the current folder."
echo "In order to work, this script needs the following three parameters in the listed order: "
echo "\t- The full path for the folder or file you want to backup."
echo "\t- The name of the Storage where you want to store the backup at."
echo "\t- The name for the backup file (timestamp will be added to the beginning of the filename)\n"
echo "Example: sh bckupscript.sh ./testdir testStorage backupdata\n"
}

Сбор файлов

Прежде чем сценарий сможет переместить файлы в хранилище, сначала нужно собрать все нужные файлы и объединить их в один пакет для загрузки. Для этого можно использовать утилиту tar и условный оператор. Поскольку для создания архива (иногда называемого «zip-файлом») используется tar, функция будет называться tarandzip().

Объявите функцию и добавьте еще одну команду echo, которая сообщит, что сценарий начал собирать файлы.

...
tarandzip(){
echo "\n##### Gathering files #####\n"
}

Затем можно добавить команду tar, которая соберет и сожмет файлы в единый файл.

tarandzip(){
echo "\n##### Gathering files #####\n"
tar -czvf $GIVENNAME-$DATETIME.tar.gz $SRC
}

Команда tar вызывается с несколькими опциями и переменными.

  • c сжимает полученный файл.
  • z использует gzip для сжатия.
  • v включает расширенный вывод (verbose).
  • f определяет имя полученного файла (оно указывается после этого флага).
  • $GIVENNAME-$DATETIME.tar.gz – это объявленные переменные, которые сценарий вызывает для того, чтобы создать имя нового файла. Для этого он комбинирует значения $GIVENNAME и $DATETIME и добавляет расширение .tar.gz.
  • $SRC определяет исходный файл или каталог, который нужно скопировать с помощью tar.

Теперь функция делает все необходимое, но вы можете добавить еще пару вызовов echo, чтобы предоставить пользователю дополнительную информацию о работе сценария. Это можно сделать с помощью условных операторов, например:

if tar -czvf $GIVENNAME-$DATETIME.tar.gz $SRC; then

echo "\n##### Done gathering files #####\n"


return 0


else


echo "\n##### Failed to gather files #####\n"


return 1


fi

Когда вызывается оператор if, он выполняет команду tar и дожидается результата. Если результат команды положительный (то есть она выполнена успешно), выполняются строки между then и else, которые:

  • Выводят сообщение, что сценарий успешно выполнил процесс tar.
  • Выводят код ошибки 0, благодаря чему часть кода, вызывающая эту функцию, знает, что все работает нормально.

Остальная часть этой функции будет выполняться только в том случае, если команда tar выдаст ошибку при выполнении. В этом случае ветка else сделает следующее:

  • Отобразит сообщение о том, что команда tar выполнена с ошибкой.
  • Вернет код ошибки 1, который сообщит сценарию, что что-то пошло не так.

В языке bash выражение if/then/else нужно закончить с помощью с fi.

Полная функция tarandzip() будет выглядеть так:

tarandzip(){
echo "\n##### Gathering files #####\n"
if tar -czvf $GIVENNAME-$DATETIME.tar.gz $SRC; then
echo "\n##### Done gathering files #####\n"
return 0
else
echo "\n##### Failed to gather files #####\n"
return 1
fi
}

Перемещение файлов в хранилище объектов

На этом этапе можно переместить копии файлов в харнилище с помощью команды s3cmd. Как и в случае с tarandzip, здесь можно использовать if/then/else и добавить инструкции, чтобы пользователи могли быстро разобраться с тем, как работает сценарий.

Объявите функцию:

...
movetoStorage(){
}

Теперь можно использовать s3cmd и переменные, которые вы объявили ранее, чтобы создать команду, которая будет передавать файлы резервных копий в хранилище:

movetoStorage(){
~/s3cmd-2.0.1/s3cmd put $GIVENNAME-$DATETIME.tar.gz s3://$DST
}

Вот что значит каждая часть команды:

  • ~/s3cmd-2.0.1/s3cmd вызывает утилиту s3cmd.
  • put – это команда, которую s3cmd использует для отправки данных в корзину.
  • $GIVENNAME-$DATETIME.tar.gz – имя файла, который будет загружен в хранилище. Имя файла резервной копии определяется функцией tarandzip().
  • s3://$DST; — это место назначения перемещаемого файла. Здесь s3:// — это URI-подобная схема, которая используется для описания пути к хранилищу, а $DST; — это переменная, которую вы определили ранее.

Теперь у вас есть функция, которая может загружать архивные файлы в удаленное хранилище. Однако она не уведомляет пользователя о состоянии процесса. Добавьте команду echo перед функцией (чтобы сообщить пользователю, что она была запущена) и после функции (чтобы сообщить, как все прошло).

Для начала нужно уведомить пользователя о том, что процесс начался:

movetoStorage(){
echo “\n##### MOVING TO STORAGE #####\n”
~/s3cmd-2.0.1/s3cmd put $GIVENNAME-$DATETIME.tar.gz s3://$DST
}

Поскольку команда будет выполнена либо успешно, либо неудачно (это означает, что она либо сможет загрузить файлы в хранилище, либо не сможет), вы можете передать пользователям одно из двух сообщений:

...
if ~/s3cmd-2.0.1/s3cmd put $GIVENNAME-$DATETIME.tar.gz s3://$DST; then

echo "\n##### Done moving files to s3://"$DST" #####\n"


return 0


else


echo "\n##### Failed to move files to the Storage #####\n"


return 1


fi

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

Если процесс s3cmd был выполнен успешно, функция выводит на экран сообщение об этом (первая строка echo в выражении then) и возвращает код 0, который информирует вызывающую функцию о завершении операции. Если процесс завершается неудачно, выражение then просто выводит сообщение об ошибке (вторая строка echo) и возвращает код 1, который говорит сценарию, что произошла ошибка.

В целом функция movetoStorage() выглядит так:

movetoStorage(){
echo "\n##### MOVING TO STORAGE #####\n"
if ~/s3cmd-2.0.1/s3cmd put $GIVENNAME-$DATETIME.tar.gz s3://$DST; then
echo "\n##### Done moving files to s3://"$DST" #####\n"
return 0
else
echo "\n##### Failed to move files to the Storage #####\n"
return 1
fi
}

Управление потоком

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

Предполагая, что все настроено правильно, при запуске сценарий должен прочитать команду ввода, присвоить значения каждой переменной, выполнить функцию tarandzip() и movetoStorage(). Если сценарий выдаст ошибку на любом этапе, он должен отобразить вывод функции showhelp(), чтобы помочь пользователям устранить неполадки. Добавьте ряд операторов if/then/else в нижней части файла:

...
if [ ! -z "$GIVENNAME" ]; then
if tarandzip; then
movetoStorage
else
showhelp
fi
else
showhelp
fi

Первый оператор if в вышеприведенном разделе проверяет значение переданной третьей переменной. Он делает это следующим образом:

  • [ ]: квадратные скобки означают, что все, что в них находится, является проверкой. В данном случае проверяется значение определенной переменной.
  • !: в данном случае этот символ значит «не».
  • -z: эта опция определяет пустую строку. Вместе с восклицательным знаком это значит, что оператор ищет «не пустую строку».
  • $GIVENNAME: здесь это значит, что строка, которая не должна быть пустой, должна содержать значение переменной $GIVENNAME. Этой переменной присваивается значение, переданное третьим параметром при вызове сценария из командной строки. Если передать сценарию менее 3 параметров, код не получит третьего параметра для значения $GIVENNAME, поэтому он присвоит переменной пустую строку, и этот тест вернет ошибку.

Предполагая, что этот первая проверка прошла успешно, сценарий перейдет к следующему оператору if и т. д. Если какой-либо из операторов if возвращает ошибку, оператор then вызовет функцию showhelp, и на выходе будет отображаться справка. По сути, этот оператор склеивает все предыдущие функции и дает bash информацию, необходимую для их выполнения в правильном порядке.

Сценарий готов!

Код сценария

Полный код сценария выглядит следующим образом:

#!/bin/bash
DATETIME=`date +%y%m%d-%H_%M_%S`
SRC=$1
DST=$2
GIVENNAME=$3
showhelp(){
echo "\n\n############################################"
echo "# bkupscript.sh                            #"
echo "############################################"
echo "\nThis script will backup files/folders into a single compressed file and will store it in the current folder."
echo "In order to work, this script needs the following three parameters in the listed order: "
echo "\t- The full path for the folder or file you want to backup."
echo "\t- The name of the Storage where you want to store the backup at (not the url, just the name)."
echo "\t- The name for the backup file (timestamp will be added to the beginning of the filename)\n"
echo "Example: sh bkupscript.sh ./testdir testStorage backupdata\n"
}
tarandzip(){
echo "\n##### Gathering files #####\n"
if tar -czvf $GIVENNAME-$DATETIME.tar.gz $SRC; then
echo "\n##### Done gathering files #####\n"
return 0
else
echo "\n##### Failed to gather files #####\n"
return 1
fi
}
movetoStorage(){
echo "\n##### MOVING TO STORAGE #####\n"
if ~/s3cmd-2.0.1/s3cmd put $GIVENNAME-$DATETIME.tar.gz s3://$DST; then
echo "\n##### Done moving files to s3://"$DST" #####\n"
return 0
else
echo "\n##### Failed to move files to the Storage #####\n"
return 1
fi
}
if [ ! -z "$GIVENNAME" ]; then
if tarandzip; then
movetoStorage
else
showhelp
fi
else
showhelp
fi

Проверив сценарий, вы можете сохранить и закрыть файл.

Тестирование сценария

Теперь нужно убедиться, что сценарий работает. Это не только поможет понять, правильно ли вы написали сценарий, но также даст вам возможность проверить сценарий в действии.

Для тестирования такого сценария обычно рекомендуется использовать фиктивные файлы. Несмотря на то, что вы точно знаете, что сценарий не причинит вреда системе и данным, лучше испытать его на ненужных файлах. Сначала создайте каталог с помощью команды mkdir:

mkdir backupthis

Затем создайте два пустых файла:

sudo touch backupthis/file1.txt
sudo touch backupthis/file2.txt

Теперь попробуйте загрузить копию содержимого каталога backupthis в хранилище.

sh bkupscript.sh ./backupthis name_of_your_storage testrun

Примечание: Поскольку функция movetoStorage() автоматически добавляет s3: // к целевой переменной (т. е. к имени хранилища), в переменной нужно указать только имя хранилища, а не его полный URL-адрес. Например, если URL хранилища — https://example-storage-name.nyc3.my-storage.com, то команда должна выглядеть следующим образом:

sh bkupscript.sh ./backupthis example-storage-name testrun

Эта команда запустит сценарий и выведет такой результат:

##### Gathering files #####
./backupthis/
./backupthis/file1.txt
./backupthis/file2.txt
##### Done gathering files #####
##### MOVING TO STORAGE #####
upload: 'testrun-180119-15_09_36.tar.gz' -> 's3://name_of_your_storage /testrun-180119-15_09_36.tar.gz'  [1 of 1]
162 of 162   100% in    8s    19.81 B/s  done
##### Done moving files to s3://name_of_your_storage #####

Если сценарий выдал ошибки, просмотрите код и убедитесь, что он соответствует примеру. Кроме того, убедитесь, что ваша установка s3cmd настроена правильно и что access key и the secret key указаны правильно.

Автоматизация резервного копирования с помощью cron

Если тестирование сценария прошло успешно, автоматизируйте процесс бэкапа с помощью планировщика cron. В данном случае сценарий будет запускаться каждую минуту.

Сделайте сценарий исполняемым:

chmod +x bkupscript.sh

Затем отредактируйте файл crontab:

crontab -e

Возможно, вам будет предложено выбрать текстовый редактор:

no crontab for root - using an empty one
Select an editor.  To change later, run 'select-editor'.
/bin/ed
/bin/nano <---- easiest
/usr/bin/vim.basic
/usr/bin/vim.tiny
Choose 1-4 [2]:

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

* * * * * ~/bkupscript.sh ~/backupthis nameofyourstorage cronupload

Сохраните и закройте файл.

Теперь cron будет ежеминутно перезапускать бэкап. Убедившись, что все работает должным образом, вы можете изменить этот интервал.

Заключение

Теперь у вас есть сценарий для автоматического бэкапа данных в удаленное хранилище объектов. Этот сценарий можно использовать в качестве основы для разработки более сложных сценариев, которые можно интегрировать в среду непрерывной интеграции и доставки типа JenkinsDrone или Travis CI.

Читайте также: Настройка непрерывной интеграции в Drone в Ubuntu 16.04

Tags: ,