Прямой ответ
Cluster Autoscaler (CA) меняет число узлов кластера. В отличие от HPA, который управляет числом подов, CA управляет ёмкостью, на которой эти поды размещаются. Работает он в связке с планировщиком.
Масштабирование вверх. CA периодически проверяет наличие подов в состоянии Pending, которые не разместились из-за нехватки ресурсов. Если такие поды есть, CA выбирает группу узлов и увеличивает её размер. Новый узел регистрируется, и планировщик размещает ожидающие поды.
Масштабирование вниз. Узел считается кандидатом на удаление, если его загрузка ниже порога (по умолчанию 50 % от allocatable) и он остаётся в таком состоянии заданное время (по умолчанию 10 минут). Перед удалением CA вытесняет поды с узла, соблюдая PodDisruptionBudget.
Узел не будет удалён, если на нём выполняется хотя бы одно из условий:
| Блокирующее условие | Причина |
|---|---|
| Под с PodDisruptionBudget, который будет нарушен | Защита от добровольных прерываний |
| Под kube-system без PDB | Защита системных компонентов |
| Под с локальным хранилищем (emptyDir) | Потеря данных |
| Под, который не может быть перемещён | Отсутствие подходящего узла |
Аннотация cluster-autoscaler.kubernetes.io/scale-down-disabled: "true" |
Явный запрет |
Задержки защищают от колебаний: после добавления узла CA не удаляет узлы заданное время, после удаления — тоже. Без них кластер входил бы в цикл «добавили узел, нагрузка распределилась, узел стал пустым, удалили».
# запрет удаления конкретного узла
metadata:
annotations:
cluster-autoscaler.kubernetes.io/scale-down-disabled: "true"
Практика: настройка и эксплуатация
1. Связка HPA + CA. HPA поднимает число реплик по загрузке, новые поды попадают в Pending, CA добавляет узлы. Задержка полного цикла — от нескольких десятков секунд до нескольких минут, в зависимости от времени запуска узла в облаке. Планировать ёмкость нужно с учётом этой задержки — см. статью про capacity planning.
2. CA опирается на requests. Под без requests считается не требующим ресурсов и не провоцирует добавление узла. Заниженные requests приводят к размещению на узле, где фактически ресурсов нет, — см. статью про requests и limits.
3. Задавайте PodDisruptionBudget. Без PDB вытеснение при удалении узла может остановить все реплики сервиса одновременно. Это самый частый источник проблем при включённом CA.
4. Системные поды мешают scale down. Поды в kube-system без PDB делают узел неудаляемым. Либо задайте им PDB, либо размещайте на выделенной группе узлов, не участвующей в автомасштабировании.
5. Используйте несколько групп узлов. Разделение по типу нагрузки (рабочие поды, пакетные задачи, GPU) позволяет масштабировать каждую группу независимо и выбирать разные типы машин.
6. Следите за фрагментацией. Несколько частично заполненных узлов не удаляются, если на каждом остаётся под. Задержка scale down и правильный размер узла снижают расход.
7. Проверяйте поведение при исчерпании квоты облака. CA не может добавить узлы, если достигнут лимит виртуальных машин в регионе; событие об этом видно в логах CA, но не в статусе подов.
Рекомендации:
- Начните с ограниченного диапазона. Минимум один-два узла, максимум — исходя из бюджета. Без верхней границы ошибка в HPA приводит к неконтролируемому росту счёта.
- Разделяйте группы по критичности. Рабочие нагрузки и разовые задачи на одних узлах мешают друг другу: всплеск пакетных задач вытесняет рабочие поды.
- Мониторьте число pending-подов. Это опережающий индикатор: если поды ждут размещения дольше пары минут, CA не справляется либо упирается в лимит.
- Тестируйте вытеснение. Проверка, что сервис переживает удаление узла, важнее настройки самого автоскейлера.
- Согласуйте с бюджетом. Автомасштабирование без алерта на число узлов превращает ошибку конфигурации в счёт на крупную сумму.
Практический сценарий: узлы добавлялись, но не удалялись
Контекст: кластер в облаке вырос с 6 до 14 узлов за сутки и держался на этом уровне неделю, хотя нагрузка вернулась к обычной.
- Диагностика.
kubectl get nodesпоказал 14 узлов, из них 8 с загрузкой ниже 20 %. Логи CA содержали сообщение о невозможности вытеснения подов. - Проверка подов. На «пустых» узлах находились поды
kube-systemбез PDB: сборщики метрик и агент логирования, развёрнутые как DaemonSet без исключений, и несколько подов мониторинга. - Дополнительная причина. Часть рабочих подов использовала
emptyDirдля кэша, что делает узел неудаляемым по правилам CA. - Действия. (а) Для подов
kube-systemзадали PodDisruptionBudget, позволяющий вытеснение; (б) агенты мониторинга перевели в тип, допускающий перезапуск, и убрали блокирующее локальное хранилище там, где оно не было нужно; (в) для сервисов сemptyDirоценили необходимость кэша и заменили его внешним хранилищем у двух из трёх; (г) для оставшегося сервиса закрепили выделенную группу узлов, исключённую из scale down; (д) добавили метрику на число узлов и алерт на отклонение от ожидаемого диапазона. - Результат. Через два часа CA сократил кластер до 6 узлов; недельный перерасход прекратился, а алерт на число узлов выявил бы подобную ситуацию в первые часы.
Вывод: масштабирование вниз блокируется конкретными подами, а не настройками CA. Проверка PodDisruptionBudget и локального хранилища важнее подбора порогов: без неё узлы остаются навсегда, а расход растёт незаметно.
FAQ
Чем Cluster Autoscaler отличается от HPA? HPA меняет число реплик внутри доступной ёмкости, CA меняет саму ёмкость. Они дополняют друг друга: без CA рост реплик упирается в пределы кластера.
Как быстро CA реагирует на всплеск? Проверка выполняется периодически, обычно каждые 10 секунд, плюс время запуска узла в облаке — от десятков секунд до нескольких минут. Для резких всплесков нужен запас ёмкости.
Что происходит с подами при удалении узла? CA вытесняет их с соблюдением PodDisruptionBudget; поды пересоздаются на других узлах. Если PDB запрещает вытеснение, узел не удаляется.
Можно ли использовать CA с локальным хранилищем? Можно, но поды с локальным хранилищем делают узел неудаляемым. Для таких нагрузок нужна выделенная группа узлов без автомасштабирования вниз.
Источники: Kubernetes docs (autoscaling, disruptions), Cluster Autoscaler FAQ — ссылки в шапке.