Как стать автором
Обновить
Selectel
IT-инфраструктура для бизнеса

Асинхронно копируем объекты между регионами S3 с помощью Python

Уровень сложностиСредний
Время на прочтение6 мин
Количество просмотров4K

Привет, Хабр! Я Александр Гришин, отвечаю за развитие облачных баз данных и объектного хранилища в Selectel. В своей практике часто сталкиваюсь с разными задачами клиентов. Среди них, например: реализовать репликацию данных между удаленными друг от друга регионами, отработать домен отказа «Регион» и повысить уровень отказоустойчивости своих сервисов, убрав привязку к одному городу и инфраструктуре. Сегодня я расскажу, как легко реализовать асинхронную репликацию данных в инфраструктуре Selectel, используя Python и boto3. Погнали!

Подробнее о единственном мультирегиональном S3-хранилище в РФ, географии локаций и инфраструктуры ЦОД, я рассказывал в предыдущей статье. Это ее продолжение.

Используйте навигацию, если не хотите читать текст целиком:
Исходная задача
Вариант реализации
Часть реализации в панели управления Selectel
Настройка на клиенте
Настройка cron для регулярного запуска
Итог

Исходная задача


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

В бакете-источнике будут лежат резервные копии. Нам нужно раз в час по cron забирать эти данные и передавать в бакет-приемник. Разумеется, без оплаты за трафик при перегоне данных.





Вариант реализации


Разумеется, я воспользуюсь инфраструктурой Selectel. Что потребуется:
  • бакет в ru-7 (Москва);
  • бакет в ru-1 (Санкт-Петербург);
  • между ними — виртуальная машина в регионе СПб в пуле ru-1, которая запускает Python-скрипт и копирует объекты из одного региона в другой.


Концептуальная схема поставленной выше задачи.

Такое решение позволяет нам:
  • сокращать задержки при записи в целевой бакет;
  • получать максимальную пропускную способность;
  • не платить за входящий/исходящий трафик между регионами — весь он остается внутри сети Selectel, считается внутренним и не тарифицируется;
  • вся инфраструктура находится в Selectel и не зависит от третьих лиц — получаем понятный уровень SLA и единое окно для обслуживания.

Внутренний трафик — это входящий и исходящий трафик между публичным адресом объекта облачной платформы и публичным адресом другой услуги Selectel.


Часть реализации в панели управления Selectel


Я перечислю только основные шаги. Сначала создаем инфраструктуру для хранения данных.

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

  1. Перейдите в панель управленияОбъектное хранилище.
  2. Выберете нужный регион, например Москва ru-7 → Создать контейнер (бакет).
  3. Выберите холодный класс хранения (оптимально для резервных копий).
  4. Выберите тип адресации vHosted. Это тип адресации подразумевается как базовый для S3-бакета.
  5. Тип контейнера — приватный (для работы с чувствительными данными).
  6. Повторите первые три шага в каждом интересующем вас регионе, например в Санкт-Петербург ru-1.
  7. Создайте служебного пользователя с ролью администратора объектного хранилища и доступом в этот проект.
  8. Создайте S3-ключ в панели управления.
  9. Сохраните Access Key и Secret Key (будьте внимательны: ключи не хранятся в наших системах и показываются только один раз).

Создаем инфраструктуру для репликации.
  1. Перейдите в раздел Облачные серверы.
  2. Выберите нужный регион и пул, например Санкт-Петербург ru-1.
  3. Выберите необходимую конфигурацию сервера.
  4. Учтите, что объекты будут промежуточно загружаться на эту виртуальную машину, поэтому я предлагаю подключить сетевой диск. Его потом можно легко масштабировать хоть до 10 ТБ.
  5. Под OS будем использовать небольшой, но производительный локальный SSD NVMe-диск.
  6. Выбираем приватную подсеть.
  7. Добавляем SSH-ключ и создаем виртуальную машину.

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


Используем виртуальную машину с сетевым диском сразу на 1 ТБ — этого хватит с запасом. К тому же, это не дорого.

  • Selectel S3 пока не поддерживает серверсайд репликации между регионами.
  • Поэтому метод copy_object работает только внутри одного пула и не подойдет нам для решения задачи.
  • Но репликацию можно реализовать вручную через Python с помощью всего двух методов: get_object и put_object.

Настройка на клиенте


Для автоматизации будем писать простой скрипт на Python + boto3. На виртуальной машине создаем файл replicate_s3.py. Этот скрипт реализует асинхронную репликацию объектов между двумя регионами — из пула ru-7 (Москва) в ru-1 (Санкт-Петербург).

import boto3
from botocore.config import Config
from botocore.exceptions import ClientError
import datetime

# Доступы
ACCESS_KEY = ‘access key’
SECRET_KEY = ‘secret

# Эндпоинт и имена бакетов
endpoint = 'https://s3.storage.selcloud.ru'
source_bucket = 'habr42'              # Бакет-источник (регион ru-7)
destination_bucket = 'habr42-cold'    # Бакет-назначение (регион ru-1)

