Введение
Это третья статья из серии статей, в которых рассказывается о том, как можно создать резервную копию недорогого NAS-решения (построенного с помощью raspberry pi) в Azure.
В предыдущих статьях мы рассмотрели доступные облачные решения для хранения данных, а также их стоимость. Мы решили, какой сервис будем использовать (Azure Storage), и создали безопасную инфраструктуру с помощью Terraform.
В этой заключительной статье мы сосредоточимся на решении для резервного копирования наших файлов в Azure Storage с использованием уровня Archive для снижения затрат.
Решение для резервного копирования
Вводим Rclone. Rclone — это программа командной строки для управления файлами в облачном хранилище. Это многофункциональная альтернатива веб-интерфейсам облачных хранилищ поставщиков (как описано на веб-странице).
И это то, что нам нужно для автоматизации резервного копирования. Мы не хотим нажимать на кнопку, мы хотим, чтобы резервные копии наших файлов создавались несколько раз в течение дня.
Мы также хотим сосредоточиться на безопасности, и для этого нам придется открывать и закрывать брандмауэр на нашей учетной записи хранилища, когда происходит резервное копирование.
Итак, давайте начнем.
Учетные данные
Сначала нам нужно будет создать файл учетных данных.
Откройте текстовый редактор и вставьте следующий json-текст:
{
"appId": "replaceme",
"displayName": "replaceme",
"password": "replaceme",
"tenant": "replaceme"
}
Если вы следили за моим предыдущим постом, то помните, что мы развернули инфраструктуру с помощью terraform, и это привело к созданию некоторых выходных данных. Если вы сохранили их, то можете заменить значения в текстовом файле:
Changes to Outputs:
+ appId = (known after apply)
+ displayName = "backupapplication"
+ password = (known after apply)
+ tenant = "xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx"
Если вы не сохранили значения, вы все равно можете получить их, зайдя на портал azure или через командную строку. Если вы не помните пароль, возможно, придется сгенерировать новый пароль для принципала службы.
Теперь, когда у нас есть файл, давайте отложим его в сторону и приступим к сценарию.
Сценарий
Давайте воспользуемся нашим другом bash, чтобы собрать наше решение воедино.
Начнем с безопасности. Нам нужно иметь возможность открывать и закрывать брандмауэр хранилища, чтобы создавать резервные копии наших файлов. Для этого нам нужно пройти аутентификацию в azure (с помощью нашего файла учетных данных) и добавить наш публичный ip-адрес в брандмауэр.
Получаем публичный ip-адрес. Используем aws! Вы все правильно поняли. AWS предоставляет бесплатную конечную точку для обнаружения вашего публичного ip-адреса.
Поэтому наша функция будет выглядеть следующим образом:
getPublicIp() {
curl checkip.amazonaws.com
}
Теперь, когда у нас есть способ получения публичного ip-адреса, нам нужно пройти аутентификацию. Используя учетные данные принципа службы, мы можем легко получить токен доступа, который позволит нам взаимодействовать с хранилищем azure через rest api. Итак, давайте сделаем это:
getAzureToken() {
client_id=$1
client_secret=$2
tenant=$3
scope="https%3A%2F%2Fmanagement.core.windows.net%2F.default"
headers="Content-Type:application/x-www-form-urlencoded"
data1="client_id=${client_id}&scope=${scope}&client_secret=${client_secret}&grant_type=client_credentials"
data2="https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token"
curl -X POST -H $headers -d $data1 $data2
}
Как вы видите, нужные нам параметры доступны в сгенерированном нами файле. Нам просто нужно получить их из файла и передать в функцию.
Итак, теперь, когда у нас есть токен и публичный ip, мы можем начать открывать и закрывать коммуникации в брандмауэре azure.
Давайте поработаем над функцией open. Нам нужно будет вызвать api, который позволяет нам взаимодействовать с нашей учетной записью хранилища (представленной идентификатором ресурса), и передать полезную нагрузку json, которая указывает, что хранилище по умолчанию запрещает весь трафик, но разрешает нашему публичному ip общаться:
addNetworkException() {
token=$1
subscriptionId=$2
resourceGroupName=$3
accountName=$4
publicIp=$5
headers1="Content-Type:application/json"
headers2="Authorization:Bearer ${token}"
url="https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.Storage/storageAccounts/${accountName}?api-version=2021-09-01"
data="{"properties":{"networkAcls":{"defaultAction":"deny","ipRules":[{"action":"allow","value":"${publicIp}"}]}}}"
curl -X PATCH -H "$headers1" -H "$headers2" -d "$data" "$url"
}
Закрытие брандмауэра аналогично. Нам просто нужно удалить ip-адрес из json и передать пустой массив:
removeNetworkException() {
token=$1
subscriptionId=$2
resourceGroupName=$3
accountName=$4
publicIp=$5
headers1="Content-Type:application/json"
headers2="Authorization:Bearer ${token}"
url="https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.Storage/storageAccounts/${accountName}?api-version=2021-09-01"
data="{"properties":{"networkAcls":{"defaultAction":"deny","ipRules":[]}}}"
curl -X PATCH -H "$headers1" -H "$headers2" -d "$data" "$url"
}
Теперь, когда мы позаботились о функциях безопасности, давайте поработаем над самим резервным копированием.
Давайте воспользуемся нашим файлом учетных данных, чтобы добавить информацию о azure в конфигурацию rclone (Это будет выполняться только один раз):
rclone_config() {
echo 'Adding configuration...'
rclone config create "$name" azureblob account="$storageaccountname" access_tier="$accesstier" service_principal_file="$credential_file"
echo 'Config entry added!'
}
Каковы параметры функции?
- $name — Имя конфигурации
- $storageaccountname — Имя учетной записи azure
- $accesstier — Уровень доступа к архиву, который будет использоваться для дешевого хранения наших файлов
- $credential_file — Путь к файловой системе для нашего созданного вручную файла учетных данных.
Теперь нам нужна функция, выполняющая резервное копирование:
rclone_backup() {
echo 'Starting backup...'
rclone sync "$sourcepath" "$name":"$container" "--azureblob-archive-tier-delete" "-v"
if [ $? -eq 0 ]; then
echo 'Backup completed!'
else
echo 'Something went wrong!'
exit 1
fi
}
И снова параметры.
- $sourcepath — Путь к вашей папке в файловой системе
- $name — Имя конфигурации rclone, которое мы использовали в предыдущей функции
- $container — Имя контейнера хранилища azure.
А теперь давайте соберем все это вместе.
getPublicIp() {
curl checkip.amazonaws.com
}
getAzureToken() {
client_id=$1
client_secret=$2
tenant=$3
scope="https%3A%2F%2Fmanagement.core.windows.net%2F.default"
headers="Content-Type:application/x-www-form-urlencoded"
data1="client_id=${client_id}&scope=${scope}&client_secret=${client_secret}&grant_type=client_credentials"
data2="https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token"
curl -X POST -H $headers -d $data1 $data2
}
addNetworkException() {
token=$1
subscriptionId=$2
resourceGroupName=$3
accountName=$4
publicIp=$5
headers1="Content-Type:application/json"
headers2="Authorization:Bearer ${token}"
url="https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.Storage/storageAccounts/${accountName}?api-version=2021-09-01"
data="{"properties":{"networkAcls":{"defaultAction":"deny","ipRules":[{"action":"allow","value":"${publicIp}"}]}}}"
curl -X PATCH -H "$headers1" -H "$headers2" -d "$data" "$url"
}
removeNetworkException() {
token=$1
subscriptionId=$2
resourceGroupName=$3
accountName=$4
publicIp=$5
headers1="Content-Type:application/json"
headers2="Authorization:Bearer ${token}"
url="https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.Storage/storageAccounts/${accountName}?api-version=2021-09-01"
data="{"properties":{"networkAcls":{"defaultAction":"deny","ipRules":[]}}}"
curl -X PATCH -H "$headers1" -H "$headers2" -d "$data" "$url"
}
rclone_config() {
echo 'Adding configuration...'
rclone config create "$name" azureblob account="$storageaccountname" access_tier="$accesstier" service_principal_file="$credential_file"
echo 'Config entry added!'
}
rclone_backup() {
echo 'Starting backup...'
rclone sync "$sourcepath" "$name":"$container" "--azureblob-archive-tier-delete" "-v"
if [ $? -eq 0 ]; then
echo 'Backup completed!'
else
echo 'Something went wrong!'
exit 1
fi
}
publicIp=$(getPublicIp)
credentials=$(cat "$credential_file")
azureToken=$(jq -j '.access_token' <<<"$(getAzureToken "$client_id" "$client_secret" "$tenant")")
addNetworkException "$azureToken" "$subscriptionid" "$resourcegroupname" "$storageaccountname" "$publicIp"
config=$(rclone config dump)
if [ -z "$config" ]; then
rclone_config
rclone_backup
else
rclone_backup
fi
Чтобы было проще, я скомпилировал это в bash-скрипт, доступный по адресу
Вы можете просмотреть описание каждого блока кода, а также прочитать описание параметров скрипта.
Используя загруженный скрипт, мы можем просто сделать его исполняемым и передать параметры:
chmod +x linuxFSAzureBackup.sh
А затем запустить его с помощью приведенного ниже кода (это фиктивный пример. Пожалуйста, замените его на свои собственные значения).
./linuxFSAzureBackup.sh -n "raspberry2azure" -k "/home/pi/azurecredentials.json" -s "myspecialstorage" -r "specialresourcegroup" -i "497b54be-ccfb-47be-994d-b4d549a191cb" -a "Archive" -p "/mnt" -c "myspecialcontainer"
Порядок параметров:
- -n Имя, которое мы присвоим конфигурации rclone»
- -k Путь для файла учетных данных, сгенерированного azure Cli»
- -s Имя учетной записи Azure Storage»
- -r Имя группы ресурсов, в которой находится Azure Storage Account»
- -i Идентификатор подписки Azure»
- -a Желаемый уровень доступа к учетной записи хранилища для резервного копирования файлов»
- -p Путь, по которому расположены элементы, подлежащие резервному копированию»
- -c Имя контейнера учетной записи Azure Storage».
Вот результаты:
Добавление публичного ip-адреса
Копирование файлов
Удаление правила ip-адреса
В итоге мне пришлось создать файл фильтра для rclone, потому что некоторые файлы не копировались. Так что это будет мой следующий вклад в скрипт. Но, пожалуйста, не стесняйтесь изменять его по своему усмотрению.
Вот и все. Теперь вы можете добавить скрипт в crontab и иметь облачное решение для резервного копирования на вашем raspberry pi.
Надеюсь, вам понравилась эта серия статей.
До скорой встречи.