Как стать автором
Поиск
Написать публикацию
Обновить
86.33
Magnit Tech
Соединяем IT и ритейл

Сохранение и восстановление версии бакета объектного хранилища MinIO S3 с учетом содержимого и конфигурации

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

Меня зовут Михаил, я работаю в Magnit Tech и занимаюсь внедрением 1C платформы на операционную систему Linux. В этой статье я расскажу, как реализовать создание резервных копий бакетов S3-совместимого объектного хранилища MinIO.

(Сразу дам спойлер: нам удалось это сделать с наименьшими затратами места на диске с использованием инкрементальных бэкапов в виде обычного BASH скрипта).

В платформе 1С с версии 8.3.23 появилась поддержка работы с объектным хранилищем S3. Все файлы, которые раньше записывались в БД теперь могут быть автоматически адресованы в объектное хранилище. При этом основной недостаток 1С — любое изменение файлов в хранилище приводит к удалению старого файла и созданию нового с новым именем.

То есть мы не можем отслеживать изменения файлов в хранилище. И на вопрос «зачем?» — резервная копия бакета (конфигурация + содержимое) может быть полезна для воспроизведения тестов работы с хранилищем и восстановления конкретного состояния объектного хранилища, если оно сильно раздулось.
То есть в 1C при крайне больших объемах данных восстановление версии будет происходить очень и очень долго при простом перетаскивании файлов и создании этого бакета.

Из данной ситуации вытекает задача — реализовать возможность бэкапировать S3-бакет с наименьшими затратами.

"Хочешь что-то спрятать - положи на самое видное место."
"Хочешь что-то спрятать - положи на самое видное место."

Краткое описание понятий (погружение в теорию)

Если вы шарите в MinIO или в других схожих S3-совместимых объектных хранилищах, то пропускайте этот раздел, тут мы пройдемся по базе MinIO.

С целью облегчить понимание вопроса дадим краткое описание используемых понятий:

Cловарь терминов
  • MinIO S3 — это S3-совместимое (Simple Storage Service / Сервис простого хранилища) объектное хранилище, которое предоставляет доступ к содержимому через протоколы HTTP/HTTPS, оно состоит из выделенных одноуровневых ячеек хранения — бакетов, в которых хранятся файлы (объекты) по указанным префиксам, например, «https://127.0.0.1:9001/mybucket/myfile».

  • Бакет (Bucket / Корзина) отдельная ячейка хранения группы объектов со своей конфигурацией, содержащей правила предоставления доступа, удержания объектов, включение версионирования и т. п. Множество бакетов легко воспринимать как одноуровневую файловую структуру, где ниже бакета спуститься нельзя, то есть все что идет после бакета — это не папки как файловой структуре, а префиксы (пространство имен) по которым мы можем различать объекты между собой.
    Соответственно пустых префиксов в бакете быть не может. Пример, префикса в формате URL с HTTPS протоколом: «https://127.0.0.1:9001/mybucket/folder‑with‑png/image.png».

  • Объекты (Objects) — это файлы различных форматов (CSV, XLS, TAR, ZIP, MP3, MP4, JPEG, PNG и т. д.), которые хранятся в бакете.

  • Префикс (Prefix) является ключом для доступа к объекту. Он представляет из себя строку, состоящую из наименований уровней иерархии, например, «folder1» и разделителей, например «/». Он создается только при создании объектов и не может существовать без них. Префикс позволяет имитировать структуру файловой системы.

Более кратко понятия изложены в словаре официальной документации MinIO

S3-совместимое объектное хранилище мы можем выбрать в роли альтернативы для хранения неструктурированных данных. Например, мы можем хранить таблицы (CSV, XSLX), видео, картинки, аудио (MP4, JPEG, PNG, MP3) и так далее.

Одним из его основных преимуществ является возможность производить горизонтальное масштабирование.

Помимо MinIO S3 имеется множество различных реализаций этого хранилища, например, AWS S3, Google Cloud Storage, Azure Cloud.

Основное использование MinIO S3 — это разгрузка БД, в которых хранятся BLOB (Binary Large OBject) файлы (картинки, архивы и прочие неструктурированные данные, безжалостно пожирающие место на жестком диске).

Пример кейса из реальной жизни: у нас при переносе 1C с серверов Windows Server на Linux встретились тяжеловесные БД MS SQL Server, где большей частью размеров оказались неструктурированные данные.

На этом наше теоретическое введение заканчивается. Перейдем к основной части.

Чего мы хотим

Процитирую задачу:

«Есть хранилище S3 с произвольным количеством бакетов, нужно делать их бэкапы для возможности восстановления конфигурации и состояния всех файлов на конкретную дату (в т.ч. удаленных) при этом максимально сэкономить используемое место под бэкапы.»

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

