← Kubernetes: планирование
5 мин · средне · Урок 7 из 7

PodDisruptionBudget: защита от drain

Чем контролируемое выселение отличается от аварийного, как minAvailable и maxUnavailable останавливают kubectl drain.

Контролируемые и неконтролируемые выселения

Pod - наименьшая единица, которую запускает Kubernetes. Pod могут исчезнуть по двум разным причинам.

Неконтролируемое выселение (involuntary). Узел отключился, OOM-killer убил процесс, узел потерял связь с кластером. Здесь Kubernetes ничего не гарантирует.

Контролируемое выселение (voluntary). Кто-то осознанно убирает Pod. Например, kubectl drain выводит узел на обслуживание и выселяет с него все Pod. Такие операции идут через API eviction - запрос к Kubernetes на удаление Pod.

PDB работает только на этой половине. Упавший узел не спрашивает разрешения, и никакой бюджет его не остановит.

Что делает PodDisruptionBudget

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

Ready это состояние Pod, в котором он готов принимать трафик. Если выселение нарушит бюджет, API возвращает ошибку, и kubectl drain ждёт, повторяя попытку.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: api

Этот PDB требует минимум 2 Pod с меткой app: api в состоянии Ready. Если их три, выселить можно одного. Если их два, выселение блокируется.

minAvailable: 2
  Ready ●●●  →  выселить можно 1
  Ready ●●   →  drain заблокирован

selector выбирает Pod по меткам. Он должен совпадать с метками, которые проставляет Deployment. Если selector не совпадает ни с одним Pod, PDB существует, но ничего не защищает.

minAvailable и maxUnavailable

Бюджет задают одним из двух полей.

spec:
  minAvailable: 2     # минимум 2 Pod в Ready
spec:
  maxUnavailable: 1   # максимум 1 под не Ready одновременно

Значение задают числом или процентом, например "50%". В одном PDB используют либо minAvailable, либо maxUnavailable, но не оба сразу.

Если minAvailable равен числу реплик, выселить нельзя ни один Pod. Сервис «защищён», но обслуживание узла невозможно. Для трёх реплик ставят minAvailable: 2, тогда можно выселить один Pod из трёх.

Как читать состояние

$ kubectl get pdb api-pdb
NAME      MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
api-pdb   2               N/A               1                     30s

ALLOWED DISRUPTIONS показывает, сколько Pod можно выселить прямо сейчас. При трёх Ready и minAvailable: 2 это число равно 1. Если оно 0, выселение заблокировано.

$ kubectl describe pdb api-pdb
...
Status:
  Allowed disruptions:    1
  Current:                3
  Desired:                2
  Expected:               3

Current healthy показывает, сколько Pod сейчас в Ready. Desired healthy показывает, сколько требует бюджет.

Как PDB ведёт себя при drain

Для kubectl drain нужны права на ноды, поэтому запускает его обычно администратор кластера. drain сначала помечает узел как закрытый для новых Pod (cordon), затем выселяет существующие. PDB заставит drain застрять на последнем разрешённом Pod. После обслуживания узел возвращают в работу командой kubectl uncordon <node>, иначе новые Pod не смогут на него попасть. Вот как это выглядит:

$ kubectl drain node-2 --ignore-daemonsets --delete-emptydir-data
node/node-2 cordoned
evicting pod prod/api-7d4f-aaa
error when evicting pods/"api-7d4f-aaa" -n "prod"
  (will retry after 5s): Cannot evict pod as it would violate the
  pod's disruption budget.
evicting pod prod/api-7d4f-aaa
... (зависает в этом цикле)

Домашка

Теорию закрепляет задание на своём кластере: 1 шаг с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.

./run.sh start k8s-pdb     # развернуть стартовое состояние
./run.sh verify k8s-pdb    # проверить текущий шаг

Коротко

Прошли материал до конца? Отметьте урок пройденным.