Logo Craft Homelab Docs Нейросети Хостинг Обучение Контакты
Аварийное восстановление мультикластерного Linkerd: четыре сценария отказа и что они показали Трендовые github проекты в нашем телеграм канале. Подпишись →
22 октября 2026 г.

Как ломается сервисная сетка, когда падает кластер или регион

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

Ниже разобран стенд из трёх кластеров с Linkerd и четыре сценария: отказ control plane, кластера, зоны доступности и региона.

Стенд

Три кластера — WEST, CENTRAL и EAST — подняты локально через k3d в общей Docker-сети. В каждом по три узла, каждый узел изображает отдельную зону доступности. CENTRAL и EAST находятся в одном «регионе», WEST — в другом. В WEST живут генератор нагрузки k6 и мониторинг на Prometheus + Grafana; сбои вносятся только в CENTRAL и EAST, чтобы не потерять метрики.

Приложение — podinfo, по одной реплике на узел, девять реплик всего. Оно опубликовано сразу в трёх мультикластерных режимах Linkerd:

  • federated — один логический сервис, эндпойнты которого собираются из всех кластеров-участников;
  • flat (pod-to-pod) — сервисы удалённых кластеров зеркалируются, клиент сам выбирает, куда идти (в тесте k6 ходит в EAST);
  • gateway — в исходном кластере создаётся сервис, эндпойнт которого указывает на шлюз в целевом кластере; поды разрешает уже целевой кластер.

Нагрузка постоянная: 30 RPS на каждый режим в каждом кластере. Сбои вносятся остановкой подов и Docker-контейнеров-узлов, удалением Docker-сети и задержками через Chaos Mesh. Для облака те же сценарии воспроизводятся через Chaos Mesh или LitmusChaos.

На дашборде отслеживались: запросы без mTLS, RPS, доля ошибок, число эндпойнтов federated-сервиса, доступность шлюза и доля межзонального трафика.

Сценарий 1: отказ control plane

Недоступен destination

Сервис destination отвечает за обнаружение эндпойнтов и контроллер политик. Его выключили в CENTRAL, а затем отмасштабировали приложение в EAST до нуля. Через 90 секунд CENTRAL по-прежнему считал все federated-эндпойнты живыми, хотя подов в EAST уже не существовало. Сетка продолжала работать на устаревшей картине мира.

Недоступен identity

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

Отсюда главный вывод сценария: план переключения почти всегда включает масштабирование, а масштабирование зависит от живого control plane. Если сетка лежит, процедура восстановления упирается в неё. Health-чеки подов при этом могут маскировать проблему: приложение отвечает, пока не понадобится что-то поменять.

Сценарий 2: отказ кластера

В EAST остановили все три узла, затем повторили тест с удалением Docker-сети между кластерами — полная потеря связности.

Режимы реагируют по-разному, и разница определяется тем, где происходит обнаружение эндпойнтов: в локальном кластере (federated, flat) или в удалённом (gateway). В одних режимах отказ виден сразу, в других — только косвенно.

Самая неприятная ловушка: если discovery продолжает отдавать мёртвые эндпойнты, запросы уходят туда и висят до тайм-аута клиента. Если тайм-аутов нет, метрики вроде request_total даже не растут — ошибок в статистике нет, потому что запросы не завершаются. Алерт на долю ошибок такую ситуацию пропустит. Тайм-ауты и ретраи нужно задать либо в клиенте, либо средствами Linkerd.

Для тестов полезнее жёсткие обрывы, чем graceful shutdown. Корректное завершение замечают readiness-пробы и другие механизмы, а внезапная потеря узла обнаруживается только по тайм-аутам discovery. Именно так получаются честные цифры времени обнаружения и восстановления.

Сценарий 3: зона деградирует

В одну зону кластеров EAST и CENTRAL добавили задержку +400 мс. Поды всё это время оставались healthy.

Topology-aware routing в Kubernetes такую зону не видит: формально всё работает, и трафик продолжает идти в медленные эндпойнты. HAZL (High Availability Zonal Load Balancing из Buoyant Enterprise for Linkerd) смотрит на фактическое поведение эндпойнтов и уводит трафик туда, где отвечают быстрее.

У HAZL есть и второй эффект — деньги. В штатном режиме он держит трафик в своей зоне даже при переходе между кластерами. Open source Linkerd распределяет ту же нагрузку без учёта зон, и в облаке большинство запросов превращается в оплачиваемый межзональный egress.

Ограничение: межкластерная зональная локальность HAZL пока работает только в режиме flat (pod-to-pod), на gateway она не распространяется.

Сценарий 4: отказ региона

Оба кластера региона a выключены, остаётся только WEST.

Federated-режим это пережил: поды WEST уже входили в пул federated-сервиса, и трафик просто перетёк на них. Условие одно — WEST должен выдержать всю нагрузку и уметь масштабироваться. Если запаса мощности нет, нужны rate limiting и circuit breaking, чтобы сервисы принимали ровно столько запросов, сколько могут обработать; Linkerd поддерживает оба механизма.

Flat и gateway в этом тесте отказали, потому что их целевые эндпойнты находились в упавшем регионе. Это свойство конкретной схемы стенда, в другой топологии результат будет другим.

Настройки установки, которые выстрелят во время аварии

Установка Linkerd с дефолтными значениями Helm-чарта и установка по production-гайду Buoyant ведут себя по-разному:

  • webhookFailurePolicy. Без HA-режима для proxy injector стоит Ignore. Если injector недоступен, поды стартуют без прокси и оказываются вне сетки — без mTLS и без политик. В HA-режиме значение меняется на Fail, и такие поды не создаются вовсе. Какой вариант лучше, зависит от того, что для вас хуже во время аварии: поды вне сетки или поды, которые не запускаются.
  • defaultInboundPolicy. В обоих режимах по умолчанию all-unauthenticated: поды в сетке принимают трафик без mTLS, пока политику не ужесточат глобально или на уровне namespace.

Перед тем как писать DR-план, стоит пройтись по production-чеклисту Buoyant и сверить свои значения.

Алерты, которых нет из коробки

Алерт на долю 5xx ловит только симптом. Для сетки нужны отдельные сигналы:

  • состояние компонентов control plane (destination, identity, proxy injector);
  • срок действия сертификатов прокси;
  • поды, застрявшие на инициализации и не вошедшие в сетку;
  • трафик без mTLS там, где его быть не должно;
  • для federated — число эндпойнтов, для gateway — доступность шлюза.

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

Как построить тест

Возьмите один сценарий — например, выход кластера из строя или рост задержки в регионе — и прогоните его целиком:

  1. Зафиксируйте исходное состояние: сервисы работают, нагрузка стабильная.
  2. Запишите ожидаемое поведение: например, межкластерные запросы падают по тайм-ауту.
  3. Внесите сбой и проверьте, что алерты сработали.
  4. Восстановите систему и проверьте, что алерты закрылись.
  5. Разберите, какие компоненты отказали, исправьте и повторите.

Последний этап обязателен. Проблемы с identity на стенде проявлялись только при попытке поднять реплики, то есть уже во время восстановления. Тест, который заканчивается на «сбой внесён, алерт пришёл», их не поймает. Отдельный полезный вариант: остановить часть control plane и одновременно дать нагрузку, которая запустит автоскейлинг, — так сразу видно, успеют ли алерты раньше пользователей.