Стоит учесть, что некоторые опции бакета нам не требуется сохранять, например, версионирование в объектном хранилище с 1C не будет применяться.

Удивительно, но найти ответ на вопрос «Как бэкапить бакет S3?» оказалось не так просто. Поисковик Google и даже всезнающая LLM DeepSeek не выдавали нам релевантный ответ. В конце концов приняв тот факт, что эта тема не имеет широкого распространения мы обратились к официальной документации MinIO! И тут мы также не встретили готового решения. Разве что только намеки на то как это можно реализовать.

Предварительная подготовка инструментов MinIO

Этот шаг можно тоже пропустить, так как тут я только описываю установку базовых инструментов — Docker, CLI клиент и сервер MinIO перед изучением различных решений, которые я находил в процессе исследования вопроса.

Для того чтобы мы могли практически убедиться в работе исследуемых решений мы решили развернуть тестовый сервер MinIO с топологией Single-Node Single-Drive (SNSD) в Docker контейнере, поскольку это просто и не требует много времени на настройку (ссылочка на инструкцию по установке сервера minio).

Для администрирования нашего сервера мы взяли заботливо предложенную утилиту mc.

Инструменты и их версии:

Сервер MinIO — RELEASE.2024–11–07T00–52–20Z

CLI клиент MinIO mc — RELEASE.2024–11–17T19–35–25Z

Docker клиент и сервер — версия 27.3.1, API версии 1.47

Развертывание тестового MinIO сервера с помощью Docker:

$sudo docker pull minio/minio:latest
$sudo mkdir -p /var/minio/data
$sudo docker run -d \
    -p 9000:9000 \
    -p 9001:9001 \
    --name minio \
    -v /var/minio/data:/data \
    -e "MINIO_ROOT_USER=ROOTNAME" \
    -e "MINIO_ROOT_PASSWORD=CHANGEME123" \
    minio/minio server /data --console-address ":9001"

Как видно для сервера мы указали переменные MINIO_ROOT_USER и MINIO_ROOT_PASSWORD, они указывают имя и пароль root пользователя. Запоминаем их.

После запуска сервера в Docker контейнере мы можем войти в консоль MinIO в браузере под именем root пользователя по следующему URL «http://localhost:9001/»:

Отлично Мы имеем свой локальный MinIO сервер и можем иметь к нему доступ через консоль в браузере (MinIO Web интерфейс).

Так как консоль не может покрыть все наши административные «хотелки», мы дополнительно установили CLI клиент MinIO — mc.

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

Установка mc на нашу тачку с ОС Linux — Debian 11 и архитектурой 64 bit Intel производиться с помощью следующих команд:

$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/

Проверка работы:

$mc --help

Указываем alias развернутого MinIO сервера для mc c указанием имени и пароля пользователя под которым будем выполнять операции:

$mc alias set local http://localhost:9000 ROOTNAME CHANGEME123

Проверяем все ли на месте командой mc ping:

$mc ping local

Результат:

Немного про mc:

mc — он же CLI клиент MinIO, удобный инструмент для взаимодействия как с локальной файловой системой, так и с S3-совместимым хранилищем, то есть как и в Unix системах мы имеем стандартные команды ls, cp, mv, rm, вместо rsync — mirror для работы с файловой системой и с S3, также имеем команды работающие только для S3-совместимого хранилища, например, mc admin info.

Он имеет два режима: mc и mc admin

mc — для любого хранилища

mc admin — только для работы с MinIO S3 и AWS S3

Получив все базовые инструменты мы можем перейти к самой увлекательной рубрике ээээксперементы!

Поиск решения

Для понимания того насколько решение полное требуется иметь ответы на следующие вопросы:

  1. Что вообще представляет из себя конфигурация бакета?

  2. Что мы можем знать об объектах?

Ответ на первый вопрос «Что вообще представляет из себя конфигурация бакета?»:

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

