Как в Kubernetes обеспечивается грамотное (graceful) завершение работы узла с учетом приоритетов Pod’ов?

«Как в Kubernetes обеспечивается грамотное (graceful) завершение работы узла с учетом приоритетов Pod’ов?» — вопрос из категории Kubernetes, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Грамотное завершение работы узла (Node Drain/Shutdown) с учетом приоритетов обеспечивается совместной работой нескольких механизмов Kubernetes:

  1. Приоритеты и вытеснение (Priority & Preemption): Pod'ам назначается priorityClassName. При нехватке ресурсов на узле (например, во время его осушения) Pod'ы с низким приоритетом завершаются первыми, чтобы освободить место для Pod'ов с высоким приоритетом.

  2. Бюджет нарушений работы Pod'ов (Pod Disruption Budget - PDB): PDB определяет, какое минимальное количество реплик приложения (minAvailable) или максимальное количество реплик, которые могут быть недоступны одновременно (maxUnavailable). Планировщик эвакуации (kubectl drain) соблюдает эти ограничения, завершая Pod'ы постепенно.

  3. Механизм graceful termination самого Pod'а: При эвакуации Pod сначала получает сигнал SIGTERM, может выполнить хук preStop, и только после истечения terminationGracePeriodSeconds (по умолчанию 30с) получает SIGKILL.

Практический пример процесса:

# Команда для администратора, инициирующая эвакуацию узла
kubectl drain my-node --ignore-daemonsets --delete-emptydir-data

При этом:

  • На узле my-node перестают планироваться новые Pod'ы.
  • Сначала эвакуируются Pod'ы без PDB или с наименьшим приоритетом.
  • Для каждого эвакуируемого Pod'а контроллер соблюдает его PDB. Если эвакуация нарушит PDB (например, станет недоступно более maxUnavailable реплик), операция для этого приложения приостанавливается до тех пор, пока не станет доступна другая реплика.
  • Pod'ы с высоким приоритетом и критичные stateful-приложения (базы данных) завершаются в последнюю очередь или не завершаются, если это нарушит PDB.

Пример PriorityClass и PDB:

# PriorityClass
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "Для критичных системных компонентов."
---
# Pod Disruption Budget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: my-app-pdb
spec:
  minAvailable: 2 # Всегда должно быть доступно минимум 2 пода
  selector:
    matchLabels:
      app: my-critical-app