Almost Over

Бекап файлов и баз данных на Amazon S3

Бекап файлов и баз данных на Amazon S3

Как говорят в народе — существуют 2 категории админов: те, которые уже делают бекапы и те, которые об этом серьёзно задумываются. А к какой категории относитесь Вы?

Резервные копии — одна из наиболее важных вещей, без которой долговременная жизнь любого проекта практически невозможна. И важно делать не только локальные бекапы для возможности отката, но и удалённые, для возможности полного восстановления рабочего проекта в случае сбоя работы сервера, например. В данном руководстве будет показано, как настроить автоматические бекапы с использованием внешнего сервиса AWS (Amazon Web Services) S3 (Simple Storage Service).

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

Регистрация на AWS

Для регистрации на Amazon Web Services потребуется ввести номер карты и номер мобильного телефона.
С карты спишется, если память мне не изменяет, сумма в 1$ и затем начислится обратно. После регистрации карту можно будет вообще удалить, продолжая пользоваться бесплатными услугами в течении года.
Для подтверждения же мобильного номера Amazon здесь обыграла почти все сервисы. Обычно приходит смс с кодом подтверждения, а у AWS звонит на номер робот и произносит в трубку код верификации. В общем, номер скорее всего придётся указать свой.

Обычно верификация аккаунта занимает около суток.

Настройка AWS S3

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

Добавление Policy S3

Переходим по ссылке console.aws.amazon.com/iam/home#policies и создаём новую политику:
Create New Policy -> Create Your Own Policy (Select) -> “AmazonS3ReadWriteNotDeleteAccess”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation",
"s3:ListBucketMultipartUploads"
],
"Resource": "arn:aws:s3:::backup-vds",
"Condition": {}
},
{
"Effect": "Allow",
"Action": [
"s3:AbortMultipartUpload",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:GetObjectVersion",
"s3:GetObjectVersionAcl",
"s3:PutObject",
"s3:PutObjectAcl",
"s3:PutObjectAclVersion"
],
"Resource": "arn:aws:s3:::backup-vds/*",
"Condition": {}
},
{
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*",
"Condition": {}
}
]
}

Создание своей политики AWS S3

Добавление User S3

Переходим по ссылке console.aws.amazon.com/iam/home#users и создаём нового пользователя:
Create New Users -> “VDSBackup”.
Также не забываем поставить галочку «Generate an access key for each user».
Создание нового пользователя AWS S3

Далее появится сообщение о том, что пользователь успешно создан и будут доступны для просмотра ключи этого пользователя под спойлером «Hide User Security Credentials». Сохраняем «Access Key ID» и «Secret Access Key» в безопасное место, они то нам и будут нужны для дальнейшего доступа.

Следом выбираем этого пользователя и подсоединяем к нему созданную выше политику:
“VDSBackup” -> Permissions -> Attach Policy.

Добавление Bucket S3

Переходим по ссылке console.aws.amazon.com/s3/home и создаём корзинку, куда и будут складываться бекапы:
Create Bucket -> “backup-vds”.
Создание новой корзины AWS S3
Обратим внимание, для снижения задержки и цены советуют выбирать регион для корзины максимально близко к региону расположения сервера. Рекомендую Frankfurt (DE) или Ireland (IE).
И, да, имя корзины должно быть оригинальное!

Настройка Lifecycle S3

Переходим по ссылке console.aws.amazon.com/s3/home, выбираем только что созданную корзину и добавляем Lifecycle:
“backup-vds” -> Properties -> Lifecycle -> Add rule -> Whole Bucket: backup-vds.
Выбираем «Archive to the Glacier Storage Class» (экономный тип архивации) с периодом на 30 дней и «Permanently Delete» (окончательное удаление) этих архивов через 120 дней. По-усмотрению можно выбрать интервалы побольше, но желательно не меньше указанных.
Настройка архивации и удаления AWS S3


Настройка s3cmd

Добавляем s3 репозиторий в CentOS 6.

$ wget -O /etc/yum.repos.d/s3tools.repo http://s3tools.org/repo/RHEL_6/s3tools.repo
$ yum install s3cmd
$ s3cmd --configure