Конфигурация бакета состоит из следующих опций:

  • Версионирование объектов (Versioning)
    Описание: Позволяет хранить несколько версий одного объекта, что полезно для восстановления данных после случайного удаления или перезаписи. Версионирование объектов может быть включено «enabled» единожды и после только приостановлено «suspended» [ссылка].
    Применение: Включается для обеспечения возможности восстановления предыдущих версий файлов.

  • Политики удержания объектов (Object Lock)
    Описание: Позволяет блокировать объекты от удаления или изменения на определенный период времени. Эту опцию можно включить только при создании бакета и только с версионированием.

  • Применение: Используется для обеспечения неизменности данных, что важно для соответствия нормативным требованиям.

  • Квота (Quota)
    Описание: Позволяет ограничивать объем данных, которые могут быть сохранены в бакете.
    Применение: Используется для контроля использования ресурсов.

  • Теги (Tags)
    Описание: Тегирование позволяет добавлять метаданные к объектам в виде ключевых пар (ключ‑значение). Теги могут использоваться для классификации, поиска и управления объектами.
    Примечание:
    Теги полезны для организации данных и применения политик на основе метаданных. Теги можно использовать в сочетании с Object Lifecycle Management и Access Control.

  • Жизненный цикл объектов (ILM / Object Lifecycle Management)
    Описание: Позволяет автоматически удалять или перемещать объекты по истечении определенного времени или при выполнении других условий.
    Применение: Используется для оптимизации хранения и управления данными.

  • Цели бакета (Bucket targets)
    Описание: Целевые места транспортировки объектов, при истечении установленного срока или для размещения объектов на удаленном сервере.
    Применение: Разгрузка диска действующего сервера путем перемещения файлов на другой менее используемый сервер.

Ответ на второй вопрос «Что мы можем знать об объектах?»:

Объекты в MinIO — это единицы данных, которые хранятся в бакетах. Каждый объект имеет следующие характеристики:

  • Ключ (Key): Уникальный идентификатор объекта в бакете.

  • Метаданные (Metadata): Дополнительная информация об объекте, такая как тип содержимого, размер, дата создания и пользовательские теги.

  • Опционально версия (Version): Если версионирование включено, объект может иметь несколько версий, каждая из которых сохраняется отдельно.

  • Уровень хранения (Storage Tier): Объект может находиться на горячем, холодном или архивном уровне хранения в зависимости от настроек Tiering.

Итого:

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

1. Версионирование объектов

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

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

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

И прилагающиеся следующие проблемы:

  • Сохраняются только версии объектов, без сохранения конфигурации самого бакета.

  • Место на диске занимается не эффективно, так как MinIO не предоставляет инкрементный или дифференциальный тип версионирования, поэтому каждая новая версия будет иметь свой полный размер (За исключением удалений). Это может сильно сказаться на потреблении пространства диска.
    MinIO does not perform incremental or differential-type versioning. For mutation-heavy workloads, this may result in substantial drive usage by older or aged object versions. [ссылка]
    Например, мы имели громоздкий файл ZIP на 30 Гб и чуть-чуть поменяли, добавлением 1 Гб данных, в итоге у нас имеется 2 версии: V1 размером 30 Гб и V2 размером 31Гб.

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

  • Перенос версий возможен только с помощью репликации.

  • 1C удаляет объект (файл) и создает новый с новым именем, что просто будет требовать идентифицировать какой требуется заменить.

Тем не менее, посмотрим как производить базовые операции для включения версионирования, как отображать версии объектов, как производить восстановление версии. 

1.1 Включение версионирования бакета

Версионирование включается у бакета как при его создании, так и после. При выключении версии объектов не будут удалены и при загрузке нового объекта ему будет присвоен ID null. Более подробно об версионировании бакета можно узнать из официального источника MinIO.

Включение версионирования бакета при создании:

$mc mb --with-versioning <server-alias>/<bucket>

Пример:

Включение версионирования у бакета, если оно выключено:

$mc version enable <server-alias>/<bucket>

Пример:

Проверка наличия версионирования:

$mc version info –json <server-alias>/<bucket>

Пример:

1.2 Просмотр файлов в бакете

Любая версия в бакете имеет присвоенный уникальный ID, а также маркер, который может иметь значение либо PUT — загружен, либо DEL — удален.

Чтобы посмотреть на версии можно использовать как Web интерфейс MinIO «консоль», так и любой совместимый с MinIO CLI клиент, например, mc, rclone, aws и так далее.
Предварительно повторим ситуацию, когда мы имеем файл в бакете с несколькими версиями.

Для этого помещаем файл в бакет с версионированием и производим его удаление, после вносим изменения в локальный файл и загружаем его в бакет с новым именем:

# Включаем у существующего бакета версионирование
$mc version enable local/cs-bucket
# Помещаем файл в бакет
$mc put S3_on-premis_ОС.xlsx local/cs-bucket
# Удаляем файл в бакете
$mc rm local/cs-bucket/S3_on-premis_ОС.xslx 
# Вносим изменения в файл 
$echo “New altering!” >> S3_on-premis_ОС.xslx 
# Помещаем файл с изменениями в бакет с заданным наименованием
$mc put S3_on-premis_ОС.xslx local/cs-bucket/S3_on-premis_ОС-new-name.xslx
# Теперь отображаем что же у нас получилось:
# Команда, чтобы отобразить все версии файлов, которые не младше 5 секунд
$mc ls –rewind "0d0h0m5s" --versions local/cs-bucket

Версии объектов в бакете с включенным версионированием выглядят следующим образом:

