"Под работает стабильно, потом его убивает с OOMKilled, а в логах ничего нет. И что тогда случилось?" - распространенная боль в проде, но в 80% случаев всему виной неправильно выставленные
resources. Это ооочень важная тема для понимания, чтобы в последствии понимать настройки любого пода (сорри за тавтологию, но лучше и не скажешь👍). Сегодня разберемся, как это всё работает
В
spec.containers[ ].resources мы описываем два параметра для CPU и памяти:
resources:
requests:
cpu: "250m" # 0.25 ядра
memory: "128Mi"
limits:
cpu: "500m" # 0.5 ядра
memory: "256Mi"
Requests - объём ресурсов, который Scheduler учитывает при размещении пода на ноде. Планировщик не запустит под, если на ноде недостаточно свободных ресурсов с учётом requests всех уже работающих подов. Реальное потребление контейнера может отличаться от
requestsПример: а ноде 4 CPU и 8 GiB памяти. Если там уже запущено подов с `requests: cpu=3, memory=6Gi`, то Scheduler пустит на неё новый под только если его `requests` ≤ 1 CPU и ≤ 2 GiB
Limits - максимальный объём ресурсов, который ядро Linux разрешает потреблять контейнеру через механизм cgroups. При превышении limits.cpu контейнер подвергается троттлингу (то есть к искусственному замедлению). При превышении limits.memory контейнер принудительно завершается через OOM-killer
Если говорить конкретней, что происходит с CPU и Memory при превышении Limits, то:
CPU (измеряется в миллиядрах: 100m = 0.1 ядра):
• Превышение limits.cpu, следовательно троттлинг
• Под не убивается, ему просто искусственно замедляют выполнение
• Реализовано через `cgroups` и CFS (Completely Fair Scheduler) ядра Linux
• Приложение начинает работать медленнее, но остаётся живым
• Признак проблемы в метриках, то есть растёт `container_cpu_cfs_throttled_periods_total`
Memory (измеряется в Mi/Gi):
• Превышение `limits.memory`, следовательно OOMKill (Out Of Memory Kill)
• Под убивается мгновенно ядром Linux, без предупреждения, без graceful shutdown (если не настроен `preStop hook`)
• Kubelet видит смерть и перезапускает контейнер (если restartPolicy: Always)
• Признак проблемы: в `kubectl describe` pod видно `OOMKilled` в состоянии `Last State`
Такие разные последствия превышения лимита обосновываются тем, что CPU - возобновляемый ресурс (такты процессора делятся между всеми). А вот память - невозобновляемый (то есть если её не хватит, ядру придётся кого-то убить, иначе упадёт вся нода). Linux выбирает «жертву» через OOM-killer
Ещё важно разобраться в том, что на основе requests и limits Kubernetes автоматически присваивает каждому поду класс качества обслуживания (QoS Class). Это напрямую диктует приоритет при нехватке ресурсов на ноде (Node Pressure) или при её восстановлении после сбоя 💻
• Guaranteed (requests == limits для CPU и памяти), высший приоритет. Планировщик старается разместить такие поды первыми. При критической нехватке ресурсов на ноде они умирают последними
• Burstable (заданы requests, но limits выше или не заданы), средний приоритет
• BestEffort (ресурсы не заданы вообще), низший приоритет, эдакое«пушечное мясо» кластера
ВАЖНО! Если у пода не заданы ограничения, при дефиците ресурсов на ноде он будет принудительно остановлен (evicted) в первую очередь, чтобы спасти поды с гарантированными ресурсами. При восстановлении ноды он также будет запущен в последнюю очередь.












