VK Cloud

Версионирование бакетов S3: разбор от команды VK Object Storage

15 июня 2026 г.
_blog_head_121.png

В S3 без версионирования нет кнопки «отменить»: PUT молча перезаписывает объект, DELETE удаляет его навсегда. Версионирование решает это на уровне самого бакета, ведь хранилище ведёт полную историю изменений каждого объекта и восстанавливает данные после ошибочной перезаписи или удаления. Разберём, как устроены версии объектов, что такое delete-marker и как версионирование работает в связке с Object Lock — на примере VK Object Storage.

Елизавета Белоконова2.png

Статья подготовлена вместе с экспертом

Елизавета Белоконова, менеджер продукта

Что такое версионирование и зачем оно нужно

Версия объекта — это состояние файла в конкретный момент, его «снимок». У каждой версии есть versionId — строковый идентификатор, безопасный для URL. Включённое версионирование заставляет хранилище сохранять цепочку таких снимков вместо того, чтобы заменять предыдущее содержимое. На практике это позволяет откатиться после ошибочной перезаписи или удаления: операции перестают быть разрушительными, а удаление обычно превращается в создание служебного delete‑marker.

S3-совместимые хранилища дают инженерам набор инструментов для работы с данными: масштабируемость до петабайтов без сложной настройки, надёжность за счёт автоматического резервирования, гибкое управление доступом. И версионирование бакетов — одна из ключевых функций. Но чтобы встроить её в рабочие процессы, нужно понимать её механику.

Три режима бакета

У версионирования бакетов S3 три состояния. Переключение между ними меняет поведение операций PUT и DELETE.

Режим Особенности PUT DELETE История
Выключено  Состояние по умолчанию для нового бакета перезаписывает объект удаляет навсегда не ведётся
Включено (Enabled) Требуется включать специально создаёт новую версию с уникальным versionId добавляет delete-marker хранится
Приостановлено (Suspended) Включается только после того, как версионирование уже работало. Новая загрузка file.txt перезапишет существующую null-версию (если она есть) без сохранения истории. грузит объект с null-версией добавляет null-delete-marker старые версии сохранены

При этом вернуться из «включено» в «выключено» нельзя — можно только приостановить. Это ограничение влияет на работу с Object Lock, к которому мы вернёмся ниже.

Операции с объектами: что меняется внутри

API для пользователя остаётся прежним — те же PUT, GET, DELETE. Меняется внутренняя механика.

PUT — запись объекта

Если бакет не версионирован или приостановлен, объект получает null-версию, а PUT перезаписывает предыдущее содержимое. При включённом версионировании каждый PUT создаёт новую версию с уникальным versionId, старая версия становится неактуальной, а в ответе появляется заголовок x-amz-version-id с идентификатором новой версии.

Новая версия — всегда независимая запись. Она не наследует ACL, теги и метаданные автоматически.

GET и HEAD — чтение объекта

Для текущего объекта хранилище само выбирает версию с самым поздним временем создания. Чтобы получить конкретный снимок, нужно явно указать versionId. Объекты с null-версией доступны по тому же пути, что и обычно.

DELETE — удаление объекта

Поведение DELETE зависит от режима бакета:

  • Версионирование выключено — объект удаляется физически и навсегда.
  • Включено — обычное удаление не стирает данные. Хранилище создаёт delete-marker, и он становится актуальной версией. Запрос без versionId вернёт ошибку 404 Not Found, но старые версии остаются на месте и восстанавливаются. Удаление с указанием versionId стирает именно ту версию — даже сам delete-marker.
  • Приостановлено — удаление создаёт null-delete-marker.

При обращении к актуальному маркеру удаления хранилище вернёт 404 Not Found, а при запросе неактуального маркера из истории по versionId — 405 Method Not Allowed.

Правила жизненного цикла: контроль объёма

При включённом версионировании данные не исчезают — каждая перезапись и удаление добавляют версию. Объём бакета растёт, поэтому нужна автоочистка. За неё отвечают правила жизненного цикла (lifecycle):

  • NoncurrentVersionExpiration — автоудаление неактуальных версий по истечении N дней. Это основной инструмент контроля объёма.
  • NewerNoncurrentVersions — ограничивает число хранимых неактуальных версий. Например, оставлять только 5 последних.
  • ExpiredObjectDeleteMarker — удаляет сам delete-marker, если у объекта не осталось реальных версий. Логика правил работает от актуальной версии к старым.