Как видно удаленные файлы помечаются меткой DEL и вся их функция заключается в том, чтобы сообщать пользователю о том, что этот файл был удален в указанное время.

Также у удаленных файлов как и у загруженных имеются такие же поля как дата и время, размер, место размещения, ID версии, номер версии, маркер и имя. 

1.3 Восстановление версии

Вот тут мы наткнулись на камень.

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

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

Так мы создадим вторую версию действующего файла, которая основана на содержимом прошлой версии.

$mc cp --version-id <id> <server-alias>/<bucket-1>/<object> <server-alias>/<bucket-2>/<object>

Восстановление запускается по ID версии объекта.

Самый простой способ использовать Web интерфейс, где можно отобразить все версии объекта и восстановить выбранную.

Для этого мы можем зайти в консоль и выбрать интересующий нас объект.

Восстановление маркера удаления файла не произведет ничего, поэтому требуется восстанавливать версию до них или после них.

Иначе нам придется плясать танцы с бубном, поскольку альтернатива - выгружать объект нужной версии.

2. Синхронизация содержимого

Тоже очень простая идея синхронизировать содержимое обычного бакета с содержимым бакета с версионированием.

То есть мы таким образом можем переносить версию объекта перед его удалением и созданием нового. Только будет та же проблема с поиском имени нового объекта.

Для этой задачи можно использовать множество инструментов: mc mirror, rclone, restic и тому подобные инструменты наподобие rsync.

Мы же покажем только mc mirror и rclone:

# Синхронизация содержимого mybucket-version с mybucket с mc
$mc mirror local/mybucket local/mybucket-version

# Синхронизация содержимого
$rclone sync local:mybucket local:mybucket-version

2. Репликация бакета

Второй вариант который мы рассматривали — репликация бакета.

Ее мы долго не рассматривали, так как она изначально очень громоздкая, но позволяет нам сохранять состояние бакета идентичное состоянию оригинала (опции в конфиге + содержимое).

Идея заключается в том, чтобы производить синхронизацию бакета из сервера источника в сервер хранения версий состояния файлов.

Она нас заинтересовала возможностью сохранять все опции бакета. Однако, как оказалось это решение неэффективно, поскольку вместо 1 сервера нам потребуется запускать 2, и вместо пачки версий объектов мы будем хранить 2 пачки версий объектов.
По нему мы не будем проходить долго, так как изначально это модифицированная версия первого подхода.
То есть теперь мы будем производить сохранение полной резервной копии бакета каждый раз когда будет происходить изменение.
В плане выполнения пункта об эффективнос ти мы сразу же скажем, что 
Имеется 2 варианта репликации:

Репликация бакета со стороны клиента - mc mirror (сохраним только объекты)

Client-side Bucket Replication

Use the command process to synchronize objects between buckets within the same S3-compatible cluster or between two independent S3-compatible clusters. Client-side replication using mc mirror supports MinIO-to-S3 and similar replication configurations. [Ссылка]

Репликация бакета со стороны сервера (опции в конфиге + объекты)

Репликация бакета (не site) фактически создает реплику на указанный бакет с сохранением конфигурации (за некоторыми исключениями) и с сохранением содержимого в другое S3 совместимое хранилище (MinIO, AWS S3, Google Cloud Storage, Azure BLOB Storage).

В таком случае мы будем иметь реплику бакета, которая будет обновляться в определенное время до удаления файла в 1C. И в случае чего мы сможем ее подтянуть, когда нам это понадобиться.
Что само собой очень затратно и сложно в реализации, поэтому мы продолжили искать более щадящие способы.
Если это будет интересно, то напишите в комментариях я постараюсь рассмотреть этот подход тоже в следующей статье.

4. Бэкап данных minio-data с указанием конкретного бакета

Третий вариант, который мы нашли за исключением одного большого НО появился у нас в мыслях на основе комментария на stack-overflow. Смысл подхода прост - бэкапить папку с minio-data, причем только того бакета, который нам требуется. Итого мы имеем бэкап бакета, который будет хранить в себе состояние всех файлов (метаданные и содержимое) на указанный промежуток времени без сохранения конфигурации бакета (только его имя).

А теперь большое НО:

Стоит отметить, что идея не официальная и ни в коем случае не поддерживается разработчиками MinIO (из описания официальной документации). Тем не менее, она работает и может послужить в некоторых случаях как выход из ситуации когда требуется производить бэкап состояния одного или нескольких бакетов MinIO сервера, где кластер имеет только один диск.

Как реализовать:

1) В качестве источника содержимого бакета мы используем путь указанный при развертывании MinIO сервера, например, /var/minio/data/<bucket>

