Без requests и limits scheduler не знает, сколько ресурсов нужно Pod, и при нехватке памяти kubelet вытесняет Pod произвольно. Resource management даёт scheduler данные для размещения и kubelet — приоритеты для eviction.
[source: kubernetes.io/docs/concepts/configuration/manage-resources-containers/]
Requests и Limits
Каждому контейнеру задаётся два параметра для CPU и памяти:
- requests — гарантированный минимум. Scheduler использует requests для выбора узла: если на узле нет запрошенных ресурсов — Pod туда не попадёт.
- limits — максимально допустимое потребление, принудительно ограничивается kubelet.
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: myapp:1.0
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
CPU
Измеряется в millicores (миллиядрах):
CPU — сжимаемый (compressible) ресурс. При превышении limit контейнер троттлится — замедляется, но не убивается.
Часть команд не ставит CPU limits в production, чтобы избежать throttling при наличии свободных ресурсов. Memory limits — обязательны.
Memory
Измеряется в байтах с суффиксами:
Память — несжимаемый (incompressible) ресурс. При превышении limit контейнер получает OOMKilled и перезапускается. kubectl describe pod покажет Reason: OOMKilled.
QoS классы
Kubernetes присваивает каждому Pod класс QoS. Он определяет приоритет при eviction на узле.
[source: kubernetes.io/docs/concepts/workloads/pods/pod-qos/]
Guaranteed
Все контейнеры в Pod имеют requests == limits для CPU и memory.
resources:
requests:
cpu: 500m
memory: 256Mi
limits:
cpu: 500m
memory: 256Mi
Наивысший приоритет, последний кандидат на eviction. Для критических сервисов.
Burstable
Хотя бы один контейнер имеет requests, и requests != limits (или limit не задан).
resources:
requests:
cpu: 250m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
Средний приоритет. Вытесняется после BestEffort.
BestEffort
Ни один контейнер не имеет requests и limits.
# resources не указаны вообще
Низший приоритет. Первый кандидат на eviction при нехватке ресурсов.
Порядок eviction
При нехватке памяти на узле kubelet вытесняет Pod в порядке: BestEffort → Burstable → Guaranteed.
# Посмотреть QoS класс Pod
kubectl get pod <name> -o jsonpath='{.status.qosClass}'
LimitRange
LimitRange задаёт defaults и допустимые диапазоны для контейнеров в Namespace.
[source: kubernetes.io/docs/concepts/policy/limit-range/]
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: dev
spec:
limits:
- type: Container
default: # limits по умолчанию (если не указаны)
cpu: 500m
memory: 256Mi
defaultRequest: # requests по умолчанию (если не указаны)
cpu: 100m
memory: 128Mi
min: # минимально допустимые requests
cpu: 50m
memory: 64Mi
max: # максимально допустимые limits
cpu: "2"
memory: 2Gi
- type: Pod
max:
cpu: "4"
memory: 4Gi
Если контейнер запросит ресурсы за пределами min/max — API Server отклонит манифест.
kubectl get limitrange -n dev
kubectl describe limitrange default-limits -n dev
ResourceQuota
ResourceQuota ограничивает суммарное потребление ресурсов в Namespace.
[source: kubernetes.io/docs/concepts/policy/resource-quotas/]
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: dev
spec:
hard:
# Вычислительные ресурсы
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
# Количество объектов
pods: "20"
services: "10"
services.loadbalancers: "2"
persistentvolumeclaims: "10"
configmaps: "20"
secrets: "20"
При активной ResourceQuota с requests.cpu или requests.memory каждый Pod обязан указать соответствующие requests — иначе API Server отклонит Pod. Поэтому ResourceQuota используют вместе с LimitRange: LimitRange задаёт defaults, ResourceQuota ограничивает суммарно.
# Просмотр квот и текущего использования
kubectl get resourcequota -n dev
kubectl describe resourcequota compute-quota -n dev
Рекомендации по выбору значений
Практический подход:
- Запустить приложение без limits
- Собрать метрики потребления (Prometheus +
kubectl top pods --containers) - Установить requests ≈ p50 потребления, limits ≈ p99 + запас 20-30%
# Текущее потребление ресурсов
kubectl top nodes
kubectl top pods
kubectl top pods --containers # по контейнерам
kubectl top pods -n production
Полный пример: Namespace с квотами и defaults
# 1. Namespace
apiVersion: v1
kind: Namespace
metadata:
name: production
---
# 2. LimitRange — defaults для контейнеров без явных requests/limits
apiVersion: v1
kind: LimitRange
metadata:
name: production-limits
namespace: production
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 128Mi
max:
cpu: "4"
memory: 4Gi
---
# 3. ResourceQuota — суммарные ограничения для namespace
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.cpu: "40"
limits.memory: 80Gi
pods: "100"
Когда использовать
requests всегда — без requests scheduler разместит Pod на узле без достаточных ресурсов.
memory limits всегда — утечка памяти в одном контейнере может убить весь узел.
CPU limits — опционально. Без них Pod может burst в свободные ресурсы; с ними throttling начинается даже при наличии свободных ядер.
LimitRange — в каждом namespace с пользователями или CI/CD. Защищает от Pod без requests/limits.
ResourceQuota — для мультикомандных кластеров с лимитами на команду/окружение.
Типичные ошибки
Нет requests — Pod в BestEffort. Pod первым вытесняется при нехватке ресурсов. В production у всех Pod должны быть requests.
OOMKilled в цикле. Приложение превышает memory limit, перезапускается, снова OOMKilled. Увеличить limit или исправить утечку. Диагностика: kubectl describe pod → Last State и Reason: OOMKilled.
CPU throttling незаметно ломает latency. kubectl top показывает текущее потребление, не пиковое. Throttling виден через Prometheus container_cpu_cfs_throttled_seconds_total.
ResourceQuota без LimitRange. При активной квоте Pod без явных requests не пройдут admission. Используй вместе.
Жёсткие limits для JVM. JVM потребляет много памяти при старте (heap + metaspace + stack). Ставь -Xmx ниже memory limit.
Альтернативы
Vertical Pod Autoscaler (VPA) — подбирает requests/limits по историческому потреблению. Режимы Off (рекомендации) и Auto (рестарт Pod). Устанавливается отдельно.
Horizontal Pod Autoscaler (HPA) — масштабирует реплики по CPU/memory/custom метрикам.
KEDA — event-driven autoscaler по внешним метрикам (Kafka lag, RabbitMQ, SQS).