Листинг и аудит

Для просмотра содержимого бакета есть две операции с разным охватом:

  • ListObjects — стандартный листинг. Возвращает только актуальные версии, маркеры удаления не показывает. Подходит, когда нужна текущая картина бакета.
  • ListObjectVersions — показывает всё: массив всех версий плюс массив всех delete-markers. Это инструмент для аудита, бэкапа и восстановления.

Object Lock: защита от преднамеренного удаления

Версионирование защищает от случайных изменений, но не от преднамеренного удаления злоумышленником или администратором с доступом. Object Lock закрывает этот пробел: он реализует модель WORM (Write Once, Read Many), при которой объект после сохранения нельзя изменить или удалить в течение заданного срока.

Object Lock критичен там, где данные нельзя терять или подменять: финансовые отчёты, юридические и медицинские документы, бэкапы, соответствие требованиям регуляторов. Атаки Ransomware всё чаще нацелены на облачные бэкапы — атакующие шифруют или удаляют объекты в S3, чтобы лишить жертву возможности восстановиться. Связка Object Lock и версионирования снимает этот риск.

Object Lock не работает без версионирования: блокировка применяется к конкретной версии объекта, а не к файлу в целом. То есть:

  • Текущую версию можно заблокировать — её нельзя удалить или изменить.
  • Новую версию можно загрузить — она не заблокирована, пока блокировка не настроена.
  • Старая заблокированная версия остаётся нетронутой.

У Object Lock есть ограничения:

  • требуется включённое версионирование;
  • параметр --object-lock-enabled-for-bucket задаётся только при создании бакета;
  • после включения Object Lock нельзя отключить версионирование или перевести бакет в Suspended — попытка вернёт ошибку InvalidBucketState;
  • бакет навсегда остаётся в состоянии Enabled.

Так сделано специально, чтобы retention-политику нельзя было бы обойти, отключив версионирование.

Применение на практике версионирование в VK Object Storage

Подробнее остановимся на том, как все описанное выше работает на практике. В рамках примера будем использовать S3-совместимое хранилище VK Object Storage в VK Cloud, которое в рамках недавних обновлений получило поддержку версионирования.

Важно знать

VK Object Storage — S3-совместимое объектное хранилище собственной разработки VK Tech, без open-source движков вроде Ceph или MinIO. По данным VK Cloud (март 2026), VK Object Storage — одна из крупнейших инсталляций S3 в России: свыше 400 ПБ данных, надёжность хранения 99,9999999% (9 девяток), топ-1 в рейтинге CNews.

Подготовка AWS CLI

Настройку начинаем с команды:

aws configure

CLI запросит четыре параметра: Access Key ID, Secret Key (соответствует ключу в консоли), регион по умолчанию (ru-msk — Москва, kz-ast — Казахстан) и формат вывода (json, yaml, yaml-stream, текст, таблица).

Сценарий 1: только версионирование

Создаём бакет:

aws s3api create-bucket --bucket versioning-only-bucket --region ru-msk --endpoint-url https://hb.ru-msk.vkcloud-storage.ru

Включаем версионирование:

aws s3api put-bucket-versioning --bucket versioning-only-bucket --versioning-configuration Status=Enabled --endpoint-url https://hb.ru-msk.vkcloud-storage.ru

Проверяем состояние:

aws s3api get-bucket-versioning --bucket versioning-only-bucket --endpoint-url https://hb.ru-msk.vkcloud-storage.ru

Ожидаемый результат:

{ "Status": "Enabled" }

После этого все новые объекты получают уникальный versionId. PUT создаёт новую версию, а не перезаписывает предыдущую. DELETE создаёт delete-marker. Старые объекты, загруженные до включения версионирования, остаются с versionId = null.

Выключить версионирование уже нельзя — можно только приостановить:

