Обслуживание узлов Kubernetes: cordon и drain

Быстрые ссылки
- Применение cordon к узлу
- Выполнение drain на узле
- Принудительное завершение Pod без grace period
- Решение типичных ошибок drain
- Минимизация простоя с помощью Pod Disruption Budgets
- Повторное включение узлов в кластер
- Краткое резюме
Краткие определения
- cordon — отметить узел как «недоступный для планировщика», чтобы на него не попадали новые Pod.
- drain — эвакуировать (evict) текущие Pod с узла, чтобы освободить его для отключения или удаления.
Важно: cordon не завершает запущенные Pod; он только блокирует новые.
Применение cordon к узлу
Cordoning помечает узел как непригодный для новых размещений. Команда:
kubectl cordon Пример:
$ kubectl cordon node-1
node/node-1 cordonedПроверка статуса узлов:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
node-1 Ready,SchedulingDisabled control-plane,master 26m v1.23.3Узлы с пометкой SchedulingDisabled не принимают новых Pod.
Выполнение drain на узле
Drain инициирует процедуру эвакуации Pod с указанного узла. Он сначала ставит cordon (если вы этого не сделали вручную), затем пытается безопасно завершить Pod и дать им возможность корректно завершиться перед удалением.
Запуск drain:
$ kubectl drain node-1Пример вывода:
node/node-1 already cordoned
evicting pod kube-system/storage-provisioner
evicting pod default/nginx-7c658794b9-zszdd
evicting pod kube-system/coredns-64897985d-dp6lx
pod/storage-provisioner evicted
pod/nginx-7c658794b9-zszdd evicted
pod/coredns-64897985d-dp6lx evicted
node/node-1 evictedПосле успешного drain вы можете безопасно выключать или удалять узел.
Примечание: drain не завершит Pod, защищённых PodDisruptionBudget без явного разрешения.
Принудительное завершение Pod: игнорирование grace periods
Если Pod имеют длинный grace period и вам нужно срочно вывести узел, используйте флаг --grace-period:
$ kubectl drain node-1 --grace-period 0Важно: это принудительно остановит контейнеры без времени на очищающие операции. Используйте с осторожностью.
Решение типичных ошибок drain
Ниже — два распространённых сценария и способы их решения.
Нельзя удалить Pod, не управляемые контроллером
Ошибка появляется, если на узле есть «голые» Pod — созданные вручную и не принадлежащие Deployment/ReplicaSet/StatefulSet/Job. Kubernetes не может автоматически пересоздать такие Pod на других узлах.
Варианты решения:
- Перевести Pod под управление контроллера (создать Deployment/ReplicaSet).
- Удалить Pod вручную и затем выполнить drain.
- Если вы понимаете риски, можно применить
--force:
$ kubectl drain node-1 --force--force удалит «голые» Pod, делая их недоступными.
Нельзя удалить Pod, управляемые DaemonSet
DaemonSet создаёт Pod на каждом узле и игнорирует SchedulingDisabled. При удалении такой Pod он сразу пересоздаётся на том же узле — поэтому drain завершится с ошибкой.
Решение: пропустить DaemonSet’ы при эвакуации:
$ kubectl drain node-1 --ignore-daemonsetsДаже системные компоненты в kube-system часто используют DaemonSet, поэтому флаг может понадобиться, даже если вы их явно не создавали.
Минимизация простоя: Pod Disruption Budgets (PDB)
Pod Disruption Budget — объект, который ограничивает количество одновременно недоступных Pod для набора ресурсов (Deployment, ReplicaSet, StatefulSet и т.д.).
Принцип: PDB гарантирует, что будет доступно минимальное количество Pod (или не более определённого процента будет недоступно) во время планируемых прерываний.
Пример YAML PDB:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: demo-pdb
spec:
minAvailable: 4
selector:
matchLabels:
app: my-appЭта политика требует минимум 4 запущенных Pod с меткой app=my-app. Drain, который приведёт к меньшему числу доступных Pod, будет заблокирован.
Параметры:
minAvailable: 4— требовать как минимум 4 Pod.maxUnavailable: 50%— разрешить до 50% Pod быть недоступными.
Только одно поле (minAvailable или maxUnavailable) может присутствовать.
Пересечение с drain: как обходить PDB
Если нужно немедленно вывести узел, можно обойти механизм эвакуации и напрямую удалять Pod:
$ kubectl drain node-1 --disable-evictionЭто удалит Pod, игнорируя PDB. Используйте только в крайних случаях.
Повторное включение узла в кластер
После завершения обслуживания включите или перезагрузите узел и снимите cordon:
$ kubectl uncordon node-1
node/node-1 uncordonedПосле uncordon планировщик начнёт назначать на узел новые Pod.
Когда cordon+drain не сработают: типичные сценарии отказа
- Недостаточно резерва в кластере: нет свободных ресурсов для переселения Pod.
- “Голые” Pod без контроллера — они исчезнут при
--forceи не восстановятся. - Неправильно настроенные PDB блокируют планирование при массовых drain.
- Стейтфулные приложения (StatefulSet) требуют специальных шагов для сохранения порядка и данных.
Контрпример: в кластере с тремя узлами и Deployment, где реплик ровно 3, drain одного узла может нарушить доступность, если PDB требует minAvailable:3.
Альтернативные подходы
- Горизонтальное масштабирование кластера перед обслуживанием: добавить узел, дать кластерам перераспределиться, затем drain и удалить.
- Использовать Rolling Update на уровне инфраструктуры (например, провайдерские инструменты), чтобы постепенно заменять узлы без одновременной потери вместимости.
- Для критичных сервисов применять multi-zone/region кластеры.
Ментальные модели и эвристики
- Модель “места и вместимости”: представьте, что все Pod — это чемоданы, а узлы — полки. Cordoning закрывает полку для новых чемоданов, drain аккуратно перекладывает чемоданы на другие полки.
- Эвристика SRE: никогда не выводите более 10–20% узлов одновременно без проверки доступных ресурсов и PDB.
Быстрый набор команд (cheat sheet)
kubectl cordon NODE # заблокировать узел для новых Pod
kubectl drain NODE # эвакуировать Pod c NODE
kubectl drain NODE --ignore-daemonsets
kubectl drain NODE --force # удалить "голые" Pod
kubectl drain NODE --grace-period 0 # форсированное завершение
kubectl drain NODE --disable-eviction# обойти PDB
kubectl uncordon NODE # вернуть узел в планирование
kubectl get pods -o wide --all-namespaces
kubectl get pdb # список Pod Disruption Budgets
kubectl describe node NODE # данные по узлуРоли и чек-листы
Оператор (инженер поддержки):
- Проверить свободную ёмкость кластера (CPU, RAM, диски).
- Найти зависимости (PDB, StatefulSet, DaemonSet).
- Запланировать maintenance window.
- Выполнить cordon → drain → выключение → uncordon.
Разработчик приложения:
- Убедиться, что Pod управляются контроллером (Deployment/StatefulSet).
- Настроить корректный readinessProbe и livenessProbe.
- Определить адекватный terminationGracePeriodSeconds.
SRE/руководитель смены:
- Проверить PDB для критичных сервисов.
- Координировать одновременные drains между зонами.
- Иметь план отката в случае проблем.
Процедура (SOP) — быстрый playbook
- Оповестить потребителей и команду (maintenance window).
- Проверить метрики кластера и available resources.
- Запустить
kubectl cordon NODE. - Запустить
kubectl drain NODE(или с флагами при необходимости). - Наблюдать за статусом Pod и Logs.
- Выполнить аппаратное обслуживание/обновление.
- Перезапустить узел и
kubectl uncordon NODE. - Проверить, что Pod успешно запустились и метрики в норме.
Критерии приёмки
- Узел снят с обслуживания и снова возвращён в пул.
- Все Pod целевых приложений восстановлены и в состоянии Ready.
- Нет нарушений PDB (кроме тех случаев, где отключение было согласовано).
- Латентность и ошибки приложения возвращены к предвиденным уровням.
Тестовые случаи / критерии приёмки
- Drain узла с Deployment (3 реплики) при наличии свободного места на других узлах — все Pod перезапускаются и доступны.
- Drain узла с “голыми” Pod без
--force— drain должен завершиться с ошибкой. - Drain узла с DaemonSet — при отсутствии
--ignore-daemonsetsоперация должна предупредить. - Принудительный drain с
--grace-period 0— Pod завершаются немедленно; приложение может потерять незавершённые транзакции (ожидаемое поведение).
Диаграмма принятия решения (Mermaid)
flowchart TD
A[Начало обслуживания узла] --> B{Доступно ли место в кластере?}
B -- Да --> C[cordon]
B -- Нет --> D[Добавить узел или перенести нагрузку]
C --> E{Есть ли Pod без контроллера?}
E -- Да --> F[Перевести под контроллер или использовать --force]
E -- Нет --> G{DaemonSet есть?}
G -- Да --> H[Добавить --ignore-daemonsets]
G -- Нет --> I[drain]
I --> J[Отключить/обслужить узел]
J --> K[uncordon и проверка]
F --> I
H --> IФакты и подсказки
- Cordoning — быстрый и безопасный шаг; он не прерывает трафик.
- Drain может заблокироваться PDB, проверьте их заранее.
- Stateful приложения требуют дополнительной осторожности (например, порядок остановки, сохранение состояний).
Безопасность и приватность
- Убедитесь, что учетные записи и права (RBAC) соответствуют политикам безопасности: команды
kubectl drain/cordonтребуют соответствующих разрешений. - При использовании облачных API для удаления узлов не храните секреты в явном виде.
Локальные особенности и советы для разных провайдеров
- В облаке: сначала масштабируйте группу узлов, дождитесь присоединения новых нод, затем drain.
- На bare-metal: подготовьте план отказоустойчивости сети и хранение данных (SAN/NFS) перед выключением узла.
Резюме
Cordons и drains — стандартный и безопасный путь подготовки узла Kubernetes к обслуживанию. Cordons запрещают новые планирования, drain аккуратно переселяет Pod. В критичных системах сочетайте эти команды с Pod Disruption Budgets и тестами, чтобы избежать неожиданного простоя. Планируйте действия, соблюдайте роли и следуйте playbook, чтобы выполнение обслуживания было повторяемым и безопасным.
Важно: всегда тестируйте процедуру на стенде, прежде чем выполнять в production.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента