ZIM-НИЙ SAAALEЗимние скидки: до −50% на старт и −20% на продление
до 31.01.2026 Подробнее
Выберите продукт

Kubernetes PodDisruptionBudget: обслуживание нод без сюрпризов

PodDisruptionBudget в Kubernetes помогает переживать плановые прерывания без падений сервиса, но при ошибочной настройке легко блокирует kubectl drain. Разбираем minAvailable/maxUnavailable, Allowed disruptions, YAML-шаблоны, диагностику причин и чек-лист для maintenance window.
Kubernetes PodDisruptionBudget: обслуживание нод без сюрпризов

Когда вы заходите в плановое обслуживание кластера Kubernetes (апгрейд нод, замена дисков, обновление ОС, работы у провайдера), чаще всего вы делаете одно и то же: kubectl drain и ждёте, пока поды переедут. И вот здесь внезапно выясняется: часть подов не уезжает, дрен «висит», а maintenance window не резиновое.

В центре этой истории обычно PodDisruptionBudget (он же poddisruptionbudget, сокращённо kubernetes pdb). PDB — это контракт между владельцем приложения и оператором кластера: «вот сколько реплик можно потерять при плановых (voluntary) прерываниях». С одной стороны, он защищает сервис от того, что вы случайно выдавите сразу слишком много реплик. С другой — если PDB настроен неправильно или приложение не готово к эвикшенам, он же и блокирует обслуживание.

Ниже — практичная памятка, как работать с disruption budget так, чтобы и сервис жил, и drain node не превращался в лотерею.

Что такое PDB и какие прерывания он контролирует

PodDisruptionBudget ограничивает количество подов, которые можно добровольно выселить одновременно. К voluntary disruptions относятся операции, которые инициирует человек или контроллер, соблюдающий eviction API: kubectl drain, вывод ноды из эксплуатации, а также часть сценариев кластерной автоматики (в зависимости от версии Kubernetes и конкретной реализации).

Важно: PDB не защищает от недобровольных (involuntary) событий: падение ноды, OOMKill, kernel panic, потеря сети или диска. То есть PDB — это инструмент именно для безопасного обслуживания и управляемых изменений, а не «серебряная пуля» от аварий.

Ментальная модель: PDB — это «сколько можно добровольно выселить сейчас», а не «сколько должно работать всегда».

minAvailable vs maxUnavailable

PDB задаётся одним из двух способов:

  • minAvailable — минимальное число (или процент) подов, которые должны оставаться доступными.
  • maxUnavailable — максимальное число (или процент) подов, которые могут быть недоступны.

Указывать оба нельзя. На практике maxUnavailable часто понятнее операторам: «можно потерять не больше N». minAvailable удобен, когда вы мыслите «должно оставаться не меньше N».

Как PDB влияет на kubectl drain и почему нода может не дрениться

Команда kubectl drain выполняет выселение подов через eviction API. Kubernetes проверяет PDB для каждого пода и решает: можно ли «прервать» его прямо сейчас, не нарушив disruption budget.

Типичные причины, почему drain node упирается:

  • Слишком строгий PDB для малого числа реплик. Например, 2 реплики и minAvailable: 2 — вы запретили любые эвикшены.
  • Нехватка ресурсов на остальных нодах: поды физически некуда переселить. PDB тут ни при чём, но по симптомам выглядит как «дрен не заканчивается».
  • Под не становится Ready после пересоздания (пробы, зависимости, миграции), поэтому доступных реплик становится меньше, и PDB начинает блокировать следующие эвикшены.
  • Мало реплик или singleton (1 реплика) при minAvailable: 1 или maxUnavailable: 0 — вы сделали «нулевой бюджет».
  • Неправильный selector в PDB: он матчится не на те поды или не матчится вообще, и ожидания не совпадают с реальностью.

Быстрая диагностика: что именно блокирует эвикшены

Начинайте с проверки статуса PDB и текущего «бюджета»:

kubectl get pdb -A
kubectl describe pdb -n my-ns my-app-pdb

В kubectl describe важны поля:

  • Allowed disruptions — сколько подов можно выселить прямо сейчас.
  • Current healthy и Desired healthy — сколько подов считается здоровыми и сколько должно оставаться.

Если Allowed disruptions равен 0, kubectl drain будет ждать (или падать ошибкой эвикшена), пока не появится доступный «бюджет».

Если вам удобнее тестировать сценарии обслуживания на отдельном стенде, поднимайте кластер на VDS: так проще воспроизвести влияние PDB на drain и оценить реальный запас по ресурсам.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Практика: примеры PodDisruptionBudget для типовых приложений

