
Привет, Хабр! Я Александр Гришин, отвечаю за развитие облачных баз данных и объектного хранилища в Selectel. В своей практике часто сталкиваюсь с разными задачами клиентов. Среди них, например: реализовать репликацию данных между удаленными друг от друга регионами, отработать домен отказа «Регион» и повысить уровень отказоустойчивости своих сервисов, убрав привязку к одному городу и инфраструктуре. Сегодня я расскажу, как легко реализовать асинхронную репликацию данных в инфраструктуре Selectel, используя Python и boto3. Погнали!
Подробнее о единственном мультирегиональном S3-хранилище в РФ, географии локаций и инфраструктуры ЦОД, я рассказывал в предыдущей статье. Это ее продолжение.
Используйте навигацию, если не хотите читать текст целиком:
→ Исходная задача
→ Вариант реализации
→ Часть реализации в панели управления Selectel
→ Настройка на клиенте
→ Настройка cron для регулярного запуска
→ Итог
Исходная задача
Нужно обеспечить географическую разнесенность и катастрофоустойчивость хранящихся у компании резервных копий по разным бакетам, городам и федеральным округам на расстоянии около 700 км.
В бакете-источнике будут лежат резервные копии. Нам нужно раз в час по cron забирать эти данные и передавать в бакет-приемник. Разумеется, без оплаты за трафик при перегоне данных.


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

Концептуальная схема поставленной выше задачи.
Такое решение позволяет нам:
- сокращать задержки при записи в целевой бакет;
- получать максимальную пропускную способность;
- не платить за входящий/исходящий трафик между регионами — весь он остается внутри сети Selectel, считается внутренним и не тарифицируется;
- вся инфраструктура находится в Selectel и не зависит от третьих лиц — получаем понятный уровень SLA и единое окно для обслуживания.
Внутренний трафик — это входящий и исходящий трафик между публичным адресом объекта облачной платформы и публичным адресом другой услуги Selectel.
Часть реализации в панели управления Selectel
Я перечислю только основные шаги. Сначала создаем инфраструктуру для хранения данных.
В предыдущей статье о мультирегиональности в объектном хранилище есть ссылка на подробную инструкцию, которая включает создание сервисного пользователя и другие шаги.
- Перейдите в панель управления → Объектное хранилище.
- Выберете нужный регион, например Москва ru-7 → Создать контейнер (бакет).
- Выберите холодный класс хранения (оптимально для резервных копий).
- Выберите тип адресации vHosted. Это тип адресации подразумевается как базовый для S3-бакета.
- Тип контейнера — приватный (для работы с чувствительными данными).
- Повторите первые три шага в каждом интересующем вас регионе, например в Санкт-Петербург ru-1.
- Создайте служебного пользователя с ролью администратора объектного хранилища и доступом в этот проект.
- Создайте S3-ключ в панели управления.
- Сохраните Access Key и Secret Key (будьте внимательны: ключи не хранятся в наших системах и показываются только один раз).
Создаем инфраструктуру для репликации.
- Перейдите в раздел Облачные серверы.
- Выберите нужный регион и пул, например Санкт-Петербург ru-1.
- Выберите необходимую конфигурацию сервера.
- Учтите, что объекты будут промежуточно загружаться на эту виртуальную машину, поэтому я предлагаю подключить сетевой диск. Его потом можно легко масштабировать хоть до 10 ТБ.
- Под OS будем использовать небольшой, но производительный локальный SSD NVMe-диск.
- Выбираем приватную подсеть.
- Добавляем 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 дней. Этот период полностью покрывает время на подготовительные работы и снижает нагрузку на бизнес.