[Перевод] Аварийное восстановление в Kubernetes: три воспроизводимых сценария сбоя


Команда VK Cloud перевела статью, описывающую три сценария сбоя, которые отличают наличие резервных копий от возможности восстановления, а также рекомендации, следующие из каждого сценария. Каждый сценарий воспроизводим на ноутбуке из указанного выше репозитория стенда, и каждый показанный вывод терминала является реальным выводом терминала, полученный в стенде
Документ посвящён восстановлению stateful-приложений, работающих в Kubernetes: проверке наличия данных в резервных копиях, разделению между декларативным и хранимым состоянием, а также обеспечению согласованности в приложениях с несколькими томами. В нём не рассматриваются требования комплаенса, сравнение продуктов и восстановление базовой облачной инфраструктуры или инфраструктуры дата-центра, однако указано, где начинается ответственность за эти задачи.
Конкретные инструменты упоминаются там, где они нужны для описания сценария: Velero и CSI snapshot APIs. Они приведены как эталонные реализации, чтобы сделать сценарии более предметными. Описанные отказы и рекомендации применимы к любому инструменту, который выполняет ту же роль.
Определения

Четыре уровня восстановления
Чтобы восстановление можно было считать успешным, нужно вернуть четыре уровня:

Для каждого уровня есть зрелые инструменты, и по отдельности они обычно восстанавливаются без проблем. Сбои возникают на стыках между уровнями: кластер восстановлен, но данных нет; данные восстановлены, но к ним нет нет пути, по которому к приложению поступает трафик; описание приложения создаёт пустой том. В трёх следующих сценариях нарушается один из таких стыков.
Стенд

Два кластера и два сервиса, всё локально:
Production: кластер Kubernetes, в котором каждый узел представляет собой отдельную лёгкую виртуальную машину со своим ядром. Поэтому потеря production-кластера означает фактическое выключение машины.
Recovery: второй кластер, который существует ещё до того, как что-либо пойдёт не так.
Хранилище резервных копий: S3-совместимое объектное хранилище за пределами обоих кластеров. Благодаря этому потеря любого из кластеров не приводит к потере точек восстановления. Инструмент резервного копирования в обоих кластерах настроен на один и тот же бакет.
Git: локальный Git-сервис, где хранятся манифесты приложения. За изменениями в нём следит GitOps-контроллер в recovery-кластере.
В качестве рабочей нагрузки используется приложение с PostgreSQL и заранее известным содержимым базы данных — четырьмя строками. Поэтому каждое восстановление можно проверить по ожидаемому результату, а не по зелёному статусу на дашборде.
Сценарий 1. Проверка, что бэкап содержит данные

Резервное копирование Kubernetes состоит из двух отдельных частей: определений ресурсов в YAML и данных постоянных томов. Инструменты резервного копирования защищают данные томов с помощью снапшотов (снимков) на стороне провайдера или через CSI, резервного копирования файловой системы либо переноса данных снапшотов во внешнее хранилище. В этом стенде используется последний подход — Velero и его механизм переноса данных.
Обычно проверка ограничивается статусом Completed у резервной копии. Но стоит пойти дальше и убедиться, что байты данных тома действительно были перенесены:
$ kubectl -n velero get datauploads -l velero.io/backup-name=$BACKUP \
-o custom-columns='NAME:.metadata.name,PHASE:.status.phase,BYTES:.status.progress.bytesDone'
NAME PHASE BYTES
guestbook-rehearsal-20260727001126-q2j9m Completed 47989888Здесь механизм переноса данных подтверждает, что 47 989 888 байт данных тома покинули кластер и были записаны во внешнее хранилище. Если инструмент резервного копирования не может показать это число для конкретной резервной копии, к нему стоит отнестись внимательно.
После удаления пространства имён вместе с PVC и восстановления из этой резервной копии те же четыре строки вернулись примерно за две минуты. Это позитивный сценарий, но он скрывает три вещи, которые ни один инструмент резервного копирования не сделает автоматически:
Защита данных тома не делает резервную копию базы данных согласованной на уровне приложения. Если приложение этого требует, необходимо настроить хуки для сброса данных на диск или перевода приложения в согласованное состояние.
Восстановление на другой инфраструктуре может потребовать сопоставления классов хранения и других преобразований. Инструменты предоставляют необходимые механизмы, но проектировать и тестировать их должна каждая команда самостоятельно.
Статус резервной копии
Completedозначает лишь, что операция резервного копирования завершилась. Он не доказывает, что приложение запустится, будет содержать ожидаемые данные или сможет обслуживать трафик. Такие доказательства даёт только сквозной тест восстановления.
Граница ответственности. Инструменты резервного копирования восстанавливают ресурсы в уже существующий кластер. Они не создают сам кластер, его узлы, сеть, балансировщики нагрузки или DNS. Восстановлением Kubernetes как платформы должен заниматься другой механизм: например, инфраструктура как код или Cluster API.
Поэтому в DR-плане, который начинается со слов «восстановить резервную копию», нужно указать, во что именно будет восстанавливаться эта копия.
Сценарий 2. Объявленное состояние не является сохранённым состоянием

