← Все статьи

Том Longhorn, который не хотел расти: attachment ticket, прибитый к плохой ноде

PVC бесконечно висел в Resizing, а Longhorn каждые пять секунд повторял расширение без единой ошибки. Устаревший attachment ticket держал том на одной нездоровой ноде.

В Optimacros одному участнику MySQL понадобилось больше места: его PVC был 6 GiB, и я пропатчил его до 20 GiB. StorageClass разрешает расширение, Longhorn умеет онлайн-resize, а идентичный PVC на другой ноде вырос примерно за 40 секунд. Этот — нет.

Симптом

PVC бесконечно оставался в Resizing=True. Объекты самого Longhorn выглядели сделанными наполовину: spec.size тома уже был 20 GiB, status.expansionRequired — true, но currentSize движка так и не сдвинулся с 6 GiB. Внутри пода файловая система оставалась 6 GiB.

longhorn-manager каждые пять секунд писал Starting engine expansion from 6→20Gi на одной и той же ноде — и никакой ошибки. Цикл без сообщения об ошибке — худший вариант: даже искать нечего.

Сужаем круг

Идентичный PVC, который расширился без проблем, жил на другой ноде. Значит, проблема локальна для ноды. Сама нода была в Ready, так что дело не в kubelet, а в движке тома именно на этой ноде. С этой же ноды начинался более ранний инцидент, и на ней старое ядро, так что подозреваемый номер один был ясен.

Очевидный ход — перенести под на здоровую ноду, чтобы движок перезапустился там. Kubernetes отказал с Multi-Attach error: том «уже эксклюзивно подключён к другой ноде».

Взаимная блокировка

Longhorn отслеживает, кому нужен подключённый том, через attachment tickets на объекте volumeattachments.longhorn.io. Список тикетов показал виновника: тикет volume-expansion-controller, который прибивал том к плохой ноде.

Система завязала сама себя в узел:

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

Решение

Я удалил зависший тикет расширения JSON-патчем на VolumeAttachment Longhorn. Longhorn сам согласует тикеты, так что это не ручное состояние, которое потом надо поддерживать: контроллер пересоздаст то, что ему нужно. Освобождённый том Longhorn отключил, довёл отложенное расширение, пока том был отключён, и подключил снова.

Чтобы свежий движок поднялся в другом месте, я сделал cordon плохой ноды и удалил под StatefulSet. Он поднялся на здоровой ноде, CSI-плагин выполнил resize2fs, и df внутри пода показал 20 GiB. После этого я сделал uncordon.

Одно предупреждение для stateful-нагрузок: перенос пода перезапускает участника базы. Сначала убедитесь, что кворум держится (в MySQL Group Replication 2 из 3 выживают), и следите за errant transaction на участнике после рестарта: с ней инкрементальный rejoin невозможен и придётся пересобирать через clone.

Выводы

  • Цикл повторов без ошибки сам по себе подсказка: что-то ждёт условия, которое никогда не наступит. Ищите, что держит его на месте.
  • Если расширение ломается локально на ноде, сравните с той же операцией на другой ноде, прежде чем винить систему хранения.
  • Attachment tickets Longhorn стоит посмотреть пораньше: устаревший тикет объясняет и зависшее расширение, и Multi-Attach error.
  • Починить том — не значит починить ноду. Держите stateful-тома подальше от подозрительной ноды, пока по ней не будет отдельного разбора.