АрхитектураОблако и инфраструктураИнженер по платформенной инфраструктуре Kubernetes

Разберите ситуацию: новый под остаётся в Pending, хотя на узле нет свободной памяти, но его приоритет выше ...

Разберите ситуацию: новый под остаётся в Pending, хотя на узле нет свободной памяти, но его приоритет выше уже работающих подов. Как механизм вытеснения позволяет планировщику разместить его?

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: critical
value: 100000
preemptionPolicy: PreemptLowerPriority
---
apiVersion: v1
kind: Pod
metadata:
  name: payments
spec:
  priorityClassName: critical
  containers:
    - name: app
      image: example/payments:2.0
      resources:
        requests:
          memory: 2Gi
Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Вытеснение подов (preemption) позволяет планировщику удалить один или несколько менее приоритетных подов, чтобы освободить ресурсы для нового пода. Приоритет задаётся через PriorityClass, а вытеснение применяется только если после удаления подходящих жертв новый под действительно сможет быть размещён.

Это не создаёт дополнительных ресурсов: временно или постоянно прекращаются менее важные нагрузки. Если для пода не существует подходящего узла даже после вытеснения, его статус останется Pending.

Исторический контекст

В обычном планировании под может ожидать бесконечно долго, если кластер занят менее важными задачами. Для критичных сервисов этого недостаточно: им требуется получить ресурсы даже при перегрузке кластера.

Механизм приоритетов и вытеснения отделяет важность нагрузки от времени её запуска. Это позволяет заранее определить, какие рабочие нагрузки должны сохраняться при дефиците ресурсов, а какие допустимо перезапустить.

Постановка проблемы

В примере под payments требует 2 GiB памяти, но подходящий узел уже занят подами с более низким приоритетом. Простое наличие свободного места на других узлах не гарантирует размещение: они могут не удовлетворять ограничениям по ресурсам, размещению или другим условиям планирования.

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

Подробное решение

Планировщик сначала ищет узлы, на которых под можно разместить без удаления других подов. Если таких узлов нет, он рассматривает preemption: моделирует удаление подов с меньшим приоритетом и проверяет, станет ли узел подходящим.

Вытесняться могут только поды с приоритетом ниже, чем у ожидающего пода. Планировщик выбирает набор жертв с учётом того, насколько малое количество ресурсов нужно освободить и какие дополнительные ограничения требуется сохранить. После принятия решения жертвам отправляется удаление, а новый под может получить узел после фактического освобождения ресурсов.

В конфигурации PriorityClass значение 100000 определяет высокий приоритет. Поле preemptionPolicy: PreemptLowerPriority разрешает вытеснять менее приоритетные поды; при значении Never под сохраняет высокий приоритет при выборе планирования, но сам никого не вытесняет.

Вытеснение не является мгновенным резервированием ресурсов. Удаление пода может занимать время из-за terminationGracePeriodSeconds, финализаторов или зависших процессов. Поэтому критичный под некоторое время всё равно может оставаться в состоянии Pending.

PodDisruptionBudget учитывается планировщиком как ограничение, которого желательно не нарушать при выборе жертв, но он не является абсолютной гарантией неприкосновенности пода при всех видах вытеснения. Кроме того, слишком агрессивные приоритеты могут привести к постоянной борьбе нагрузок за ресурсы и нестабильности менее приоритетных сервисов.

apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: batch value: 100 preemptionPolicy: Never --- apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: critical value: 100000 preemptionPolicy: PreemptLowerPriority

Здесь задания класса batch имеют приоритет, но не вытесняют другие поды. Под класса critical может вытеснить поды с меньшим приоритетом, если это необходимо для его размещения.

Ситуация из практики

В кластере одновременно запускались платёжный API и ночные аналитические задания. При резком росте трафика новые реплики API не размещались, потому что узлы были заняты аналитикой.

Рассматривались три варианта. Увеличение кластера сохраняло бы все нагрузки, но требовало времени и дополнительных расходов. Ручное удаление аналитических подов быстро освобождало бы ресурсы, но было бы ненадёжным и зависело бы от реакции оператора. Одинаковый приоритет для всех подов не давал бы системе формального способа выбрать жертву.

Выбрали PriorityClass: API получил высокий приоритет, аналитика — низкий, а для некоторых фоновых заданий установили preemptionPolicy: Never. В результате при дефиците ресурсов планировщик мог вытеснять часть аналитики, а после завершения пикового периода аналитические задания запускались заново.

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

Что кандидаты часто упускают

1. Может ли под с высоким приоритетом вытеснить под с таким же приоритетом?

Нет. При обычной политике PreemptLowerPriority жертвами рассматриваются поды только с более низким приоритетом. Равенство приоритета не даёт права вытеснения, поэтому высокое значение должно быть согласовано между командами и не назначаться всем критичным нагрузкам без необходимости.

2. Гарантирует ли PriorityClass немедленный запуск пода?

Нет. Приоритет влияет на выбор кандидатов и возможность вытеснения, но не отменяет остальные условия планирования. Под всё равно может остаться в Pending, если не хватает ресурсов даже после вытеснения, нарушены требования nodeSelector, affinity, taints или ограничения томов.

3. Чем вытеснение отличается от обычного удаления пода при масштабировании?

Вытеснение — это решение планировщика, принятое для размещения другого пода с более высоким приоритетом. Обычное масштабирование изменяет желаемое число реплик контроллера, а вытеснение не меняет напрямую это число: контроллер жертвы обычно создаёт замену, если её спецификация всё ещё требует прежнее количество реплик.