Первым делом у нас запросят те самые «Access Key ID» и «Secret Access Key», что мы получили при создании пользователя выше.
Затем указываем регион (DE, IE, etc.).
Далее, предложат задать «Encryption password», который нужен для защиты файлов от чтения неавторизированных персон во время копирования на S3. Задаём любой легко для вас запоминающийся.
Path to GPG program — По-умолчанию, Enter.
Use HTTPS protocol [Yes] — По-умолчанию, Enter.

После задания всех установок предложат протестировать доступ, соглашаемся. Тестируются ключи доступа и зашифрованное соединение.
После успешного теста на завершающем этапе предлагают сохранить настройки, что мы и делаем. Выглядит это примерно так:
Конфигурация s3cmd


Настройка скрипта

Для автоматического выполнения бекапов через определённый интервал по крону, нам понадобится небольшой скрипт.

Для удобства обновления, скрипт разделён на 3 части:

  1. backup-to-s3.sh — основной скрипт, выполняющий сжатие и отправку на S3.
  2. backup-config.sh — скрипт, который содержит различные переменные и данные для бекапа (в том числе и пароль от MySQL).
  3. backup-exclude.txt — текстовый файл, содержащий в себе файлы и директории для исключения. Необязателен для использования, отключен по-умолчанию.
$ cd ~
$ wget https://raw.githubusercontent.com/ivan-nginx/scripts/master/backup-to-s3.sh
$ wget https://raw.githubusercontent.com/ivan-nginx/scripts/master/backup-config.sh
$ wget https://raw.githubusercontent.com/ivan-nginx/scripts/master/backup-exclude.txt
$ chmod 755 backup-to-s3.sh

backup-to-s3.sh

Если Вы решили держать скрипты не в root директории, следует изменить переменную
source ~/backup-config.sh.
Если основной скрипт и скрипт конфигурации находятся в одной директории, достаточно изменить её на
source ./backup-config.sh.
Если же основной скрипт располагается, например, в директории root, а конфигурационный скрипт, скажем, в etc, тогда нужно задать абсолютный путь этой переменной —
source /etc/backup-config.sh.

backup-config.sh

В конфигурационном скрипте задаём основные переменные.

  • S3BUCKET — та самая корзина, котороую мы создали в Amazon S3. В нашем случае это backup-vds.
  • DIRS — файлы или директории списком, которые будут сжаты в один архив.
  • EXCLUDE — файлы или директории для исключения (см. backup-exclude.txt).
  • S3PATH — префикс для корзины на S3. Полезно, если бекапы делаются с нескольких разных серверов в одну корзину.
  • MYSQLDUMPPATH — путь к MySQL, если он был установлен в директорию не по-умолчанию.
  • TMP_PATH — директория для хранения временных копий дампов и архивов на локальном сервере.
$ nano ~/backup-config.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
MYSQLROOT=root
MYSQLPASS=pass
S3BUCKET=backup-vds

DIRS="/etc
/root/backup-config.sh
/root/backup-exclude.txt
/var/spool/cron/root
/var/www/php-cgi
/var/www/vhosts/site.com"


# if u want to exclude files/directories, uncomment EXCLUDE variable and create backup-exclude.txt file with files/directories like this:
#/var/www/vhosts/site.com/directory
#/var/www/vhosts/site.com/file.gz
#/var/www/vhosts/site.com/backup/database*.sql*
#EXCLUDE="-X /root/backup-exclude.txt"

# the following line prefixes the backups with the defined directory. it must be blank or end with a /
S3PATH=

# when running via cron, the PATHs MIGHT be different. If you have a custom/manual MYSQL install, you should set this manually like MYSQLDUMPPATH=/usr/local/mysql/bin/
MYSQLDUMPPATH=
#tmp path.
TMP_PATH=/tmp/

Если необходимо исключить какие-либо файлы или директории, переменную EXCLUDE нужно раскомментировать и указать абсолютный путь до файла backup-exclude.txt.

backup-exclude.txt

В исключения вписываем списком абсолютные или относительные пути файлов и/или директорий. Также, можно задавать значения по маскам (wildcard).

$ nano ~/backup-exclude.txt
1
2
3
/var/www/vhosts/site.com/directory
/var/www/vhosts/site.com/file.gz
/var/www/vhosts/site.com/backup/database*.sql*

Запуск скрипта

Скрипт принимает параметры запуска:

  • backup-to-s3.sh day
  • backup-to-s3.sh week
  • backup-to-s3.sh month
  • backup-to-s3.sh auto

