Распределённая тренировка выглядит здоровой: Pod в Running, рестартов нет, OOMKill нет, scheduler доволен. Но обучение не начинается, а большая часть дорогих GPU простаивает. Такой сбой легко пропустить, потому что каждый отдельный компонент работает в рамках собственного контракта.

Авторы лаборатории Kubeflow/Cilium воспроизвели именно этот сценарий. Kubernetes разместил coordinator и worker по доступным ресурсам, а Cilium честно применил межзонную сетевую политику. Scheduler не знал о закрытом пути, CNI не мог переставить уже запущенный workload. Два локально правильных решения вместе создали неработающую систему.

Как возникает невидимый конфликт

Распределённая тренировка состоит как минимум из coordinator и нескольких GPU-worker. Worker обмениваются параметрами и синхронизируют градиенты; без связи с coordinator вычислительный конвейер не продвигается.

Kubernetes scheduler обычно смотрит на запрошенные CPU, память, GPU, taint, affinity и другие объявленные ограничения. Он не выводит сетевую достижимость из произвольной CiliumNetworkPolicy и не понимает, что конкретной группе Pod необходимо находиться внутри одного разрешённого сетевого домена.

Cilium, напротив, применяет указанную оператором политику. Разделение availability zone может быть осознанным: для ограничения blast radius, соблюдения требований или защиты выделенного GPU-пула. Нарушить правило ради уже принятого scheduler решения CNI не должен.

В результате coordinator оказывается в одной зоне, worker — в другой, а network policy блокирует трафик. Для Kubernetes все процессы запущены. Для ML-задачи полезной работы нет.

Три проявления одной причины

Одинаковое рассогласование topology и network policy проявляется по-разному.

1. Жёсткая блокировка

Межзонное соединение запрещено. Worker ждут coordinator, тренировка не стартует. Это самый заметный вариант: таймауты и отсутствие прогресса появляются быстро.

2. Тихая потеря производительности

Соединение разрешено, но gradient synchronization постоянно платит за cross-zone latency. Авторы отмечают возможное падение throughput на 30–60% без явной ошибки. Все readiness probe остаются зелёными, а задача просто выполняется намного дольше.

3. Лишний сетевой счёт

Тренировка работает, но большой поток данных ходит между availability zone. Проблема обнаруживается не в логах, а позже в строке inter-AZ data transfer.

Эти варианты полезно рассматривать вместе. Жёсткий deny, latency и стоимость — разные наблюдаемые эффекты одного отсутствующего контракта: scheduler не получил информацию о сетевой topology группы.

Почему не нужно ослаблять Cilium policy

Первая реакция при blocked traffic — разрешить соединение. Но в этой истории политика выражала нужную границу безопасности. Удалить её означало бы исправить симптом ценой расширения blast radius.

Авторы оставили Cilium без изменений и добавили scheduler недостающие ограничения:

  • nodeAffinity закрепляет группу за подходящей GPU-зоной;
  • topologySpreadConstraints задаёт допустимое размещение связанных Pod;
  • toleration разрешает coordinator попасть на tainted GPU-узлы;
  • альтернативный podAffinity размещает worker в той зоне, куда попал coordinator, без жёстко заданного имени зоны.

Идея проста: communicating group должна размещаться там, где разрешён её внутренний трафик. Политика остаётся строгой, workload становится topology-aware.

В лаборатории после co-location загрузка GPU выросла примерно с 40 до 85%. Один и тот же fix убрал hard block, cross-zone latency и межзонный трафик.

Пример направления исправления

Конкретный YAML зависит от operator и структуры MLJob, но смысл ограничения можно показать сокращённо:

spec:
  template:
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchLabels:
                  training-role: coordinator
              topologyKey: topology.kubernetes.io/zone
      tolerations:
        - key: dedicated
          operator: Equal
          value: gpu
          effect: NoSchedule

Такой фрагмент нельзя копировать в production вслепую. Нужно проверить labels, направление affinity, поведение при недоступной зоне и способность autoscaler добавить подходящие узлы. Слишком жёсткое правило способно заменить сетевой сбой на вечный Pending.

Какие сигналы должны быть на дашборде

Стандартного статуса Pod недостаточно. Для распределённой ML-задачи полезно связать минимум четыре группы сигналов:

  • фактическую загрузку GPU и память ускорителя;
  • прогресс job: step, epoch, batch или checkpoint;
  • размещение coordinator и worker по zone/node;
  • deny, retransmit, latency и объём cross-zone traffic.

Ключевой алерт должен отвечать не на вопрос «запущен ли контейнер», а на вопрос «производит ли job полезную работу». Например: все Pod Running, но GPU utilization ниже порога и training step не меняется заданное время.

Для расследования удобно строить единую таблицу:

pod → role → node → zone → GPU utilization → peer connectivity

Она соединяет то, что scheduler, CNI и ML-framework обычно показывают в разных интерфейсах.

Как воспроизвести без production-риска

Авторы опубликовали лабораторию с kind-кластером, CPU/GPU-зонами, Cilium policy, правилами Prometheus, Grafana dashboard и сценариями «до/после». Это хороший формат проверки архитектурной гипотезы: команда видит failure mode до того, как он появится на дорогом кластере.

Для собственного теста достаточно доказать четыре состояния:

  1. scheduler способен разнести coordinator и worker;
  2. policy блокирует или замедляет межзонный путь;
  3. Pod остаются формально здоровыми при отсутствии прогресса;
  4. topology constraint возвращает workload к полезной работе без ослабления policy.

После этого стоит добавить regression-проверку в шаблон платформы или admission policy, а не надеяться, что каждый ML-инженер вспомнит о topology вручную.

Где заканчивается вывод

Числа 40% и 85% относятся к воспроизводимой лаборатории, а не к универсальному бенчмарку Kubeflow или Cilium. Реальный эффект зависит от модели, размера batch, типа collective communication, сети, accelerator и облачного тарифа.

Но общий паттерн переносится далеко за пределы ML: scheduler оптимизирует объявленные ресурсы, сеть применяет объявленную политику, а бизнес-workload имеет неявные зависимости между ними. Если зависимость не выражена в spec и не наблюдается как единый SLI, зелёные компоненты не гарантируют здоровую систему.