Production-кластер выключен. Recovery-кластер, существовавший ещё до аварии, содержит GitOps-контроллер, настроенный на Git, и инструмент резервного копирования, настроенный на общее хранилище. До этого момента приложение в нём ни разу не запускалось.
Синхронизация приложения из Git завершается успешно: статус синхронизации — Synced, StatefulSet разворачивается, под базы данных переходит в состояния Running и Ready, все дашборды показывают зелёный статус. Однако запрос к базе данных возвращает:
ERROR: relation "attendees" does not existБаза данных работает, но она пуста. Ничего не сломалось. В Git хранились только декларации, поэтому Kubernetes в точности выполнил то, что описано в YAML: создал StatefulSet, Service и выделил для PVC новый пустой том. GitOps безупречно восстановил объявленное состояние, но не восстановил сохранённое состояние.
Оба инструмента необходимы, потому что восстанавливать нужно две разные сущности, и каждый из них отвечает ровно за одну из них: Git хранит желаемое состояние, а резервные копии — состояние. В стенде восстановление, которое вернуло проверенные данные, состояло из следующих шагов:
Удалить пустое приложение, созданное синхронизацией.
Восстановить приложение из хранилища резервных копий вместе с томами.
Проверить данные по ожидаемому содержимому.
Восстановление также происходило между разными инфраструктурными средами: на одном node runtime, а на другом восстановлена. Авария может вынудить восстанавливаться на другой инфраструктуре, поэтому переносимость восстановления нужно проверять на практике, а не считать её гарантированной.
Измерение. В стенде путь от выключения production-кластера до проверки данных в recovery-кластере занял четыре минуты при первом выполнении и чуть меньше двух минут при повторном, отрепетированном запуске. Обе цифры отражают только автоматизированную часть сценария. Производственный RTO включает также обнаружение инцидента, принятие решения, переключение трафика и последующий возврат к штатной схеме.
Общий вывод: момент, когда дашборды стали зелёными, ещё не был восстановлением. Восстановлением стал момент, когда данные вернулись и были проверены.

Разворачивайте кластеры Kubernetes с Managed Containers
Автоматизируйте деплой
и снижайте затраты на инфраструктуру
до 60%
Сценарий 3. Согласованность нескольких volume

