Сценарий, который стоит примерить на свою инфраструктуру. Вы восстанавливаете PostgreSQL из ночного бэкапа. Каталог данных лежит на одном PVC, WAL — на другом (разнесли ради изоляции I/O). Все снапшоты отчитались об успехе, поды поднялись. А Postgres не стартует: WAL ссылается на страницы, которых нет в файлах данных.

Бэкап не побился при передаче. Он был неконсистентным в момент снятия.

По материалам статьи Kubernetes 1.36 restores a lost guarantee for database backups (Shubham Pampattiwar, мейнтейнер Velero, 15 сентября 2026). Разбор и манифесты мои.

Что именно ломается

Инструмент бэкапа перебирает PVC приложения и снимает VolumeSnapshot с каждого — по очереди. Том A, том B, том C.

Каждый снапшот по отдельности crash-consistent: это эквивалент выдёргивания питания у одного конкретного диска. Но между собой они не согласованы. Пока снимается A, приложение продолжает писать. Транзакция успевает попасть в журнал на томе B и сослаться на данные, которых в снимке A уже нет — он был заморожен парой сотен миллисекунд раньше.

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

Проблема коварна тем, что проявляется только при восстановлении. Мониторинг зелёный, VolumeSnapshot в статусе readyToUse: true, отчёты о бэкапах приходят исправно — ровно до ночи, когда восстановление действительно понадобится.

Гарантия, потерянная при переезде в Kubernetes

Дисковые массивы решили это десятилетия назад — механизмом consistency group. Вы говорили массиву, какие LUN принадлежат одному приложению, и при снятии снимка группы массив замораживал их все в один момент. Восстановление было когерентным по построению.

В cloud native эта гарантия не переехала. CSI стандартизировал снапшоты вокруг одного объекта — VolumeSnapshot, привязанного к одному PVC. Один PVC — один снимок. Для stateless-сервиса с единственным томом модель нормальная. Для всего, что размазывает состояние по нескольким томам, она не способна выразить, какие тома принадлежат друг другу.

Обходной путь существовал: заморозить приложение (остановить I/O, сбросить буферы, снять снимки, разморозить). Но замораживать нагруженную базу на время снятия нескольких снапшотов — ровно та деградация, которой бэкапы и должны избегать.

VolumeGroupSnapshot

Недостающий примитив стал GA в Kubernetes 1.36 (май 2026). Группа консистентности вернулась — но уже как вендоронезависимый API, а не как фича конкретного железа.

Три объекта:

1. VolumeGroupSnapshotClass — заводит администратор, описывает, как драйвер CSI снимает групповые снимки:

YAML
apiVersion: groupsnapshot.storage.k8s.io/v1
kind: VolumeGroupSnapshotClass
metadata:
  name: csi-group-snapclass
driver: example.csi.k8s.io
deletionPolicy: Delete
Нажмите, чтобы развернуть и увидеть больше

2. VolumeGroupSnapshot — запрос пользователя. Ключевая часть — селектор по меткам:

YAML
apiVersion: groupsnapshot.storage.k8s.io/v1
kind: VolumeGroupSnapshot
metadata:
  name: pg-cluster-snapshot
  namespace: production
spec:
  volumeGroupSnapshotClassName: csi-group-snapclass
  source:
    selector:
      matchLabels:
        app: postgresql
        instance: prod-db-01
Нажмите, чтобы развернуть и увидеть больше

3. VolumeGroupSnapshotContent — отслеживает созданный результат, как и в случае обычных снапшотов.

Под капотом драйвер CSI делает один атомарный снимок на момент времени по всем выбранным томам. Настоящая группа консистентности, без заморозки приложения — если, конечно, нижележащее хранилище это умеет.

Почему селектор, а не список

Design-решение, которое стоит оценить: вы не перечисляете тома, а описываете их. Селектор app=postgresql захватывает и данные, и журнал; граница группы выражена в терминах Kubernetes и переживает добавление тома, переименование PVC или изменение размеров.

Перечисление пришлось бы поддерживать руками — и оно неминуемо разъехалось бы с реальностью ровно к моменту аварии.

Как выглядит восстановление

Групповой снимок разворачивается обратно в отдельные снапшоты томов — по одному на участника группы. Восстановление по-прежнему наполняет каждый PVC независимо, но теперь все участники разделяют единую точку во времени.

То есть привычный процесс восстановления не меняется; меняется только гарантия, которая за ним стоит.

Когда применять, а когда нет

Это не замена обычным снапшотам, а инструмент под конкретную задачу:

СитуацияЧто использовать
Один томVolumeSnapshot
Несколько независимых томовVolumeSnapshot на каждый
Порядок записи связывает тома (данные + WAL, данные + индексы)VolumeGroupSnapshot
Не уверены, испортит ли приложение частичное восстановлениесчитайте группой

Для по-настоящему независимых томов группировка ничего не даёт, зато добавляет накладные расходы на координацию.

Прямое следствие для CloudNativePG

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

В Рецепте 6 разбирается вынос WAL на отдельный том — с приростом производительности 15–45%. В Рецепте 7 к этому добавляются tablespaces на разных storage-классах: горячие партиции на быстром диске, холодные на дешёвом.

Оба совета правильные. Но каждый из них превращает вашу базу в многотомное приложение — то самое, для которого попучечные снапшоты дают несогласованный набор. Чем аккуратнее вы разнесли I/O, тем больше томов должны быть заморожены в один момент.

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

Что проверить перед тем, как на это положиться

Пять пунктов, каждый из которых способен обесценить всю схему:

  1. Поддержка на стороне драйвера CSI. API стандартный, но реализовать его должен драйвер, и распространение идёт неравномерно. Среди поддерживающих — Ceph CSI. Смотрите release notes именно своего драйвера.
  2. Создайте VolumeGroupSnapshotClass заранее. Выяснять, что класса нет, в момент инцидента — плохой сценарий.
  3. Атомарность не крепче бэкенда. Гарантия упирается в возможности самого хранилища; API лишь передаёт запрос вниз.
  4. Проверяйте восстановлением, а не статусом. readyToUse: true говорит о том, что снимок создан, а не о том, что из него поднимется рабочая база. Единственная настоящая проверка — реальное восстановление (об этом же был разговор в части про бэкапы ClickHouse).
  5. Проведите аудит имеющихся бэкапов. Если многотомные приложения защищены попучечными снапшотами, у вас, скорее всего, уже есть точки восстановления, которые не переживут реальную аварию, — и это никогда не проверялось.

Со стороны инструментов: Velero, де-факто стандарт бэкапа в Kubernetes, реализовал поддержку поверх апстримного API, а не собственной схемы группировки. Это важная деталь — гарантия консистентности держится на общем стандарте, а не на формате, привязанном к одному инструменту.

Итог

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

Если у вас есть база с разнесёнными томами — а следуя разумным советам по производительности, вы почти наверняка к этому пришли, — стоит сделать ровно одну вещь: восстановить прошлый бэкап на тестовом стенде и посмотреть, стартует ли база. Ответ будет информативнее любых зелёных статусов.

Авторские права

Автор: Vasiliy Koshkin

Ссылка: https://notes.melancholic.tech/posts/volume-group-snapshots/

Лицензия: CC BY-NC-SA 4.0

Использование материалов блога разрешается при условии: указания авторства/источника, некоммерческого использования и сохранения лицензии.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
ESC
⌘K Горячая клавиша