Ниже — несколько рабочих шаблонов, от которых удобно отталкиваться. В примерах используем maxUnavailable, потому что в эксплуатации проще считать «сколько можно потерять».

Диагностика PodDisruptionBudget: текущие healthy-поды и Allowed disruptions

Стандартный stateless deployment: можно потерять 1 реплику

Подходит для веба/API за балансировщиком, где реплик 2+ и нет жёсткой привязки к конкретной ноде.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: my-app-pdb
  namespace: my-ns
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app: my-app

Если у вас 3 реплики, то одновременно можно добровольно «уронить» 1. Это обычно достаточно, чтобы безопасно дренить ноды по одной.

Две реплики и строгая доступность: оставляем минимум одну

Если реплик всего 2, то maxUnavailable: 1 всё ещё ок: можно выселить одну реплику, вторая продолжит обслуживать.

Опасная зона: maxUnavailable: 0 или minAvailable: 2 при двух репликах. Такое уместно только если вы никогда не хотите voluntary disruptions и готовы обслуживать иначе (например, через отдельный механизм миграции или временное масштабирование).

Процентный budget для больших пулов

Для 20–200 реплик удобно задавать проценты, чтобы правила масштабировались вместе с нагрузкой:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: workers-pdb
  namespace: my-ns
spec:
  maxUnavailable: 10%
  selector:
    matchLabels:
      app: workers

Тут есть нюанс: проценты округляются, и на малых числах реплик поведение может отличаться от ожиданий. Если реплик мало (например, 3–5), проценты лучше не использовать — берите абсолютные значения.

Singleton (1 реплика): что делать, если нужен maintenance

Если приложение в 1 реплику и вы поставите maxUnavailable: 0, вы запретите его выселять через eviction. На плановом обслуживании это означает: нода с этим подом не дренится.

Рабочие варианты:

  • На время обслуживания временно масштабировать Deployment до 2 реплик и иметь PDB, допускающий потерю одной реплики.
  • Перевести компонент в HA (2+ реплики) и закрепить это PDB.
  • Если это stateful и одиночный мастер — проработать архитектуру (репликация, failover), потому что PDB проблему не решит.

Maintenance window: как планировать обслуживание с учётом PDB

Правильно настроенный disruption budget — это не только про безопасность, но и про предсказуемость. Чтобы maintenance window не «съедался» ожиданиями, продумайте процесс.

Чек-лист перед обслуживанием

  • Проверьте, что у ключевых workloads есть PDB, и он соответствует реальной стратегии доступности.
  • Убедитесь, что есть запас по ресурсам: если вы выведете одну ноду, оставшиеся должны «переварить» переселение.
  • Проверьте, что Pod anti-affinity и topologySpreadConstraints не делают переселение невозможным при уменьшении числа нод.
  • Прогоните «сухой» сценарий: сможете ли вы дренить хотя бы одну ноду без ручных вмешательств.

Типовой порядок действий: cordon → drain → работы → uncordon

Минимальный безопасный сценарий обслуживания ноды:

kubectl cordon node-1
kubectl drain node-1 --ignore-daemonsets --delete-emptydir-data
kubectl uncordon node-1

Параметр --delete-emptydir-data удаляет данные emptyDir при выселении. Это удобно, но опасно для подов, которые (ошибочно) хранят там важное. Если не уверены — сначала найдите такие поды.

Почему drain может быть «долгим» даже при нормальном PDB

PDB отвечает только за «можно ли выселить». А «когда под станет Ready на новой ноде» — это уже про ваше приложение и инфраструктуру. Частые источники задержек:

  • долгий старт приложения (миграции, прогрев кэша);
  • строгие readinessProbe, которые не проходят до прогрева;
  • узкие места по сети/диску при массовом пересоздании подов;
  • подвисшие завершения из-за длинного terminationGracePeriodSeconds и отсутствия корректного graceful shutdown.

Если вы хотите «упаковать» обслуживание в окно, ускорение обычно даёт не изменение PDB, а оптимизация старта и остановки плюс достаточный резерв ресурсов.

Связанный практический кейс на уровне приложений: если у вас PHP-сервисы, их «долгий stop/start» часто выявляется через slowlog и тайминги воркеров; пригодится разбор PHP-FPM slowlog: как читать и применять в эксплуатации.

Если вместе с обслуживанием вы подтягиваете безопасность (например, закрываете техдолг по TLS), держите под рукой актуальные SSL-сертификаты: так проще планировать замену сертификатов в то же окно, не размазывая изменения по нескольким релизам.

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Частые ошибки в PodDisruptionBudget и как их исправлять