Для бекапов по дням/неделям/месяцам и автоматического определения интервала соответственно.
Подробнее об этом описано здесь: github.com/woxxy/MySQL-backup-to-Amazon-S3

$ cd ~ && ./backup-to-s3.sh

Добавление в cron

Потому как AWS S3 предоставляет только 5 ГБ для бесплатного годового использования, стоит тщательно определиться с размерами бекапов. Оптимальный интервал, на мой взгляд, раз в неделю.

$ crontab <(crontab -l; echo "00 6 * * 0 sh /var/www/vhosts/almostover.ru/source/code/backup-to-s3.sh week > /dev/null 1>> /var/log/backup-to-s3.log")
$ service crond restart

Исходник backup-to-s3.sh

https://almostover.ru/code/backup-to-s3.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/bin/sh
# ================================================================== #
# Shell script to backup databases and directories/files via s3cmd.
# ================================================================== #
# Version: 1.0.4
# ================================================================== #
# Parts copyright (c) 2012 woxxy https://github.com/woxxy/MySQL-backup-to-Amazon-S3
# Parts copyright (c) 2015 betweenbrain https://github.com/betweenbrain/MySQL-backup-to-Amazon-S3
# Parts copyright (c) 2016 Ivan.Nginx https://almostover.ru
# This script is licensed under MIT license
# ================================================================== #
#source ./backup-config.sh
#source /etc/backup-config.sh
source ~/backup-config.sh

DATESTAMP=$(date +"%Y.%m.%d-")
DAY=$(date +"%d")
DAYOFWEEK=$(date +"%A")
PERIOD=${1-day}

if [ ${PERIOD} = "auto" ]; then
if [ ${DAY} = "01" ]; then
PERIOD=month
elif [ ${DAYOFWEEK} = "Sunday" ]; then
PERIOD=week
else
PERIOD=day
fi
fi

echo "========================="
echo "$(date +'%Y-%b-%d [%R]')"
echo "========================="
echo "Selected period: $PERIOD."

# we want at least two backups, two months, two weeks, and two days
#echo "Removing old backup (2 ${PERIOD}s ago)..."
#s3cmd del --recursive s3://${S3BUCKET}/${S3PATH}previous_${PERIOD}/
#echo "Old backup removed."

#echo "Moving the backup from past $PERIOD to another folder..."
#s3cmd mv --recursive s3://${S3BUCKET}/${S3PATH}${PERIOD}/ s3://${S3BUCKET}/${S3PATH}previous_${PERIOD}/
#echo "Past backup moved."

# List all the databases, exclude standart databases
DATABASES=`mysql -u root -p$MYSQLPASS -e "SHOW DATABASES;" | tr -d "| " | grep -v "\(Database\|information_schema\|performance_schema\|mysql\|test\)"`

# Loop the databases
for DB in $DATABASES; do

# dump database
echo "Starting backing up the database to a file..."
${MYSQLDUMPPATH}mysqldump --quick --user=${MYSQLROOT} --password=${MYSQLPASS} ${DB} > ${TMP_PATH}${DB}.sql
echo "Done backing up the database to a file."

echo "Starting compression..."
tar czf ${TMP_PATH}${DATESTAMP}${DB}.tar.gz ${TMP_PATH}${DB}.sql
echo "Done compressing the backup file."

# upload all databases
echo "Uploading the new backup..."
s3cmd put -f ${TMP_PATH}${DATESTAMP}${DB}.tar.gz s3://${S3BUCKET}/${S3PATH}${PERIOD}/
echo "New backup uploaded."

echo "Removing the cache files..."
# remove databases dump
rm ${TMP_PATH}${DB}.sql
rm ${TMP_PATH}${DATESTAMP}${DB}.tar.gz
echo "Cache file removed..."

done;

# backup defined files/directories with exclude
echo "Starting compression directories..."
tar pzcf ${TMP_PATH}${DATESTAMP}${HOSTNAME}.tar.gz ${DIRS} ${EXCLUDE}
echo "Done compressing directories."

echo "Uploading the new backup..."
s3cmd put -f ${TMP_PATH}${DATESTAMP}${HOSTNAME}.tar.gz s3://${S3BUCKET}/${S3PATH}${PERIOD}/
echo "New backup uploaded."

echo "Removing the cache files..."
rm ${TMP_PATH}${DATESTAMP}${HOSTNAME}.tar.gz
echo "Cache file removed..."

echo "All done."