aws s3api put-bucket-versioning --bucket versioning-only-bucket --versioning-configuration Status=Suspended --endpoint-url https://hb.ru-msk.vkcloud-storage.ru

Сценарий 2: версионирование плюс Object Lock

Object Lock работает только при включённом версионировании, и после его активации состояние версионирования становится неизменяемым. Создаём бакет сразу с Object Lock:

aws s3api create-bucket --bucket versioning-lock-bucket --object-lock-enabled-for-bucket --region ru-msk --endpoint-url https://hb.ru-msk.vkcloud-storage.ru

Включаем версионирование:

aws s3api put-bucket-versioning --bucket versioning-lock-bucket --versioning-configuration Status=Enabled --endpoint-url https://hb.ru-msk.vkcloud-storage.ru

Проверяем:

aws s3api get-bucket-versioning --bucket versioning-lock-bucket --endpoint-url https://hb.ru-msk.vkcloud-storage.ru

Ожидаемый результат:

{ "Status": "Enabled" }

Каждая версия может быть заблокирована по модели WORM. Заблокированную версию нельзя удалить или перезаписать, новые версии создавать можно, а перевести бакет в Status=Suspended нельзя — попытка вернёт ошибку InvalidBucketState.

Загрузка объекта

Без Object Lock. Создаём файл:

echo "v1" > file.txt

Загружаем объект:

aws s3api put-object --bucket versioning-lock-bucket --key file.txt --body file.txt --endpoint-url https://hb.ru-msk.vkcloud-storage.ru

В ответе приходит идентификатор версии:

{ "VersionId": "..." }

Смотрим список версий:

aws s3api list-object-versions --bucket versioning-lock-bucket --endpoint-url https://hb.ru-msk.vkcloud-storage.ru

В ответе — массив Versions, где у загруженной версии стоит IsLatest=true и свой VersionId.

Загрузка с Object Lock. Теперь грузим объект с блокировкой в режиме GOVERNANCE и сроком retention до 2026-12-31:

aws s3api put-object --bucket versioning-lock-bucket --key locked.txt --body file.txt --object-lock-mode GOVERNANCE --object-lock-retain-until-date 2026-12-31T00:00:00 --endpoint-url https://hb.ru-msk.vkcloud-storage.ru

Дата блокировки должна быть позже момента загрузки, иначе API вернёт ошибку. Хранилище создаёт новую версию с retention policy.

Проверяем retention:

aws s3api get-object-retention --bucket versioning-lock-bucket --key locked.txt --endpoint-url https://hb.ru-msk.vkcloud-storage.ru

Ожидаемый ответ:

{ "Retention": { "Mode": "GOVERNANCE", "RetainUntilDate": "..." } }

Пробуем удалить объект:

aws s3api delete-object --bucket versioning-lock-bucket --key locked.txt --endpoint-url https://hb.ru-msk.vkcloud-storage.ru

Хранилище ставит delete-marker, и объект пропадает из листинга. Но все версии остаются на месте и восстанавливаются — заблокированная версия физически никуда не делась.

Ещё больше деталей вы можете найти в документации.

Когда это пригодится

Версионирование превращает разрушительные операции в безопасные: хранилище ведёт историю каждого объекта и даёт откатиться после ошибки. В связке с Object Lock версии объектов становятся основой для систем под строгие требования безопасности — финансы, юридические и медицинские данные, защита бэкапов от ransomware. В VK Object Storage работа сводится к стандартным операциям загрузки и удаления — историю и delete-marker хранилище ведёт само.

Оставьте заявку, чтобы получить консультацию

Наши специалисты свяжутся с вами в ближайшее время и ответят на все вопросы.

section-subscribe_2x.png

            Узнавайте о выходе новых статей в блоге первыми!

            Будем держать в курсе новостей и облачных трендов

            section-subscribe_2x.png
              section-subscribe_2x.png
              Теги: S3, VK Object Storage
              Ссылка скопирована
              Поделиться

              Почитать по теме

              _blog_head_32.png
              25 июня

              Хранение и раздача видео и медиаконтента через S3 и CDN: архитектура

              _blog_head_172.png
              2 июня

              Облачная безопасность: как защитить данные в S3-хранилище

              40+ готовых сервисов