OpenAI масштабировала Kubernetes до 7500 узлов: что сломалось
Кластер в 7500 нод — территория, где ломается почти всё: DNS, etcd, сеть, планировщик. OpenAI прошла этот путь и опубликовала подробный отчёт о боли.

Kubernetes официально поддерживает кластеры до 5000 узлов. OpenAI довела свои до 7500 — и сделала это ради обучения больших моделей, где один тренировочный job съедает тысячи GPU и требует MPI-подобной связности между подами. По пути пришлось переписать сетевой слой, вынести мониторинг за пределы Prometheus и научиться жить с etcd, который начинает икать на объёме в десятки гигабайт.
Зачем вообще один такой большой кластер
Обычная рекомендация — резать нагрузку на несколько кластеров поменьше. Для веб-сервисов это работает. Для обучения GPT-класса — нет: MPI-джобы требуют, чтобы все GPU видели друг друга через быструю сеть с низкой задержкой. Резать кластер — значит резать сеть, а это удлиняет каждую итерацию обучения.
Второй мотив — эксплуатационный. Один кластер — один набор политик, один API-сервер, одна точка обновления. Инженерная команда OpenAI сознательно выбрала «одно большое чудовище» вместо десятка маленьких, чтобы не размазывать SRE-усилия.
Что ломается на масштабе
API-сервер и etcd
Первый удар приходится по управляющему слою. API-сервер держит открытые watch-соединения от каждого kubelet, каждого контроллера и каждого оператора. На 7500 узлов это десятки тысяч потоков, и штатный размер heap уже не помогает.
- API-серверов подняли несколько, за балансировщиком, с закреплением клиента к одному экземпляру — иначе кэши watch не прогреваются.
- etcd вынесли на отдельные машины с NVMe и отдельным дисковым пулом под WAL, чтобы fsync не боролся за IOPS с данными.
- События Kubernetes (те самые Events, которые пишутся о каждом рестарте) отправили в отдельный etcd-кластер. Иначе шум от событий забивает основной.
Сеть и DNS
Дефолтный CoreDNS на таком масштабе перестаёт справляться: каждый под резолвит имена соседей, и на пике запросы измеряются сотнями тысяч в секунду. Помогло размещение локального DNS-кэша на каждом узле (NodeLocal DNSCache) и агрессивное отключение поиска по search-доменам в самих приложениях.
Сетевой слой — отдельная история. Kube-proxy с iptables на кластере такого размера собирает таблицы, которые обновляются секундами. Переход на альтернативные подходы (в блоге OpenAI упоминаются собственные доработки поверх Alias-IP в GCP-стиле для Azure) снял основную боль.
Планировщик
Стандартный kube-scheduler думает о каждом поде отдельно. Для MPI-джобы это катастрофа: нужно, чтобы либо все 512 подов встали, либо ни один. Иначе половина забронирует GPU и будет ждать вторую половину, которая не поместится.
«Мы поняли, что gang scheduling — не опциональная фича, а базовое требование. Без него узлы простаивают часами.»
Решение — coscheduler-плагины и жёсткие taints на GPU-узлах, чтобы туда не заезжали случайные системные поды и не блокировали место.
Метрики: Prometheus сдался
Один Prometheus не тянет 7500 узлов. Ряды взрываются от количества GPU-метрик (utilization, память, температура, ECC-ошибки на каждый чип), и WAL перестаёт помещаться в память.
| Компонент | Что не работает на 7500 нод | Обход |
|---|---|---|
| Prometheus | OOM при загрузке WAL, часы на рестарт | Шардирование по namespace, GOMAXPROCS-тюнинг |
| etcd | Раздутый storage от Events | Отдельный etcd-кластер под события |
| CoreDNS | Задержки, timeout'ы клиентов | NodeLocal DNSCache на каждом узле |
| kube-proxy | Секундные обновления iptables | Отказ от iptables-режима |
| kube-scheduler | Нет атомарности для MPI-джобов | Coscheduler / gang scheduling |
Health-check как отдельный сервис
GPU выходят из строя. Не «может быть», а стабильно: на тысячах узлов каждый день кто-то ловит ECC-ошибку, деградацию NVLink или зависание драйвера. Kubernetes про это ничего не знает — для него узел «Ready», пока kubelet отвечает.
OpenAI написала свой контроллер, который гоняет по узлам синтетические тесты: короткий allreduce между GPU, проверка пропускной способности NVLink, чтение из /dev/nvidia*. Узел, провалившийший тест, получает taint и выводится из планирования до ручного разбора.
# Упрощённый пример проверки, которую крутит агент
nvidia-smi --query-gpu=ecc.errors.uncorrected.volatile.total \
--format=csv,noheader,nounits | \
awk '{ if ($1 > 0) exit 1 }'
Что из этого забирать себе
Мало кто держит 7500 узлов. Но проблемы начинаются гораздо раньше — уже на 500-1000. Полезные выводы для кластеров поменьше:
- Выносите Events в отдельный etcd, как только заметили рост размера БД. Это дешёвая операция, откладывать её незачем.
- Ставьте NodeLocal DNSCache сразу. Он почти ничего не стоит и снимает целый класс инцидентов.
- Если у вас GPU или другие ускорители — пишите свой health-checker. Kubelet не заметит деградацию железа.
- Считайте, во сколько обходится downtime одного узла с ускорителем. Час простоя H1001 — это порядка 2-4 долларов у гиперскейлеров, умножьте на количество узлов в джобе.
1 H100 — топовый ускоритель Nvidia для обучения LLM, цена аренды у облачных провайдеров на конец 2024 года держалась в диапазоне 2-4 доллара за GPU-час.
Prompt-инженер: Идеальные запросы для Midjourney, ChatGPT и других моделей.
Спросить за 15 ₽Источники: Scaling Kubernetes to 7,500 nodes — OpenAI Blog, Scaling Kubernetes to 2,500 nodes — OpenAI Blog
Частые вопросы
Почему OpenAI не разбила нагрузку на несколько кластеров?
Официальный лимит Kubernetes — 5000 узлов. Как его удалось превысить?
Что такое gang scheduling и зачем он для ML?
Почему стандартный Prometheus не тянет такой масштаб?
Стоит ли повторять этот путь, если у меня 200 узлов?
Какие альтернативы iptables-режиму kube-proxy?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.