Представим типичную инфраструктурную задачу. В компании для хранения артефактов сборки, бэкапов сервисов или пользовательских файлов применяется S3‑хранилище. Развернуто оно в основном контуре — например, в продакшен-кластере.
Но что, если этот кластер выйдет из строя по причине, скажем, сетевого сбоя или человеческого фактора? Весь проект может остаться без критически важных данных. Решение очевидно: данные должны периодически копироваться во второй контур — резервный дата-центр, отдельную катастрофоустойчивую инфраструктуру, возможно даже в другом регионе.
В этой статье разберем, как настроить клиентскую синхронизацию между двумя хранилищами с помощью MinIO Client. Рассмотрим все шаги для подготовки окружения, установки клиента и настройки автоматического запуска, — чтобы объекты регулярно копировались из одного бакета в другой. Пригодится всем, кто работает с инфраструктурой, распределенной по нескольким дата-центрам, тестовыми и рабочими окружениями, а также при проектировании катастрофоустойчивых сценариев.
Основные понятия
Итак, допустим, основное S3‑хранилище находится в Санкт-Петербурге — именно туда сервисы загружают объекты. Чтобы при сбое на первой площадке компания не потеряла доступ к данным, разворачивается резервный кластер в Москве. Именно эту задачу и решает синхронизация бакетов.
Что такое синхронизация бакетов
Суть синхронизации сводится к копированию объектов из исходного бакета в целевой. Реализовать этот процесс можно по‑разному: от встроенной серверной репликации до самописных скриптов. Очень удобной оказывается утилита MinIO Client (mc) — универсальный инструмент, который работает с любым S3‑совместимым API и избавляет от необходимости писать собственный код для проверки состояния файлов.
За перенос данных в клиенте отвечает команда mc mirror, которая:
- сравнивает содержимое исходного и целевого бакетов;
- копирует новые и измененные объекты;
- опционально удаляет из целевого хранилища те объекты, которых уже нет в источнике.
Важно учитывать, что mc mirror не выполняет непрерывную репликацию в реальном времени. Утилита работает исключительно по запросу, и каждый ее запуск инициирует полное сканирование обоих бакетов. Чтобы постоянно поддерживать актуальность данных в резервном хранилище, этот процесс необходимо автоматизировать самостоятельно с помощью внешних инструментов — например, планировщика cron, настройку которого разберем далее.
Если в целевом бакете включено версионирование, любое обновление объекта приведет к созданию его новой версии. В таком случае может произойти неконтролируемый рост занимаемого хранилищем, дискового пространства. Для базовых задач синхронизации включать эту опцию не обязательно.
Клиентская синхронизация vs серверная репликация
Организовать обмен данными между независимыми площадками можно по‑разному. Один способ — задействовать встроенные механизмы самих S3‑кластеров. Другой — управлять процессом извне с помощью отдельных утилит.
Серверная репликация
mc replicate — встроенный механизм MinIO, работающий на стороне самого хранилища. В отличие от клиентской синхронизации, репликация реагирует на события создания и изменения объектов в реальном времени и автоматически отправляет новые данные на резервную площадку.
Особенности:
- автономность — процесс протекает в фоновом режиме, не требует запуска вручную или настройки внешних планировщиков;
- точность — фиксируются любые операции с объектами: от создания и модификации до полного удаления, что обеспечивает строгую консистентность бакетов;
- ограниченная совместимость — инструмент работает исключительно с хранилищами MinIO, применить его для других S3-совместимых решений не получится.
Серверная репликация идеально подходит для задач, требующих работы с данными в реальном времени и работает только внутри экосистемы одного вендора.
Клиентская синхронизация
Именно этот способ мы разберем в статье. Команда mc mirror запускается вручную или по расписанию, просматривает содержимое исходного и целевого бакетов, сравнивает их, а затем копирует недостающие или измененные объекты на резервную площадку.
Особенности:
- простота — синхронизация выполняется только при вызове команды, поэтому для непрерывности процесса требуется внешний планировщик;
- дискретность — в отличие от репликации, клиент не отслеживает операции в реальном времени;
- универсальность — инструмент не привязан к конкретному вендору и может работать с разными S3-совместимыми хранилищами.
Пример:
mc mirror source/bucket target/bucket
Клиентская синхронизация незаменима при миграции между разными S3-провайдерами или для периодического резервного копирования. Именно поэтому в статье мы рассматриваем mc mirror — инструмент максимально универсальный, независимый от архитектуры хранилища, и, при этом, чрезвычайно простой в использовании.
Типы синхронизации в MinIO
Двунаправленная синхронизация
В распределенных архитектурах новые объекты часто создаются одновременно на двух независимых площадках. Например, если часть сервисов работает в Москве, другая — в Санкт-Петербурге, то оба кластера параллельно принимают трафик на запись. В подобных сценариях требуется двунаправленная синхронизация, чтобы любые изменения в одном бакете встречно транслировались и в другой.
Cluster 1 (СПб) ◄────► Cluster 2 (Москва)
Для такого режима в mc mirror есть флаг --active-active. Он активирует двустороннюю синхронизацию. Важно: команду нужно выполнить на каждой из площадок. При конфликте, — когда один и тот же объект изменился в обоих местах, — побеждает более свежая по времени изменения версия.
# Запускается на каждой площадке!
mc mirror --active-active s3-ru7/backups s3-ru3/backups-replica
Особенности:
- параллельная запись — все кластеры остаются полностью доступны для добавления и модификации файлов;
- встречный обмен — изменения распространяются в оба направления при каждом запуске синхронизации;
- требуется осторожность и четкое понимание логики приложения — например, без флага
--removeриск случайной потери данных меньше, но удаленные на одной площадке файлы могут восстанавливаться с соседнего кластера при следующем цикле синхронизации.
Веерная синхронизация
Если нужно поддерживать актуальные копии данных сразу на нескольких площадках достаточно выполнить команду mc mirror соответствующее количество раз — по одному на каждый целевой бакет.
Primary (ru-3) ─────► Replica 1 (ru-7)
Primary (ru-3) ─────► Replica 2 (ru-9)
Важно понимать: mc mirror всегда работает с парой «один источник — один целевой бакет». Схема с тремя и более равнозначными кластерами, синхронизирующими друг друга в произвольном порядке, mc mirror не поддерживается. Для полноценной веерной синхронизации между MinIO-кластерами потребуется серверная репликация с помощью mc admin replicate.
Особенности:
- индивидуальный запуск — каждый целевой бакет требует отдельного выполнения команды;
- оптимально для георезервирования — подходит для простых сценариев резервирования в несколько регионов.
Требования к окружению
Прежде чем переходить к настройке, давайте подготовим инфраструктуру. В соответствии с выбранным сценарием, развернуты два кластера: основной кластер в Санкт-Петербурге и резервный в Москве. Для работы синхронизации потребуется несколько компонентов.
Бакеты S3
Нам понадобится два бакета — по одному в каждой локации. У бакетов должен быть доступный S3 API-эндпоинт. В качестве примера рассмотрим следующие адреса::
s3.ru-3.storage.selcloud.ru— Санкт-Петербург (исходный бакет),s3.ru-7.storage.selcloud.ru— Москва (целевой бакет).
Пользователь с правами доступа
Для авторизации утилиты потребуется выделить отдельного пользователя или создать сервисный аккаунт, обладающий доступом к обоим хранилищам.
Базовый набор IAM-политик должен разрешать чтение данных из источника и их запись на резервную площадку. Если же планируется строгая синхронизация с очисткой неактуальных файлов (при использовании флага --remove), учетной записи дополнительно потребуются привилегии на удаление объектов в целевом бакете.
MinIO Client
И последний инфраструктурный компонент — mc, утилита командной строки MinIO Client, которая дает возможность управлять хранилищем. С ее помощью можно:
- подключаться к кластерам MinIO,
- создавать бакеты,
- включать версионирование,
- настраивать правила репликации,
- проверять статус синхронизации данных.
Именно через mc мы будем выполнять все дальнейшие настройки.
Выполняем синхронизацию
Теперь можно переходить к практической части. Алгоритм будет следующий.
- Установим MinIO Client (mc) — подготовим инструмент для взаимодействия с инфраструктурой.
- Создадим бакеты — развернем их на исходной и целевой площадках, между которыми будет происходить перенос данных.
- Подключим оба бакета через alias — добавим исходный и целевой S3 в конфигурацию
mc, чтобы работать с ними в рамках одной команды. - Запустим синхронизацию вручную — проверим, что все работает, прежде чем автоматизировать.
- Проверяем, что синхронизация выполнена — получим подтверждение, что первые действия вручную успешно отработали.
- Автоматизируем запуск — настроим планировщик
cron, чтобы синхронизация запускалась по расписанию. - Проверим результат — загрузим файл и убедимся, что он появился во втором хранилище.
Установка MinIO Client
Начнем с установки MinIO Client на сервер или локальную машину, на которой будет запускаться синхронизация.
Linux
Для установки утилиты потребуется загрузить бинарный файл, сделать его исполняемым и добавить директорию с ним в системную переменную PATH:
curl https://dl.min.io/client/mc/release/linux-amd64/mc \
--create-dirs \
-o $HOME/minio-binaries/mc
chmod +x $HOME/minio-binaries/mc
export PATH=$PATH:$HOME/minio-binaries/
macOS
На macOS проще всего установить MinIO Client с помощью менеджера пакетов Homebrew:
brew install minio/stable/mc
Windows
В этом случае придется немного попотеть.
1. Скачиваем MinIO Client с официального сайта и кладем бинарник в удобную директорию — например, C:\tools\mc\.
2. Чтобы вызывать клиент из любой папки, путь к нему нужно прописать в системе. Для этого через поиск Windows найдем раздел «Изменение системных переменных среды», откроем меню «Переменные среды», выберем переменную Path и нажав кнопку «Изменить» добавим директорию с mc.
3. Чтобы новые значения переменных окружения вступили в силу, бывает нужно перезапустить терминал (в некоторых случаях — саму операционную систему).
4. Проверим корректность установки с помощью простой команды в PowerShell:
mc --version
Успешный вывод версии говорит о готовности к работе. Можно двигаться дальше.
Если при подключении возникает ошибка верификации, потребуется единоразово добавить сертификат хранилища вручную.
- Откроем в браузере адрес S3-эндпоинта — например,
https://s3.ru-7.storage.selcloud.ru. - Нажмем на значок сертификата (иконка закрытого замка) в адресной строке и скачиваем сертификат
- Откроем скачанный файл, перейдем на вкладку Состав и выберем опцию Копировать в файл.
- Сохраняем в формате Base-64 encoded X.509 (.cer).
После этого можно корректно работать с эндпоинтом S3 без ошибок TLS.
Подключение к Selectel S3
Теперь, когда MinIO Client установлен и готов к работе, можно подключить наши бакеты в ru-3 (Санкт-Петербург) и ru-7 (Москва). Потребуется несколько шагов.
В нашей онлайн-документации есть инструкция по подключению MinIOс Client к S3 Selectel.
Шаг 1. Создаем бакеты
Бакетов понадобится два, в разных регионах. Однако поскольку создание одного из них ничем не отличается от другого, рассмотрим весь процесс на единственном примере.
1. В панели управления в верхнем меню откроем Продукты и перейдем в S3 и далее в раздел Бакеты. Нажмем Создать бакет.
2. Придумаем имя для бакета. Здесь есть пара ограничений, которые диктуют совместимость с S3 API. Во‑первых, имя должно быть уникальным среди всех пользователей в том же пуле. Во‑вторых, допустимы только некоторые символы: цифры, латинские буквы, точка и дефис. Полные правила — в документации Amazon: Bucket naming rules.
3. Выберим регион и пул. В нашем примере первый бакет расположен в санкт‑петербургской локации ru-3, второй — в московской ru‑7.
4. В блоке Конфигурация зададим параметры хранилища.
Тип доступа выберем Приватный — наши бакеты для резервного копирования, публичный доступ им ни к чему.
Класс для бэкапов подойдет Холодное хранение — обращение к данным происходит нечасто. Важно: класс нельзя изменить после создания бакета.
Тип адресации: возьмем vHosted — это рекомендуемый вариант для работы с S3 API.
Версионирование для базовой синхронизации включать не обязательно. Если требуется хранить историю изменений объектов — нужно отметить чекбокс Версионирование в блоке Защита данных, но надо иметь в виду, что это существенно увеличит объем хранилища.
5. Нажмем Создать бакет.
Шаги выше повторим для другого региона.
Шаг 2. Создаем сервисного пользователя
Для взаимодействия с обоими хранилищами утилите mc mirror потребуются ключи доступа.
Согласно лучшим практикам безопасности, вместо использования реквизитов владельца аккаунта следует завести отдельного сервисного пользователя — специальную учетную запись. У него не будет права входить в панель управления, но он сможет иметь доступ к ресурсам: скриптам, автоматизированным задачам и утилитам.
Процесс создания учетной записи состоит из нескольких простых шагов.
1. В верхнем меню панели управления нажмем IAM и перейдем в раздел Сервисные пользователи.
2. Нажмем Добавить сервисного пользователя и придумаем ему имя — например, s3-mirror-bot.
3. В блоке Настройки доступа добавим разрешение. Область доступа — Аккаунт или Проекты При выборе второго варианта укажем проект, в котором находятся бакеты. Роль — s3.admin, что достаточно для чтения и записи объектов через S3 API.
4. Нажмем Добавить пользователя.
Сервисный пользователь не может сгенерировать ключи самостоятельно. Эту операцию выполняет владелец инфраструктуры или администратор с ролью iam.admin. Последовательность действий следующая.
1. Откроем страницу только что созданного пользователя и перейдем на вкладку Доступ.
2. В блоке S3-ключи нажмем Добавить ключ и введем произвольное имя — например, mirror-ru3, после чего выберем проект с первым бакетом в ru-3.
3. Нажмем Сгенерировать.
4. Скопируем и сохраним оба значения: Access key и Secret key. После закрытия окна Secret key нигде больше не отобразится. Если он потерян, придется генерировать ключ заново.
5. Повторим все шаги и для второго проекта в ru-7, назвав ключ, например, mirror-ru7.
Теперь у нас два набора ключей — по одному на каждый регион. Именно их мы будем использовать при настройке алиасов в mc.
Шаг 3. Добавляем alias для каждого региона
Каждый регион Selectel — это отдельный S3-эндпоинт. В mc мы создаем для них «псевдонимы» (alias), чтобы легко работать — не набирать каждый раз длинные строки, рискуя опечаться:
mc alias set s3-ru3 https://s3.ru-3.storage.selcloud.ru <AccessKey> <SecretKey>
mc alias set s3-ru7 https://s3.ru-7.storage.selcloud.ru <AccessKey> <SecretKey>
Псевдонимы в примере выше:
s3-ru3— основной бакетru-3в Санкт-Петербурге,s3-ru7— резервный бакетru-7в Москве.- <AccessKey> <SecretKey> — значения соответствующих полей из S3-ключей.
Теперь mc знает, где искать каждый бакет.
Шаг 4. Проверяем подключение
Чтобы убедиться, что все работает и mc видит бакеты, выполним:
mc ls s3-ru3
mc ls s3-ru7
Должен появиться список бакетов в каждом регионе. Если ошибки нет — подключение успешно.
Настройка синхронизации между регионами
Отлично, у нас есть два подключенных бакета. Теперь — главное: настроим автоматическое копирование данных из Санкт-Петербурга в Москву.
Шаг 1. Пробный запуск синхронизации
Для начала запустим синхронизацию вручную, чтобы убедиться, что все работает:
mc mirror --overwrite --remove s3-ru3/backups s3-ru7/backups-replica
Разберем, что делает эта команда:
- берет все объекты из источника в
ru-3, - копирует их в резервное хранилище
ru-7, - принудительно обновляет измененные файлы за счет флага
--overwrite, - благодаря действию флага
--removeудаляет из целевой площадки лишние объекты, которых больше нет в бакете-источнике.
Если в исходном хранилище уже есть данные, копироваться они начинают незамедлительно.
Шаг 2. Проверяем, что все копируется
Проверим на простом примере. Загрузим файл в основной бакет:
mc cp test.txt s3-ru3/backups/
Снова запустим синхронизацию:
mc mirror --overwrite --remove s3-ru3/backups s3-ru7/backups-replica
Убедимся, что объекты появились во втором регионе:
mc ls s3-ru7/backups-replica
Если все подключено и настроено правильно, вывод команды mc ls покажет файл test.txt.
Шаг 3. Делаем репликацию постоянной
На предыдущем шаге мы запускали синхронизацию вручную. Но в реальной жизни нужен автоматический механизм. В Linux для этого используется cron — системный планировщик задач.
Следующая команда открывает на редактирование нужный конфигурационный файл:
crontab -e
Добавляем строку, которая будет запускать синхронизацию каждую минуту. Важное уточнение: отрезок времени приведен для примера. На практике использовать столь короткие промежутки — не самая хорошая идея, так как возникает неоправданная нагрузка и риск конфликтов между не завершившимся задачами.
* * * * * mc mirror --overwrite --remove s3-ru3/backups s3-ru7/backups-replica
Разберем эту строку:
* * * * *
│ │ │ │ └── день недели (0-7, 0 и 7 = воскресенье)
│ │ │ └──── месяц (1-12)
│ │ └────── день месяца (1-31)
│ └──────── час (0-23)
└────────── минута (0-59)
Пять звездочек (* * * * *) = выполнять каждую минуту
После сохранения конфигурации схема будет работать по следующему алгоритму.
- Сторонний сервис загружает файл в исходный бакет в
ru-3. - В течение заданного промежутка времени (в примере минуты) срабатывает
cron. - Утилита
mc mirrorсканирует хранилище, обнаруживает изменения и переносит данные на резервную площадкуru-7.
Никакого ручного вмешательства больше не требуется. Главное — иметь постоянно работающий сервер, который позволит раз в заданное время применять данную команду.
Шаг 4. Фильтрация объектов (опционально)
До этого момента мы рассматривали базовый сценарий, при котором содержимое исходного бакета переносится целиком. На практике так бывает не всегда.
В одном бакете могут одновременно находиться рабочие файлы, резервные копии, временные выгрузки, логи и прочее. Далеко не всегда все это нужно отправлять во второй регион. Во многих случаях задача звучит иначе — синхронизировать только полезные данные, а все лишнее — исключить.
Именно для таких случаев в mc mirror предусмотрены фильтры. Самый частый сценарий — исключить из репликации временные или ненужные данные. Для этого можно воспользоваться параметром --exclude. Например, чтобы проигнорировать файлы с расширением .tmp:
mc mirror --exclude "*.tmp" s3-ru3/backups s3-ru7/backups-replica
Все объекты, не попавшие под это правило синхронизируются как обычно.
Иногда наоборот требуется переносить не все, а только конкретный тип данных. Выручит параметр с противоположным действием — --include. Например, дублироваться на резервном хранилище должны только файлы .jpg:
mc mirror --include "*.jpg" s3-ru3/backups s3-ru7/backups-replica
Во второй регион попадут только файлы с указанным расширением.
В рамках одного запроса фильтры можно объединять, если требуется более точная логика:
mc mirror \
--include "*.jpg" \
--exclude "archive/*" \
s3-ru3/backups s3-ru7/backups-replica
В примере выше изображения будут синхронизироваться, но только не те, что расположены в архивном каталоге.
Зачастую эффективнее отбирать объекты не по расширению, а отталкиваясь от готовой структуры каталогов. Если целевые файлы уже сгруппированы в отдельной папке, достаточно указать соответствующий префикс прямо в путях источника и назначения:
mc mirror s3-ru3/backups/db s3-ru7/backups-replica/db
Ограничения и риски при репликации через mc mirror
Несмотря на всю простоту данной схемы репликации, отрабатывает она не идеально.
Важно понимать базовую вещь: mc mirror не отслеживает изменения в реальном времени. Каждый запуск работает по одному принципу:
- получает список объектов в исходном бакете,
- получает список объектов в бакете целевом,
- вычисляет различия,
- выполняет копирование.
То есть это полный сравнительный проход, а не обработка событий. Такой способ может привести сразу к нескольким проблемам.
В первую очередь, накладные расходы на LIST-операции линейно растут вместе с количеством объектов. Соответственно при «тяжелых» бакетах синхронизация становится заметно медленнее, а частые запуски выдают «diff overhead».
При росте количества объектов синхронизация даже самых маленьких изменений может обойтись в серьезные суммы — ведь каждый раз запрашивается полный список объектов и сравнивается каждый из них.
При использовании --remove целевой бакет становится точной копией исходного. Это означает, что mc не только добавляет новые объекты и обновляет измененные файлы, но и удаляет все, чего нет в источнике. Возникает опасность деструктивной очистки, ведь «нет в source-бакете» не всегда означает «не нужен».
Например, если upstream-система на какое‑то время перестала писать данные, очистила временные файлы, пересоздала структуру бакета, то с флагом --remove ситуация в точности воспроизведется и в downstream‑хранилище. Целевой бакет будет просто «зеркалить» проблему. Для защиты критически важных данных на резервной площадке, можно воспользоваться механизмом S3 Object Lock, заблокировав возможность удаления определенных объектов.
Особенности mc mirror и альтернативы
mc mirror — это все-таки инструмент синхронизации состояния, а не полноценная система доставки или репликации данных.
Почти real-time сценарии
Если от системы ожидается появление файла во втором регионе «почти сразу после загрузки» — mc mirror здесь не поможет. Он не реагирует на событие создания объекта, а периодически сравнивает два состояния. Время доставки зависит от частоты запуска — и ее невозможно гарантировать.
Частые изменения и «шумные» данные
Особенно плохо mc mirror чувствует себя в системах, где много мелких файлов, происходят постоянные изменения, а жизненный цикл объектов очень короткий. В таком случае один и тот же набор объектов постоянно пересчитывается, из-за чего создается избыточная нагрузка на S3 LIST и фактическая синхронизация начинает занимать заметное время даже без изменений.
Какие есть альтернативы
Лучшее решение — сочетание двух подходов. Событийная (event-driven) модель берет на себя оперативную доставку: вместо сравнения состояний система реагирует на сами события изменения объектов, поэтому постоянные LIST-запросы не нужны. А периодический mc mirror подключается отдельно — не для основной доставки данных, а для сверки состояний и устранения возможных расхождений.
mc mirror — это удобный инструмент синхронизации S3-хранилищ, но важно правильно понимать его роль. Такой способ репликации хорошо подходит там, где допустима задержка, а простота важнее, чем строгая событийность — например, для простого переноса данных. А вот в случаях, где важна минимальная задержка, критична строгая консистентность и контроль операций, mc mirror уже не так эффективен.