2) Если скопировать данную папку с одного сервера MinIO S3 в путь хранения бакетов другого или того же самого сервера, то будет произведено восстановление бакета с учетом содержимого, но без полной конфигурации.

Например мы захотели воссоздать наш бакет test1 с сервера local на сервере test. Для этого используя WinSCP производим незатейливую манипуляцию копирования папки.

Проверяем результат на локальном и тестовом сервере

Ура, мы смогли получить результат, который дает нам мысль наладить создание архивов данных папок с запуском скрипта в CRON, так как все просто и понятно в плане того, что мы можем сохранить бакет (имя бакета + состояние объектов). Отдельные опции, которые нам потребуется включать мы сможем устанавливать уже вручную. Для тестов это будет очень легко реализуемо, но, последствия таких манипуляций по отношению к данным не предсказуемы и в целом могут нанести больше вреда, чем пользы, поэтому мы продолжили искать дальше.

5. Официальное и правильное решение бэкап объектов бакета и его снапшота конфигурации

Оказалось, что поговорка «Хочешь что-то спрятать – положи на самое видное место» действительно работает.
Обрати внимание на шапку)

Кто бы мог подумать, что ответ на вопрос «Можно ли вообще целиком бэкапить бакет (полная конфигурация + объекты и их состояние, кроме версий) в MinIO» будет найден.

Описание решения бэкапа конфигурации бакета и его содержимого скромно находилось на официальном сайте во второй главе «Manage Existing MinIO Deployments» (Управление существующими развернутыми серверами MinIO) в 4 подглаве «Migrate from Gateway or Filesystem Mode»  (Миграция из режима Gateway или Filesystem). Причем создание бэкапа бакета имеет понятное и последовательное описание за что стоит сказать отдельное спасибо разработчикам документации MinIO.

Решение для бэкапа и последующего восстановления бакета (не только объектов, но и конфига) без различных развертываний дополнительных MinIO серверов, переброски только объектов и ручного воссоздания бакета со всеми его настройками на сервере состоит только из 4 команд CLI интерфейса MinIO - mc.

Описание команд на момент написания статьи для бэкапа конфигураций кластера указано здесь.
Описание последовательности действий на момент написания статьи бэкапа бакета указано на странице про миграцию из режима Gateway или Filesystem (здесь) в разделе Procedure на 4 шаге при выборе типа развертывания Filesystem Mode.

5.1 Сохранение метаданных бакета и его восстановление на сервере развертывания

Итак, чтобы сохранить метаданные бакета нам предоставляется команда CLI клиента mc

$mc admin cluster bucket export <server-alias>/<bucket>

Она позволяет получить снапшот метаданных бакета в формате ZIP файла, где содержаться все наши настройки бакета:

  • bucket targets

  • lifecycle rules

  • notifications

  • quotas

  • locks

  • versioning

Например, у cs-bucket снапшот будет именоваться cs-bucket-cs-bucket-metadata.zip 

Аналогично для восстановления бакета имеется схожая команда:

$mc admin cluster bucket import <server-alias>/ <path/to/METADATA.zip>

Как можно видеть все довольно просто - выгрузил архив с метаданными бакета и загрузил на сервер, где хочешь восстановить бакет. Причем, он будет создан, если его не было до этого на целевом сервере.

Остается только получить содержимое бакета с помощью команды синхронизации:

$mc mirror –preserve <server-alias>/<bucket> <path/to/sync/objects>

То есть мы синхронизируем содержимое локальной папки с содержимым бакета в одну сторону.

Для восстановления содержимого мы можем сделать обратное действие:

$mc mirror –preserve <path/to/saved/objects> <server-alias>/<bucket>

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

bucket_backup.sh (резервная копия бакета)
#!/bin/bash

## Описание
# Создает полные и инкрементальные бэкапы бакета

# Текущий путь от куда запускается скрипт
ABSPATH=$(pwd)
# Та директория в которой лежит скрипт
BASEDIR=$(dirname $(realpath "$0"))

# Разделитель окончания строки по умолчанию
IFS_DEF="$IFS"

# Изменить псевдоним вызываемого клиента MinIO S3
# Примечание: Если вы имеете конфликт с Midnight Commander (mc) 
# mv usr/local/bin/mc usr/local/bin/mcli
MC_ALIAS="mc"

# Изменить псевдоним сервера для клиента MinIO S3
SERVER_ALIAS_MC="test/"
# Изменить псевдоним сервера для rclone
SERVER_ALIAS_RC="minio-test:"
# Имя бакета для бэкапа
SOURCE="s31cv8"
# Наименование архива
ARCHIVE_NAME="archive"
# Наименование директории с бэкапами
BACKUPS_DIR="backups"
# Полный путь к директории с полными бэкапами
FULL_BACKUPS_DIR=$ABSPATH/$BACKUPS_DIR/$SERVER_ALIAS_MC$SOURCE/full
# Полный путь к директории с инкрементальными бэкапами
INC_BACKUPS_DIR=$ABSPATH/$BACKUPS_DIR/$SERVER_ALIAS_MC$SOURCE/inc

