Привет, Хабр! Вы когда‑нибудь обновляли ноду Kubernetes‑кластера и замечали, как несколько ваших подов сразу пропали в процессе? Не самое приятное ощущение, верно?

Запускаете плановое обновление, kubectl drain начинает выгонять поды с ноды, и вдруг сервис теряет половину реплик. Клиенты начинают получать ошибки. Что пошло не так? Вы забыли про PodDisruptionBudget.

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

Как этим пользоваться

PDB настраивается как привычный YAML манифест вида PodDisruptionBudget и живёт в policy/v1 API. В PDB мы указываем селектор на наши поды и один из двух параметров: либо minAvailable, либо maxUnavailable. Первый задаёт минимальное число подов, которые должны остаться живы, а второй максимальное число подов, которые можно одновременно положить. Оба параметра взаимоисключающие, в одном PDB вы используете что‑то одно.

Допустим, есть Deployment из 5 реплик фронтенда. Хотим, чтобы при обновлении ноды минимум 4 из 5 подов оставались работоспособными. Для этого зададим minAvailable: 4.

Пример PDB‑манифеста:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: frontend-pdb
spec:
  minAvailable: 4
  selector:
    matchLabels:
      app: my-frontend

Просим Kubernetes оставить хотя бы 4 пода с меткой app: my‑frontend в рабочем состоянии. Если действительно запущено 5 подов, то разрешён только 1 одновременный эвикшн, disruptionsAllowed будет равен 1. Kubernetes, точнее контроллер PDB, рассчитает это автоматически. Проверить можно командой:

$ kubectl get poddisruptionbudget frontend-pdb
NAME           MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
frontend-pdb   4               N/A               1                     30s

В поле ALLOWED DISRUPTIONS видно сколько подов сейчас можно выселить не нарушив бюджет. Если там 0, всё, лимит исчерпан, дополнительные поды трогать нельзя, пока уже удалённые не восстановятся. В нашем случае 1 значит, что один под можно спокойно убить (Kubernetes потом поднимет новый на другой ноде), а вот второй уже не тронет, пока первый не будет в состоянии Ready на новом месте.

Альтернатива вышеописанному — использовать maxUnavailable. Например, для того же случая из 5 реплик эквивалентно поставить maxUnavailable: 1 (не больше одного пода недоступно). Результат будет тот же. Более того, maxUnavailable часто предпочтительнее, потому что автоматически подстраивается под масштаб приложения.

Если вы увеличите реплики до 10, то maxUnavailable: 1 всё так же позволит терять только один под, а minAvailable: 4 уже будет означать, что можно убить 6 подов (оставив 4) — вероятно не то, что вы хотели. С maxUnavailable подобной ловушки нет, вы явно указываете терпимый дефицит подов. Можно задавать и в процентах, например maxUnavailable: 30% для гибкости. Kubernetes при этом округляет значения в большую сторону до целого пода.

Рассмотрим разные сценарии.

Если у нас стателес‑сервис с 10 репликами, типичная политика — не больше 20% одновременно недоступно. Значит maxUnavailable: "20%". Для критичного stateful‑сервиса (база, kafka, etcd) важно не терять кворум. Кластер из 5 нод etcd: кворум 3. Тогда можно сделать maxUnavailable: 1, не больше одного узла разом в офлайне, иначе рискуем. Либо эквивалент minAvailable: 4 (оставить минимум 4 из 5). Принцип один: оцените, сколько простоя вы переживёте без проблем, и оформите это правилом в PDB.

Отдельный случай — единственный под. Например, у вас маленький сервис в одной реплике. Хотите ли вы защитить его PDB? Казалось бы, поставим minAvailable: 1 (то есть всегда оставлять 1 под) и всё. Но тут нюанс, при таком PDB Kubernetes вообще не сможет перезапустить этот под без нарушения бюджета. Команда kubectl drain просто зависнет, отказываясь убивать последнюю реплику. Это фактически блокирует любые плановые работы, ведь ноду не перегрузить, Deployment не обновить, пока вы вручную не снимете PDB. Поэтому для одиночек обычно не вводят PDB. Либо, если уж нужно, ставят maxUnavailable: 0 (что то же самое) и договариваются с администраторами кластера: мол, прежде чем обновлять, позвоните, мы подготовимся.

Стоит упомянуть ещё несколько тонкостей.

PDB учитывает только поды в состоянии Ready. Если под не готов, то формально он уже не считается живым для бюджета. Однако до недавнего времени Kubernetes не позволял удалять неуспешный под, если тем самым здоровых подов станет меньше требуемого. Получалась неприятная ситуация, приложение и так не работает, а ноду всё равно не освободить из‑за PDB.

В свежих версиях Kubernetes ввели настройку unhealthyPodEvictionPolicy. По дефолту действует политика IfHealthyBudget,то самое классическое поведение, когда проблемные поды защищены, если система уже на минимуме. Но теперь можно переключить на AlwaysAllow, чтобы эвиктить даже нездоровые поды невзирая на бюджет. Это на случай, когда хочется поскорее избавиться от зависших или крашнутых экземпляров, не блокируя, скажем, drain узла.

Лучшие практики по использованию PDB довольно просты. Каждому важному Deploymen — свой PDB. Не ленитесь прописать бюджеты для всех сервисов, требующих высокой доступности. Следите, чтобы ваши селекторы в PDB точно совпадали с метками на подах (иначе PDB просто никого не найдет и бесполезен). И задавайте реалистичные значения, слишком мягкий PDB бессмыслен, а чрезмерно жёсткий мешает админам. Например, minAvailable: 100% на большой сервис звучит благородно, но фактически вы объявляете, что нельзя трогать ни один под вообще. Кластер с таким не поздоровится, ни обновить, ни пересоздать, пока вручную не уберёте ограничение. Так что не перегибайте палку.

Правильно настроив PDB, Kubernetes будет соблюдать границы, которые вы указали.


PodDisruptionBudget — лишь один из кирпичей платформенного подхода в Kubernetes. В курсе «Инфраструктурная платформа на основе Kubernetes» показывают, как из таких механизмов собрать рабочую платформу: эксплуатация кластеров, IaC, устойчивость сервисов и стандартизация жизненного цикла без «ручной магии». Пройдите вступительный тест, чтобы узнать, подойдет ли вам программа курса.

Для знакомства с форматом обучения и экспертами приходите на бесплатные демо-уроки:

  • 14 января, 20:00. «IaC: Тестирование инфраструктуры — как внедрить инженерные практики и перестать бояться изменений». Записаться

  • 21 января, 20:00. «Мониторинг: как понять, что твой сервис болен». Записаться

  • 22 января, 19:00. «eBPF: рентгеновское зрение для production. Видим сеть, безопасность и узкие места на уровне ядра Linux». Записаться

Комментарии (0)