Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → ResourceQuota и квоты namespace

ResourceQuota и LimitRange: квоты namespace в Kubernetes

ResourceQuota и LimitRange: квоты на CPU, память и число объектов, значения по умолчанию, scope selectors и разбор отказа создания пода.

Прямой ответ

ResourceQuota ограничивает суммарное потребление ресурсов в namespace. Без неё одна команда может занять всю ёмкость кластера, и остальные namespace останутся без возможности запускать поды.

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-quota
  namespace: billing
spec:
  hard:
    requests.cpu: "20"
    requests.memory: 40Gi
    limits.cpu: "40"
    limits.memory: 80Gi
    pods: "50"
    persistentvolumeclaims: "20"
    requests.storage: 200Gi
    services: "10"
    configmaps: "100"
    secrets: "100"
    count/deployments.apps: "30"
    count/jobs.batch: "100"

Важное следствие: если в namespace действует квота на CPU или память, каждый под обязан указывать requests и limits для соответствующего ресурса. Иначе создание отклоняется с ошибкой must specify .... Это одна из самых частых причин внезапного отказа деплоя после введения квот.

Текущее использование видно так:

kubectl describe quota team-quota -n billing
kubectl get resourcequota -n billing -o yaml

LimitRange задаёт значения по умолчанию и границы для отдельного контейнера:

apiVersion: v1
kind: LimitRange
metadata:
  name: defaults
  namespace: billing
spec:
  limits:
    - type: Container
      default:          # лимит по умолчанию, если не задан
        cpu: "1"
        memory: 512Mi
      defaultRequest:   # requests по умолчанию
        cpu: 100m
        memory: 128Mi
      min:
        cpu: 50m
        memory: 64Mi
      max:
        cpu: "4"
        memory: 8Gi

LimitRange решает ровно ту проблему, которую создаёт квота: манифесты без явных ресурсов получают осмысленные значения вместо отказа. Но значения по умолчанию не заменяют расчёта — под с дефолтом может получить слишком мало памяти и падать, см. статью про requests и limits.

Практика: как проектировать квоты

1. Квотируйте и requests, и limits. Ограничение только limits не мешает занять всю ёмкость планировщика: поды с маленькими requests размещаются на узлах, пока они не закончатся.

2. Ограничивайте число объектов. Квота на pods, configmaps и secrets защищает от бесконечного создания Job и от утечек конфигурации. Для контроллеров используйте форму count/<ресурс>.<группа>, например count/deployments.apps.

3. Учитывайте хранилище. persistentvolumeclaims и requests.storage предотвращают ситуацию, когда namespace заказывает тома больше, чем есть в кластере.

4. Используйте scope selectors для разделения. Квота может применяться только к определённым подмножествам:

spec:
  scopes: ["NotTerminating"]
  hard:
    pods: "40"

Селекторы Terminating/NotTerminating, BestEffort/NotBestEffort и PriorityClass позволяют разделить квоты для рабочих нагрузок и для разовых задач, чтобы миграция или бэкап не расходовали квоту продакшн-подов.

5. Квота не защищает узел. Она ограничивает namespace, но не гарантирует качество обслуживания: поды одного namespace продолжают конкурировать между собой. Изоляцию трафика решает NetworkPolicy — см. статью про изоляцию подов.

6. Квота сочетается с RBAC. Право создавать поды в namespace без права превышать квоту — обычная схема: разработчики могут деплоить, но не могут расширить лимиты. Настройка прав описана в статье про RBAC.

Рекомендации:

  1. Вводите LimitRange до ResourceQuota. Тогда существующие манифесты без ресурсов продолжат разворачиваться, а команда получит время указать явные значения.
  2. Считайте квоту от фактического потребления. Значение, взятое «с запасом в три раза», делает квоту бессмысленной; значение по текущему среднему блокирует рост.
  3. Оставьте запас на всплески. Квота по requests должна учитывать масштабирование: если HPA поднимает число подов вдвое, квота обязана это вместить.
  4. Мониторьте заполнение. Метрика использования квоты близка к 100 % задолго до инцидента; алерт на 85 % даёт время на реакцию.
  5. Не смешивайте команды в одном namespace. Квота применяется к namespace целиком, поэтому общий namespace означает общую квоту и взаимные блокировки.

Практический сценарий: деплой встал после введения квот

Контекст: в namespace добавили ResourceQuota с ограничением requests.cpu: 20. В тот же день все деплои начали падать с ошибкой создания пода.

  1. Диагностика. kubectl describe pod показал сообщение forbidden: failed quota: must specify requests.cpu, requests.memory. То есть отказ связан не с нехваткой ёмкости, а с отсутствием полей в манифесте.
  2. Проверка масштаба. Из 18 деплойментов явные ресурсы имели 5. Остальные развернулись раньше введения квоты и работали, но не могли пересоздаться.
  3. Причина. Квоту ввели без LimitRange и без предварительной проверки манифестов.
  4. Действия. (а) Добавили LimitRange со значениями по умолчанию, чтобы деплой восстановился немедленно; (б) для каждого сервиса проставили реальные requests по метрикам потребления, а не по умолчанию; (в) добавили в CI проверку наличия resources в манифестах; (г) для разовых задач создали отдельную квоту со scope NotTerminating, чтобы миграции не расходовали квоту рабочих подов; (д) настроили алерт на заполнение квоты выше 85 %.
  5. Результат. Деплой восстановился; через неделю значения по умолчанию остались только у трёх некритичных сервисов, а квота начала выполнять свою функцию — при попытке занять больше выделенного запрос отклонялся с понятной причиной.

Вывод: ResourceQuota меняет требование к манифестам — ресурсы становятся обязательными. Вводить квоту нужно вместе с LimitRange и предварительной проверкой существующих манифестов, иначе деплой останавливается в момент введения, а не в момент исчерпания.

FAQ

Что происходит при попытке превысить квоту? Запрос отклоняется admission-контроллером, объект не создаётся. Уже работающие поды не затрагиваются: квота проверяется в момент создания или обновления.

Чем ResourceQuota отличается от LimitRange? ResourceQuota ограничивает сумму по namespace, LimitRange — значения отдельного контейнера и задаёт значения по умолчанию. Они решают разные задачи и обычно применяются вместе.

Влияет ли квота на уже запущенные поды? Нет. Квота учитывается при создании и обновлении объектов, поэтому изменение квоты в меньшую сторону не завершает работающие поды, но блокирует новые.

Можно ли задать разные квоты для разных команд в одном namespace? Нет, квота привязана к namespace. Разделение команд требует отдельных namespace, что совпадает и с требованиями RBAC, и с сетевой изоляцией.

Источники: Kubernetes docs (Resource Quotas, Limit Ranges) — ссылки в шапке.