# Режим создания бэкапа ('full' - полный, 'inc' - икрементальный)
# Примечание: Без полного бэкапа инкрементальный создать нельзя
MODE=$1


# Получить ИД архива (от 0 до N)
function get_archive_id {
    INCS=($(ls $INC_BACKUPS_DIR))
    if [ ${#INCS[*]} -le 1 ] ; then
        return ${#INCS[*]}        
    else
        IND_LAST=$((${#INCS[*]} - 2))
        NUM_ARCHIVE=$((${INCS[$IND_LAST]:7:1} + 1))
        return $NUM_ARCHIVE
    fi
}

# Скачать актуальное содержимое и конфигурацию бакета
# в папки <bucket>/ и <bucket>_conf/
function load_actual_includes_and_config {
    # Получили изменения содержимого бакета
    rclone sync $SERVER_ALIAS_RC$SOURCE $SOURCE \
    --no-update-dir-modtime \
    --no-update-modtime \
    --metadata
    # Получили изменения конфигурации бакета
    mkdir -p $ABSPATH/$SOURCE'_conf/'
    cd $ABSPATH/$SOURCE'_conf/'; \
    $MC_ALIAS admin cluster bucket export $SERVER_ALIAS_MC$SOURCE; \
    mv $SERVER_ALIAS_MC* ./; \
    rm -rf $SERVER_ALIAS_MC; \
    cd ..
}

# Создать полный бэкап бакета
# Примечание: С инкрементальными будет использоваться 0 архив
function full_backup {
    # Загружаем актуальное содержимое и конфигурацию
    # в ту директорию, где запустили скрипт
    load_actual_includes_and_config
    
    # Получаем номер архива
    get_archive_id
    
    # Создание полного бэкапа
    tar --create \
    --gzip \
    --file "$FULL_BACKUPS_DIR/archive$?.tar" \
    --listed-incremental="$INC_BACKUPS_DIR/inc.snar" \
    $SOURCE \
    $SOURCE"_conf/"
}

# Создать инкрементальный бэкап бакета
# Примечание: Зависят от полного бэкапа с именем $ARCHIVE_NAME'0'
function inc_backup {
    # Загружаем актуальное содержимое и конфигурацию
    # в ту директорию, где запустили скрипт
    load_actual_includes_and_config

    # Получаем номер архива
    get_archive_id

    # Создание полного бэкапа
    tar --create \
    --gzip \
    --file "$INC_BACKUPS_DIR/archive$?.tar" \
    --listed-incremental="$INC_BACKUPS_DIR/inc.snar" \
    $SOURCE \
    $SOURCE"_conf/"
}



####################################################
#              НАЧАЛО РАБОТЫ СКРИПТА               #
####################################################

case "$MODE" in
    "full")
        mkdir -p "$FULL_BACKUPS_DIR"
        mkdir -p "$INC_BACKUPS_DIR"
        full_backup
        ;;
    "inc")
        mkdir -p "$FULL_BACKUPS_DIR"
        mkdir -p "$INC_BACKUPS_DIR"
        inc_backup
        ;;
    *)
        echo "Некорректный режим бэкапирования."
        echo "Допустимые варианты: full | inc."
        exit 1
        ;;
esac
recovery_bucket.sh (восстановить бакет)
#!/bin/bash

## Описание
# Восстанавливает версию бакета на указанном сервере
# из полных и инкрементальных бэкапов


# Текущий путь от куда запускается скрипт
ABSPATH=$(pwd)
# Та директория в которой лежит скрипт
BASEDIR=$(dirname $(realpath "$0"))

# Разделитель окончания строки по умолчанию
IFS_DEF="$IFS"

# Изменить псевдоним вызываемого клиента MinIO S3
# Примечание: Если вы имеете конфликт с Midnight Commander (mc)
# mv usr/local/bin/mc usr/local/bin/mcli
MC_ALIAS="mc"

# Изменить псевдоним сервера для клиента MinIO S3
SERVER_ALIAS_MC="test/"
# Изменить псевдоним сервера для rclone
SERVER_ALIAS_RC="minio-test:"
# Имя бакета для бэкапа
SOURCE="s31cv8"
# Наименование архива
ARCHIVE_NAME="archive"
# Наименование директории с бэкапами
BACKUPS_DIR="backups"
# Наименование директории содержащей восстановленную версию бэкапа
RESTORE_DIR="restoration"
# Полный путь к директории с полными бэкапами
FULL_BACKUPS_DIR=$ABSPATH/$BACKUPS_DIR/$SERVER_ALIAS_MC$SOURCE/full
# Полный путь к директории с инкрементальными бэкапами
INC_BACKUPS_DIR=$ABSPATH/$BACKUPS_DIR/$SERVER_ALIAS_MC$SOURCE/inc

# Версия бэкапа для восстановления (от 1 до N)
VERSION="$1"


## Извлечение указанной версии с учетом инкрементальных бэкапов
function extract_version {
    # Очистка папки восстановления
    rm -rf $ABSPATH/$RESTORE_DIR/*
    mkdir -p $ABSPATH/$RESTORE_DIR/$SERVER_ALIAS_MC
    # Задаем какую версию хотим извлечь
    ARCHIVES_COUNT="$VERSION"
    # Извлекаем с 0 по ARCHIVES_COUNT
    BACKUP_NAME=$FULL_BACKUPS_DIR
    for ((i = 0; i < $ARCHIVES_COUNT; i++)) {
        # Если это 1 уровень, то ставим имя бэкапа inc
        if [ $i -eq 1 ] ; then
            BACKUP_NAME=$INC_BACKUPS_DIR
        fi
        #--atime-preserve \
        tar --extract \
        --directory="$ABSPATH/$RESTORE_DIR/$SERVER_ALIAS_MC" \
        --listed-incremental="$INC_BACKUPS_DIR/inc.snar" \
        --file="$BACKUP_NAME/archive$i.tar"
    }
}

## Восстановление версии бакета
function recover_bucket {
    # Извлекаем версию бакета в Файловую Систему
    extract_version
    # Восстановление настроект бакета на указанном сервере
    # Создаем и/или устанавливаем конфигурацию бакета на сервере
    $MC_ALIAS admin cluster bucket import \
    $SERVER_ALIAS_MC$SOURCE \
    $ABSPATH/$RESTORE_DIR/$SERVER_ALIAS_MC$SOURCE'_conf/'SOURCE'-'$SOURCE'-metadata.zip'
    
    # Передаем содержимое бакета указанной версии
    rclone sync $ABSPATH/$RESTORE_DIR/$SERVER_ALIAS_MC$SOURCE $SERVER_ALIAS_RC$SOURCE \
    --no-update-dir-modtime \
    --no-update-modtime \
    --metadata
}

####################################################
#              НАЧАЛО РАБОТЫ СКРИПТА               #
####################################################

case "$VERSION" in
    *[!0-9]*)  # Если версия содержит нецифровые символы
        echo "Ошибка: версия должна быть числом (начинаться с 1)."
        ;;
    "")  # Если версия не указана
        echo "Укажите версию архива, которую хотите восстановить на сервере."
        echo "Версия указывается с 1."
        ;;
    *)  # Если версия указана корректно
        recover_bucket
        ;;
esac

Описание проекта

Нами был создан проект 1c_backup_and_recovery_buckets_MinIO_S3

Он состоит из 2 основных скриптов:

1) bucket_backup.sh - создание полного или инкрементального бэкапа

2) recovery_bucket.sh - восстановление бакета на сервере

Запуск скрипта для создания полного бэкапа

bash bucket_backup.sh full

Запуск скрипта для создания инкрементального бэкапа на основе созданного ранее полного

bash bucket_backup.sh inc

Запуска скрипта для установки n версии бакета на сервер MinIO

bash recover_bucket.sh <n>

Для реализации создания полного и инкрементного бэкапа была использована утилита tar.

Алгоритм создания инкрементального бэкапа:

  1. Смотрим какая версия была до этого

  2. Если это самый первый бэкап, то имеем в виду, что tar должен сделать 0 уровень (полный), иначе 1 .. N уровень (инкрементальный бэкап)

  3. Экспортируем метаданные бакета в созданную папку

  4. Синхронизируем содержимое бакета с локальной папкой для содержимого

  5. Создаем бэкап из этих папок

Пример получаемой структуры инкрементальных бэкапов:

Алгоритм восстановления инкрементального бэкапа:

  1. Получаем номер версии для восстановления

  2. На основе полученного номера версии устанавливаем как бэкап требуется восстановить с помощью tar (полный или инкрементальный)

  3. Восстанавливаем архив с версией конфига и содержимого в папку restoration

  4. Производим импорт конфига бакета на указанный сервер (создание включено, если нет)

  5. Производим синхронизацию файлов локальной папки с бакетом в одну сторону

Пример получаемого локального бэкапа:

Методы резервного копирования

Очередной филиал словарика, который можно спокойно пропустить, если в теме инкрементальных и дифференциальных бэкапов:

Бэкап – это резервная копия множества файлов и папок. Основной задачей решаемой бэкапированием является создание копии файлов и папок и помещение их в общий контейнер.

Основных методов резервного копирования существует 3 - создание полного бэкапа, создание дифференциального бэкапа и создание инкрементального бэкапа.

Полный бэкап - все содержимое помещенное в один архив.

Дифференциальный бэкап - только измененные, новые, удаленные файлы и папки с момента создания полного бэкапа.

Инкрементальный бэкап - только измененные, новые, удаленные файлы и папки с момента создания полного или инкрементального бэкапа.

У каждого из методов имеются преимущества и недостатки

  • Полный бэкап быстрее восстанавливается, но занимает много места

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

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

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

В tar  при создании инкрементального бэкапа 0 уровня мы сохраняем всю информацию о начальном содержимом полного бэкапа, так как по факту 0 уровень - это полный бэкап, но с сохранением истории изменений в отдельный снапшот файл *.snar

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

По поводу эффективной стратегии

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

tar при восстановлении содержимого может производить манипуляции по замене файлов и папок, а также по их удалению в папке, которая хранит не архивированное содержимое бакета, в соответствии с информацией указанной в снапшот файле *.snar 

Если мы имеем на сервере бакет, где присутствуют все объекты со времени последнего бэкапа (могут присутствовать и лишние файлы, но они будут удалены), то восстановление будет происходить быстрее в несколько раз.

Как выглядят сохраненные бэкапы бакета с взятого нами сервера:

Как выглядит структура восстановленной версии (содержимое бакета и снапшот метаданных):

Восстановленный бакет на сервере test из бакета сервера local
Восстановленный бакет на сервере test из бакета сервера local

Заключение

Для задачи бэкапа бакетов MinIO без строгого ограничения по месту на жестком диске достаточно использовать подготовленные команды клиента mc.
Это не сложно и легко автоматизируется с помощью обертки в скрипт на любом удобном для вас языке (BASH, Powershell, Python) и обычного планировщика задач (CRON).

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

В плане автоматизации мы также оборачиваем всю логику в удобный для вашего коллектива язык (BASH, Python) и запускаем его в CRON.

Если у вас имеется тестовый сервер с локальным кластером MinIO и одним диском и вам необходимо не заморачиваться с бэкапом бакета, то можно сохранить все данные MinIO в архив. При необходимости он восстанавливается с помощью обычной распаковки содержимого. Такое решение не является BEST PRACTICES, конечно, но имеет место быть.

В случае, если у вас имеется достаточно места на дисках, предназначенных для хранения бакетов, то вы можете смело включать версионирование на своем сервере. Правда, ни о каком восстановлении бакета на другом сервере речи не будет, зато можно будет восстановить состояние содержимого бакета на указанный период времени через репликацию бакета со стороны клиента - mc mirror.

Для тех, кто дошел аж досюда -- подготовил чек-лист:

Чек-лист

Версионирование бакета
Результат: Решает только проблему удаления объектов с учетом удалений.
Недостатки:

  • Не позволяет сохранять состояние бакета целиком.

  • Восстановление версий объектов трудоемкая операция.

  • Каждая версия объекта, кроме маркеров удаления, храниться целиком без инкрементальной или дифференциальной стратегии.

Синхронизация содержимого
Результат: Решает только проблему удаления объектов.
Недостатки:

  • Не позволяет сохранять состояние бакета целиком.

  • Удаления могут учитываться, но требуется создавать отдельные папки или префиксы в бакете.

  • Появляется зависимость от использования планировщика задач.

Репликация бакета
Результат: Сохраняет идентичное текущее состояние бакета целиком.
Недостатки:

  • Требует обязательного развертывания нового сервера MinIO.

  • Не хранит все версии состояния бакета.

  • Неэффективно расходуется дисковое пространство.

Сохранение данных MinIO
Результат: Сохраняет состояние бакета частично - имя бакета и его содержимое.
Официальное решение - бэкап объектов бакета и его снапшота конфигурации
Результат: Решает проблему сохранения состояния бакета не целиком (объекты и малая часть конфигурации).

Недостатки:

  • Неофициальное и опасное решение.

  • Неэффективная стратегия хранения резервных копий бакетов.

Официальное решение - бэкап объектов бакета и его снапшота конфигурации
Результат: Решает проблему сохранения состояния бакета целиком (объекты и конфигурация).
Недостатки:

  • Привязка к определенной платформе, если храним в виде инкрементальных бэкапов через tar - Linux.

Теги:
Хабы:
Всего голосов 10: ↑10 и ↓0+10
Комментарии0

Публикации

Информация

Сайт
magnit.tech
Дата регистрации
Дата основания
Численность
1 001–5 000 человек
Местоположение
Россия
Представитель
Амиран Карацев