Переезд продового кластера с Longhorn на LINSTOR — и ожидание, которое не сбылось
Зачем мы заменили Longhorn на LINSTOR/DRBD на self-managed кластере, как каждая нагрузка переезжала своим способом и что пошло не так по дороге.
Кластер, на котором живут маркетинговые сайты Optimacros, — это self-managed kubeadm на виртуалках, с Longhorn для томов: MySQL InnoDB Cluster, трёхнодовый Vault, Prometheus, Grafana и Alertmanager. В августе я перевёл всё это на LINSTOR (Piraeus) с DRBD под капотом. Вот история о том, зачем, как и в чём я ошибся.
Не ради пропускной способности
Диски простаивали 96% времени. У MySQL — ноль медленных запросов, ноль innodb_log_waits и 99.99% попаданий в buffer pool. Пропускная способность причиной не была.
Причиной была операционная динамика, измеренная до любых изменений:
- создание PVC до
Bound: 21 секунда; - первый attach: 14 секунд;
- переезд тома между нодами: 46 секунд плюс ошибка
Multi-Attach; - задержка записи: 0.16 мс на локальном диске против 12 мс на томе Longhorn.
Меньше движущихся частей в пути данных и задержка локального диска стоили миграции.
Сначала проверить рискованную часть
DRBD — модуль ядра, и это единственный новый класс отказов, который приносит LINSTOR: Longhorn живёт целиком в user-space, DRBD — нет. Поэтому до любого плана я собрал DRBD 9.3.3 под ядро нод ровно тем образом-загрузчиком, который Piraeus будет использовать в проде, загрузил и выгрузил его на одной ноде. Secure Boot оказался неприменим (загрузка через legacy BIOS), а в репозиториях Ubuntu был drbd-utils, но не было drbd-dkms — что неважно: модуль собирает DaemonSet-загрузчик Piraeus, выбирая образ по ОС ноды.
Оставшийся риск записан прямо: каждое обновление ядра пересобирает модуль, и упавшая сборка оставит ноду без хранилища. Смягчение — загрузчик собирает модуль при старте пода, так что отказ проявится сразу после ребута, а не через дни, — а ядра и так патчатся по одной ноде.
Размер с обоснованием
127 ГиБ данных при двух репликах — 254 ГиБ по кластеру. Я попросил 200 ГиБ на воркер — с запасом в 3.2 раза — по трём конкретным причинам: снапшоты Longhorn заставили том Prometheus на 30 ГиБ занимать 68 ГиБ на дисках; во время миграции оба хранилища работают рядом; реплики никогда не ложатся ровно (на одном воркере было свободно 51 ГиБ, на другом — 156). Диски пришли отдельными устройствами; LINSTOR забирает их целиком в LVM thin pool.
От наименее критичного, каждый раз своим способом
Longhorn оставался установленным как точка отката, а тома переезжали по одному, от наименее к наиболее критичному:
- Grafana (Deployment): rsync между двумя томами, затем
existingClaimв values чарта. - Prometheus: rsync ровно один раз во временный том с
Retain, потом отвязать и подключить заново под именем, которого ждёт StatefulSet. - Vault и MySQL: вообще без копирования. Raft и InnoDB clone восстанавливают участника от соседей, так что достаточно было удалять PVC одного участника за раз и давать ему подняться на новом storage class.
Что пошло не так
Поды, пережившие смену DNS накануне, всё ещё держали резолвер компонента, которого больше не было. Raft Vault разваливался на выборах с no such host, а MySQL не мог собрать группу. Лечится это только пересозданием подов, и MySQL пришлось поднимать через rebootClusterFromCompleteOutage, добирая участников клонированием.
И одна ошибка моя: я удалил StatefulSet MySQL с --cascade=orphan, не сохранив манифест. Оператор отказался пересоздавать его вокруг подов без owner reference, и я собрал StatefulSet вручную из спецификации живого пода. База маркетинговых сайтов была недоступна несколько минут, пока пересоздавался primary; сами сайты отвечали всё время.
Честный итог
Всё переехало в тот же день, linstor-r2 (LVM thin, две реплики) стал классом по умолчанию, а после этого Longhorn удалили полностью. Но ожидание, что ошибки Multi-Attach исчезнут, не оправдалось: они воспроизводятся одинаково на обоих хранилищах, потому что так Kubernetes обращается с RWO-томами, а не дефект Longhorn. Переезд тома ускорился лишь умеренно — 14 секунд вместо 19 при перемере. Выигрыш по задержке был настоящим; выигрыш по attach — в основном миф.
Выводы
- Измеряй операции, которые хочешь улучшить, до миграции — и перемеряй после. Только так заметишь, что обещанный выигрыш не был реальным.
- Сначала проверяй новый класс отказов. Для DRBD это модуль ядра, собранный тем же образом, что пойдёт в прод.
- Разным нагрузкам — разные способы переезда; кластерные базы часто восстанавливаются сами, без копирования.
- Перед
--cascade=orphanвсегда сохраняй манифест.