Реальные stateful-приложения используют несколько томов: данные базы данных и WAL, партиции брокера сообщений, наборы реплик. В примере приложение пять раз в секунду записывает согласованные пары: заказ n в один PVC и платёж n — в другой. При этом соблюдается один инвариант: каждому платежу должен соответствовать его заказ.
Если создавать снимки этих двух томов по отдельности с разницей в пять секунд, получатся два снимка со статусом ReadyToUse, каждый из которых по отдельности безупречен. Однако после восстановления обоих томов и сравнения последних зафиксированных номеров последовательности результат будет таким:
last order committed : 108352
last payment committed : 108377
[FAIL] 25 payments have NO matching order.
[FAIL] Each snapshot succeeded. The restore is still wrong.Двадцать пять платежей ссылаются на заказы, которых не существует. Ни один компонент не отказал, каждая операция завершилась успешно, но итоговая точка восстановления описывает момент времени, которого никогда не было. В production такая пятисекундная разница возникает, когда инструмент резервного копирования последовательно обходит список из сотни PVC.
Ответ на уровне API: VolumeGroupSnapshot достиг статуса GA в Kubernetes 1.36. Один объект выбирает PVC по метке, а CSI-драйвер получает единый запрос на создание согласованной при аварийном завершении точки восстановления сразу для всех томов:
apiVersion: groupsnapshot.storage.k8s.io/v1
kind: VolumeGroupSnapshot
metadata:
name: ledger-group-snap
spec:
volumeGroupSnapshotClassName: csi-hostpath-groupsnapclass
source:
selector:
matchLabels:
group: ledger
При восстановлении снимков, входящих в группу, и запуске той же проверки:
last order committed : 109169
last payment committed : 109169
[OK] Each payment has a matching order. Restore is consistent.Оговорки, которые относятся не только к лабораторному стенду:
Поддержка зависит от драйвера. Поддержка обычных
VolumeSnapshotне означает, что драйвер поддерживает групповые снимки: групповые CSI RPC требуют отдельной реализации. По состоянию на середину 2026 года большинство основных облачных драйверов, проверенных для лабораторного стенда, их не реализуют.Настройку нужно выполнять явно: оператор должен включить CRD и feature gates на стороне snapshot controller и CSI sidecar.
Согласованность при аварийном завершении работы не равна согласованности на уровне приложения. API устраняет рассинхронизацию между томами по времени, но не сбрасывает буферы базы данных и не переводит её в согласованное состояние.
В лабораторном стенде используется тестовый CSI-драйвер hostpath. Он реализует групповые RPC, но архивирует тома группы последовательно, поэтому во время создания группового снимка запись приостанавливается, чтобы результаты демонстрации оставались детерминированными. Гарантия единой точки во времени сама по себе зависит от бэкенда хранения, который использует production-драйвер.
Рекомендации по тестированию восстановления
Тест восстановления — это не удаление пода с последующим ожиданием его перезапуска: такой тест проверяет согласование состояния рабочей нагрузки. Тест восстановления:
Восстанавливает stateful-приложение целиком в чистую целевую среду, где оно раньше не запускалось.
Проверяет данные и пользовательский путь по ожидаемому содержимому, а не по статусам ресурсов.
Измеряет весь процесс по времени.
Принципы, которые можно без изменений перенести из лабораторного стенда в production:

Открытые пробелы в экосистеме
Эти сценарии выявляют пробелы, которые сегодня не может закрыть ни один отдельный инструмент:
Нет общего контракта для межкластерного аварийного переключения. Для данных, рабочих нагрузок, кластеров, трафика и идентификации существуют отдельные инструменты, но в каждой из этих областей не хватает общего контракта со следующей. Продукты решают эту задачу внутри собственных API; в базовом Kubernetes последовательность действий не определена.
Нет стандартной единицы восстановления приложения. В базовом Kubernetes нет поддерживаемого ресурса
Application, который определял бы, какие объекты, операторы, сервисы данных и внешние зависимости должны восстанавливаться вместе. Инструменты резервного копирования используют пространства имён и метки, GitOps-контроллеры — собственные объекты приложений, менеджеры пакетов — релизы, и каждый из них проводит границу по-своему.Успешное резервное копирование считается доказательством возможности восстановления. Метрики успешного завершения резервного копирования широко отслеживаются, а результаты регулярных проверок восстановления — редко.
Как принять участие
Инициатива Cloud Native Business Continuity в рамках CNCF TAG Operational Resilience — открытое предложение, которое ищет участников. Его цели — провести анализ пробелов в экосистеме, обновить рекомендации по резервному копированию и аварийному восстановлению, а также подготовить эталонные архитектуры: https://github.com/cncf/toc/issues/1779
Источники
Воспроизводимый лабораторный стенд: https://github.com/saiyam1814/kubecon-japan-dr-demo
Velero, проект CNCF Sandbox: https://www.cncf.io/projects/velero/
Хуки резервного копирования Velero: https://velero.io/docs/v1.18/backup-hooks/
Объявление о выходе VolumeGroupSnapshot в GA: https://kubernetes.io/blog/2026/05/08/kubernetes-v1-36-volume-group-snapshot-ga/
Версия этого документа в блоге: https://blog.kubesimplify.com/a-backup-is-not-disaster-recovery
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.