# Функция для создания клиента S3 с учетом региона
def get_s3_client(region: str):
    return boto3.client(
        service_name='s3',
        endpoint_url=endpoint,  # Используем единый глобальный эндпоинт
        region_name=region,     # Указываем регион, чтобы выбрать хранилище (ru-7 или ru-1)
        aws_access_key_id=ACCESS_KEY,
        aws_secret_access_key=SECRET_KEY,
        config=Config(s3={'addressing_style': 'virtual'})  # Включаем виртуальный стиль адресации бакетов
    )

# Основная функция для репликации объектов из одного бакета в другой
def replicate_objects():
    print(f"\n=== START REPLICATION {datetime.datetime.now()} ===")

    s3_ru7 = get_s3_client("ru-7")  # Клиент для региона-источника
    s3_ru1 = get_s3_client("ru-1")  # Клиент для региона-назначения

    try:
        print(f"[INFO] Получаем список объектов из {source_bucket}...")
        response = s3_ru7.list_objects_v2(Bucket=source_bucket)  # Получаем список объектов
        objects = response.get('Contents', [])  # Извлекаем список объектов из ответа

        if not objects:
            print("[WARNING] Нет объектов для копирования.")  # Если объектов нет — сообщение
        else:
            print(f"[INFO] Найдено {len(objects)} объектов. Копируем...")  # Лог количества найденных объектов

            for obj in objects:
                key = obj['Key']  # Получаем имя (ключ) объекта
                print(f"[INFO] Работаем с объектом: {key}")

                try:
                    source_object = s3_ru7.get_object(Bucket=source_bucket, Key=key)  # Считываем объект
                    data = source_object['Body'].read()  # Читаем содержимое

                    s3_ru1.put_object(Bucket=destination_bucket, Key=key, Body=data)  # Загружаем в целевой бакет
                    print(f"[SUCCESS] {key} скопирован.")
                except ClientError as e:
                    print(f"[ERROR] Не удалось скопировать {key}: {e}")  # Ошибка при копировании конкретного объекта

    except ClientError as e:
        print(f"[ERROR] Ошибка при получении списка объектов: {e}")  # Ошибка при получении списка объектов

    print(f"=== END REPLICATION {datetime.datetime.now()} ===\n")  # Завершение логгирования

# Точка входа в программу
if __name__ == "__main__":
    replicate_objects()

Что делает этот скрипт. Сперва он подключается к двум S3-клиентам (источник и приемник). Затем получает список всех объектов из исходного бакета. И наконец, поочередно скачивает каждый объект и загружает его в целевой бакет. Кроме того, скрипт логирует процесс: количество файлов, успешные копирования и возможные ошибки.

Настройка cron для регулярного запуска


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

1. Открываем crontab:
crontab -e

2. Добавляем строку — например, запуск каждый час — для путей, по которым хранятся объекты:
0 * * * * /usr/bin/python3 /path/to/replicate_s3.py >> /var/log/replication.log 2>&1

Замените /usr/bin/python3 и /path/to/replicate_s3.py.

>> /var/log/replication.log логирует вывод в файл. Это удобно для последующей отладки, если что-то пойдет не так. Все пути до исполняемых файлов следует указывать абсолютными.

3. Сохраняем файл, выходим из редактора и проверяем список заданий:
crontab -l

Итог


Мы за полчаса реализовали географически распределенное и катастрофоустойчивое хранение резервных копий в двух локациях: Москве и Санкт-Петербурге.

Репликация автоматически запускается каждый час и сопровождается логированием всех действий нашей системы. Бонус — весь трафик остается в пределах инфраструктуры Selectel и не тарифицируется. А дополнительные логи можно получить еще и со стороны хранилища.

Разумеется, это тривиальный пример с простым кодом. Его цель — раскрыть ключевые идеи реализации задачи Disaster Recovery на базе инфраструктуры объектного хранилища. Для использования в проде решение стоит улучшить. Например, реализовать:
  • поддержку копирования только новых объектов (по дате);
  • уведомления в Telegram/Slack при сбоях;
  • более тонкую настройку политики доступа для сервисного пользователя — например, ограничение доступа из интернета к бакету по разрешенным IP (SourceIp);
  • хранение версий объекта, что поможет при необходимости вернуться к конкретной версии объекта.


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

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

Следите за обновлениями. В следующей статье я расскажу, как работать с версионированием объектов в S3.

Кстати, если вы еще не пользовались объектным хранилищем Selectel, у меня для вас новость. Мы сейчас проводим миграционные каникулы для переноса данных. Подайте заявку на сайте и с момента ее одобрения можно будет не оплачивать запросы и хранение 30 дней. Этот период полностью покрывает время на подготовительные работы и снижает нагрузку на бизнес.
Теги:
Хабы:
+32
Комментарии10

Публикации

Информация

Сайт
slc.tl
Дата регистрации
Дата основания
Численность
1 001–5 000 человек
Местоположение
Россия
Представитель
Влад Ефименко