Контейнер без состояния потерять не страшно: удалил, развернул заново из описания, и всё на месте. А вот база данных, очередь сообщений или файловое хранилище держат в постоянных томах данные, которые из манифеста не воссоздать. Именно постоянные данные оказываются самым уязвимым местом восстановления Kubernetes после катастрофы. Снести случайно целое пространство имён или потерять кластер целиком означает потерять и эти данные, если о них заранее не позаботиться. Инструмент резервного копирования кластера решает эту задачу, но восстановление приложений с состоянием и их томов устроено тоньше, чем кажется. Разберём, как оно работает, какими способами снимаются тома и почему резервная копия без проверки восстановлением почти бесполезна.

Что именно нужно спасать и почему манифестов мало

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

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

Как устроен сам инструмент

По устройству это набор контроллеров, работающих внутри кластера и следящих за специальными ресурсами копирования и восстановления. Создаёшь ресурс копирования, и контроллер делает две вещи. Он выгружает все описания ресурсов Kubernetes и складывает их в хранилище. И он снимает снимки постоянных томов через подходящий механизм. На восстановлении другой контроллер проделывает обратный путь: воссоздаёт объекты и восстанавливает данные томов.

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

Какими двумя способами снимаются тома

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

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

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

Как именно восстанавливается приложение с состоянием

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

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

Порядок восстановления набора реплик с состоянием:
1. восстанавливаются заявки на тома, драйвер создаёт тома из снимков
2. тома привязываются к заявкам по имени
3. восстанавливается набор реплик, подхватывая тома по именам
4. поды стартуют с примонтированными томами и данными

Есть тонкость с тем, как тома создаются при разных способах копирования. При восстановлении из снимка интерфейса хранилища тома воссоздаёт драйвер хранилища из снимка. При восстановлении файловым способом тома создаются обычным динамическим выделением после создания заявки, и данные заливаются в них агентом. Это разные пути под капотом, хотя для пользователя результат один.

Почему время восстановления непредсказуемо без подготовки

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

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

Чем опасны несогласованные снимки и как это лечить

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

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

Почему частичное восстановление и чужое пространство имён это норма

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

Очень полезен приём восстановления в другое пространство имён. Это нужно и для миграций, и для тестирования, и для клонирования окружений. Можно поднять копию боевого набора реплик в тестовом пространстве и проверить, что данные на месте, не трогая продакшен. То же гибкое восстановление закрывает сразу несколько задач: аварийное восстановление, миграцию между кластерами и клонирование среды для разработки.

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

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

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

Какой стратегии придерживаться

Защита приложений с состоянием в Kubernetes решает то, что не под силу простому пересозданию из манифестов: возврат незаменимых данных вместе с описаниями. Разумная схема складывается из нескольких решений. Захватывать оба слоя сразу, и описания ресурсов, и данные томов. Предпочитать снимки через интерфейс хранилища ради скорости, а файловое копирование брать там, где снимки не поддерживаются. Для баз обязательно использовать перехватчики перед копированием, чтобы получить согласованное на уровне приложения состояние, а не просто согласованное на уровне сбоя. Шифровать хранилище копий, ведь там лежат все секреты. Задавать разумные сроки хранения, держа свежие копии дольше частыми, а старые реже. И, что важнее всего, регулярно репетировать восстановление в отдельном пространстве имён, замеряя его время.

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