Задача 3. Requests, limits и три класса QoS

Два пода с одинаковым потреблением, но разными манифестами — при нехватке памяти на ноде выживет один. Разбираем, чем requests отличаются от limits и как из них получаются классы Guaranteed, Burstable и BestEffort.
Опубликовано:

Задача

На одной ноде работают два пода. Оба реально потребляют по 500 МиБ памяти. Манифесты разные:

YAML
# Под A
resources:
  requests:
    memory: "1Gi"
    cpu: "500m"
  limits:
    memory: "1Gi"
    cpu: "500m"
Нажмите, чтобы развернуть и увидеть больше
YAML
# Под B
resources:
  requests:
    memory: "256Mi"
    cpu: "100m"
  limits:
    memory: "2Gi"
Нажмите, чтобы развернуть и увидеть больше

На ноде заканчивается память.

Вопрос: какой под будет убит первым и почему?

Что кажется очевидным

«Потребление одинаковое — значит, шансы равны» или «убьют того, кто просит больше памяти, то есть A».

И то, и другое неверно.

Как это работает на самом деле

Сначала — про сами поля, потому что путаница обычно начинается здесь.

requests — это обещание планировщику: «этому контейнеру нужно столько». По сумме requests планировщик решает, влезет ли под на ноду. Это не лимит — контейнер может потреблять больше.

limits — потолок. Для памяти жёсткий: превысил — OOMKilled. Для CPU — троттлинг, процесс просто замедляют.

Из соотношения этих двух полей Kubernetes выводит класс QoS — он и определяет, кого приносить в жертву при нехватке ресурсов:

КлассУсловиеПри нехватке памяти
Guaranteedrequests == limits для всех контейнеров и по CPU, и по памятивытесняют последним
Burstablerequests заданы, но не равны limits (или заданы частично)вытесняют вторыми
BestEffortни requests, ни limits не заданывытесняют первыми

Посмотреть класс:

BASH
kubectl get pod my-pod -o jsonpath='{.status.qosClass}'
Нажмите, чтобы развернуть и увидеть больше

В нашей задаче: под A — Guaranteed (requests равны limits по обоим ресурсам), под B — Burstable.

Что происходит при нехватке памяти

Два разных механизма, которые часто смешивают:

1. Вытеснение kubelet’ом (eviction). Kubelet следит за ресурсами ноды. Когда свободной памяти становится мало, он начинает выселять поды — и выбирает по классу QoS: сначала BestEffort, потом Burstable (среди них — тех, кто сильнее превысил свой request), в последнюю очередь Guaranteed.

2. OOM killer ядра. Если память кончается резко, вмешивается ядро Linux. Оно оперирует значением oom_score_adj, которое kubelet проставляет исходя из QoS: у Guaranteed — наименее «убиваемое» значение, у BestEffort — наиболее.

Под B превысил свой request (256 МиБ) более чем вдвое — он и есть первый кандидат.

Ответ

Первым убьют под B. Он в классе Burstable и потребляет вдвое больше запрошенного, тогда как под A — Guaranteed и укладывается в свой запрос.

Парадокс, который стоит осознать: под A «просит больше», но именно поэтому защищён. Запрошенные ресурсы — это ваша броня, а не расточительство.

Что с этим делать

Подробнее про сам механизм вытеснения и пороги — в задаче 19, а про то, что именно считается памятью контейнера, — в задаче 5.


Дальше: Задача 4. Общий кластер на несколько команд.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
ESC
⌘K Горячая клавиша