Ошибка 1: PDB есть, но selector не совпадает с реальными pod labels

Симптом: PDB «не работает» (или работает для других подов). Проверка:

kubectl get pod -n my-ns --show-labels
kubectl get pdb -n my-ns -o yaml

Убедитесь, что spec.selector.matchLabels точно соответствует меткам подов. Для сложных селекторов используйте matchExpressions, но держите их простыми: чем проще selector, тем меньше сюрпризов на обслуживании.

Ошибка 2: «нулевой бюджет» там, где нужно обслуживать

Симптом: Allowed disruptions: 0 всегда, даже когда всё здорово. Частая причина — minAvailable равен числу реплик или maxUnavailable: 0 на stateless сервисе.

Исправление: либо увеличьте число реплик, либо разрешите хотя бы один voluntary eviction. В идеале — оба варианта.

Ошибка 3: PDB конфликтует с реальной доступностью приложения

PDB считает «healthy» поды через готовность (readiness) и условия доступности контроллера. Если ваш readinessProbe слишком оптимистичный или, наоборот, слишком строгий, расчёт бюджета будет не отражать реальную картину.

Практический подход: сначала стабилизируйте жизненный цикл пода (startup/readiness/liveness, graceful shutdown), а уже потом «зажимайте» PDB. Иначе вы получите ложные блокировки на ровном месте.

Как сочетать PDB с кластерной автоматикой и обновлениями

PDB часто воспринимают как «препятствие» автоматизации, но на самом деле это механизм согласования. Если у вас есть автоскейлинг нод, автоматические обновления, ручные работы — PDB помогает всем участникам не вырубить сервис.

Рекомендации для эксплуатации:

  • Для критичных stateless сервисов держите 3+ реплики и maxUnavailable: 1 (или 10% на больших пулах).
  • Для системных компонентов и ingress-контроллеров также задавайте PDB, иначе обслуживание нод может «съесть» сразу несколько экземпляров.
  • Если есть строгие требования к доступности, используйте не только PDB, но и распределение подов по нодам и зонам (anti-affinity/spread) плюс резерв мощности.

Схема процесса обслуживания ноды: cordon, drain, работы и uncordon

Шпаргалка: быстрые команды для проверки перед maintenance

kubectl get pdb -A
kubectl describe pdb -n my-ns my-app-pdb
kubectl get pod -A -o wide --field-selector spec.nodeName=node-1
kubectl cordon node-1
kubectl drain node-1 --ignore-daemonsets --delete-emptydir-data

Итог: как сделать PDB союзником, а не блокером

PodDisruptionBudget — это инструмент дисциплины. Он заставляет заранее ответить на вопросы: «сколько реплик должно пережить обслуживание», «что будет, если одну ноду вывести», «есть ли у нас запас мощности».

Чтобы maintenance window проходило спокойно:

  • не делайте «нулевой» disruption budget для сервисов, которые нужно обслуживать;
  • держите достаточное число реплик и резерв ресурсов;
  • перед обслуживанием смотрите Allowed disruptions и устраняйте причины, почему он равен нулю;
  • оптимизируйте readiness и graceful shutdown — это напрямую сокращает время дренов.

С таким подходом poddisruptionbudget перестаёт быть загадочной сущностью из YAML и становится понятным регулятором, который делает drain node предсказуемым и безопасным.

Поделиться статьей

Вам будет интересно

Nginx DNS в Docker/Kubernetes: resolver, valid и ipv6=off без сюрпризов OpenAI Статья написана AI (GPT 5)

Nginx DNS в Docker/Kubernetes: resolver, valid и ipv6=off без сюрпризов

Когда backend в Docker или Kubernetes меняет IP, Nginx может продолжать подключаться к «старому» адресу. Разбираем, как работает D ...
DNSSEC на практике: KSK/ZSK, DS record и безопасный rollover без SERVFAIL OpenAI Статья написана AI (GPT 5)

DNSSEC на практике: KSK/ZSK, DS record и безопасный rollover без SERVFAIL

Разбираем DNSSEC на практике: как устроены KSK/ZSK и DS record, как читать DNSKEY/RRSIG, почему при ошибках появляется SERVFAIL и ...
Linux passthrough (VFIO): включение IOMMU (VT-d/AMD-Vi), проверка и типовые проблемы OpenAI Статья написана AI (GPT 5)

Linux passthrough (VFIO): включение IOMMU (VT-d/AMD-Vi), проверка и типовые проблемы

Практический разбор IOMMU в Linux для PCI passthrough: включаем VT-d/AMD-Vi в BIOS и через grub, проверяем /proc/cmdline и dmesg, ...