Сбои Pod'ов

Добровольные и недобровольные сбои Pod'ов

Pod'ы не исчезают до тех пор, пока кто-либо (человек или контроллер) не уничтожит их или не произойдет неизбежная ошибка аппаратного или системного программного обеспечения.

Такие неизбежные случаи называют недобровольными сбоями. Примеры:

  • аппаратный сбой физической машины, поддерживающей узел
  • администратор кластера по ошибке удаляет VM (виртуальную машину) (экземпляр)
  • ошибка облачного провайдера или гипервизора приводит к исчезновению виртуальной машины
  • паника ядра
  • узел исчезает из кластера из-за сетевого раздела кластера
  • выселение Pod'а из-за нехватки ресурсов у узла

За исключением условия нехватки ресурсов, все эти условия должны быть знакомы большинству пользователей; они не являются специфическими для Kubernetes.

Другие случаи называют добровольными сбоями. К ним относятся как действия, инициированные владельцем приложения, так и действия, инициированные администратором кластера. Типичные действия владельца приложения включают в себя:

  • удаление развертывания (deployment) или другого контроллера, который управляет Pod'ом
  • обновление шаблона развертывания Pod'а, вызывающее перезапуск
  • прямое удаление Pod'а (например, случайно)

К действиям администратора кластера относятся:

  • Освобождение (draining) узла для ремонта или обновления.
  • Перетаскивание узла из кластера для его уменьшения.
  • Извлечение Pod'а из узла, чтобы на нем можно было разместить что-то еще.

Эти действия могут быть предприняты непосредственно администратором кластера, либо автоматизацией, запущенной администратором кластера, или вашим поставщиком хостинга кластера.

Обработка сбоев

Вот несколько способов смягчить недобровольные сбои:

  • Убедитесь, что ваш Pod запрашивает ресурсы, которые ему нужны.
  • Увеличьте количество экземпляров вашего приложения (реплицируйте ваше приложение), если вам нужна более высокая доступность.
  • Для еще большей доступности при запуске реплицированных приложений распределите приложения по стойкам (racks) (используя анти-сходство) или по зонам (если используется многозонный кластер).

Частота добровольных сбоев варьируется. На базовом кластере Kubernetes нет никаких добровольных сбоев вообще. Однако администратор вашего кластера или хостинг-провайдер может запускать некоторые дополнительные службы, которые вызывают добровольные сбои. Например, развертывание обновлений программного обеспечения узла может привести к добровольным сбоям. Кроме того, некоторые реализации автоматического масштабирования кластера (узла) могут вызывать добровольные сбои при дефрагментации и сжатии узлов. Администратор вашего кластера или хостинг-провайдер должен задокументировать, какой уровень добровольных сбоев следует ожидать.

Kubernetes предлагает функции, которые помогают запускать приложения высокой доступности одновременно с частыми добровольными сбоями. Это называют набором функций бюджетов нарушений (Disruption Budgets).

Как работают бюджеты нарушений

Владелец приложения может создать объект PodDisruptionBudget (PDB) для каждого приложения. PDB ограничивает количество Pod'ов реплицированного приложения, которые одновременно отключаются из-за добровольных сбоев. Например, приложение, основанное на кворуме, хотело бы убедиться, что число работающих реплик никогда не должно быть меньше числа, необходимого для кворума. Веб-интерфейс может захотеть убедиться, что количество обслуживающих реплик нагрузки никогда не падает ниже определенного процента от общего.

Менеджеры кластеров и хостинг-провайдеры должны использовать инструменты, которые учитывают бюджеты нарушений Pod (Pod Disruption Budgets), вызывая Eviction API (API выселения) вместо непосредственного удаления Pod'ов или развертываний (deployments). Примерами являются команда kubectl drain и сценарий обновления кластера Kubernetes-on-GCE (cluster/gce/upgrade.sh).

Когда администратор кластера хочет удалить узел, он использует команду kubectl drain. Этот инструмент пытается выселить все Pod'ы с машины. Запрос на выселение может быть временно отклонен, и инструмент периодически повторяет все неудавшиеся запросы, пока все Pod'ы не будут завершены или пока не будет достигнут настраиваемый тайм-аут.

PDB определяет количество реплик, которые может выдержать приложение, относительно количества, которое оно должно иметь. Например, в развертывании, которое имеет .spec.replicas: 5, должно быть 5 Pod'ов в любой момент времени. Если его PDB допускает одновременное использование 4, то API Eviction разрешит добровольное прерывание одного, но не двух Pod'ов одновременно.

Группа Pod'ов, составляющих приложение, указывается с помощью селектора меток, такого же, который используется контроллером приложения (deployment, stateful-set и т.д.).

"Предполагаемое" количество Pod'ов рассчитывается из .spec.replicas контроллера pod'ов. Контроллер обнаруживается из Pod'ов посредством использования .metadata.ownerReferences объекта.

PDB не могут предотвратить возникновение недобровольных сбоев, но они учитываются в бюджете.

Pod'ы, которые удалены или недоступны из-за непрерывного обновления приложения, учитываются в бюджете сбоев, но контроллеры (такие как развертывание (deployment) и набор состояний (stateful-set)) не ограничиваются PDB при непрерывном обновлении - настраивается обработка сбоев во время обновлений приложения в спецификации контроллера.

Когда Pod выгружается с помощью API выселения (eviction API), он корректно завершается (TerminationGracePeriodSeconds в PodSpec.)

Пример PDB

Рассмотрим кластер с 3 узлами (nodes), от node-1 до node-3. В кластере запущено несколько приложений. У одного из них есть 3 экземпляра (replicas), которые изначально назывались pod-a, pod-b и pod-c. Другой, несвязанный Pod без PDB, называемый pod-x, также показан. Первоначально, Pod'ы расположены следующим образом:

node-1 node-2 node-3
pod-a available    pod-b available    pod-c available   
pod-x available

Все 3 Pod'а являются частью развертывания (deployment), и вместе они имеют PDB, для которой необходимо, чтобы по крайней мере 2 из 3 Pod'ов были доступны в любое время.

Для примера, предположим, что администратор кластера хочет перезагрузиться с новой версией ядра, чтобы исправить ошибку в ядре. Администратор кластера сначала пытается очистить (drain) node-1 с помощью команды kubectl drain. Этот инструмент пытается выселить pod-a и pod-x. Это удастся немедленно. Оба Pod'а переходят в состояние terminating одновременно. Это переводит кластер в состояние:

node-1 draining node-2 node-3
pod-a terminating    pod-b available    pod-c available   
pod-x terminating

Развертывание (deployment) замечает, что один из Pod'ов завершается (terminating), поэтому оно создает замену с именем pod-d. Поскольку node-1 оцеплен, он приземляется на другом узле. Что-то также создало pod-y как замену pod-x.

(Примечание: для StatefulSet, pod-a, который будет называться чем-то вроде pod-0, должен полностью завершиться, прежде чем его замена, которая также называется pod-0, но имеет другой UID, может быть создана. В противном случае, данный пример относится и к StatefulSet.)

Сейчас кластер находится в этом состоянии:

node-1 draining node-2 node-3
pod-a terminating    pod-b available    pod-c available   
pod-x terminating pod-d starting pod-y

В какой-то момент Pod'ы завершаются (terminate), и кластер выглядит следующим образом:

node-1 draining node-2 node-3
pod-b available    pod-c available   
pod-d starting pod-y

На этом этапе, если нетерпеливый администратор кластера пытается очистить (drain) node-2 или node-3, команда drain будет заблокирована, поскольку для развертывания (deployment) доступно только 2 Pod'а, а для его PDB требуется как минимум 2. Через некоторое время pod-d становится доступным (available).

Состояние кластера теперь выглядит так:

node-1 draining node-2 node-3
pod-b available    pod-c available   
pod-d available pod-y

Теперь администратор кластера пытается очистить (drain) node-2. Команда drain попытается выселить два Pod'а в некотором порядке, скажем, сначала pod-b, а затем pod-d. Это приведет к выселению pod-b. Но когда он попытается высвободить pod-d, ему будет отказано, потому что это оставит только один Pod, доступный для развертывания (deployment).

Развертывание создает замену для pod-b под названием pod-e. Поскольку в кластере недостаточно ресурсов для планирования pod-e, drain снова заблокируется. Кластер может оказаться в этом состоянии:

node-1 draining node-2 node-3 no node
pod-b available    pod-c available    pod-e pending   
pod-d available pod-y

На этом этапе администратор кластера должен добавить узел обратно в кластер, чтобы продолжить обновление.

Вы можете увидеть, как Kubernetes изменяет скорость, с которой могут происходить сбои, в зависимости от:

  • сколько реплик нужно приложению
  • сколько времени нужно, чтобы изящно (gracefully) закрыть экземпляр
  • сколько времени требуется, чтобы запустить новый экземпляр
  • тип контроллера
  • ресурсный потенциал кластера

Разделение ролей владельца кластера и владельца приложения

Часто полезно рассматривать Cluster Manager (менеджер кластера) и Application Owner (владелец приложения) как отдельные роли с ограниченными знаниями друг о друге. Такое разделение обязанностей может иметь смысл в следующих сценариях:

  • когда много групп приложений совместно используют кластер Kubernetes, и существует естественная специализация ролей
  • когда сторонние инструменты или сервисы используются для автоматизации управления кластером

Бюджеты нарушений Pod'а поддерживают это разделение ролей, обеспечивая интерфейс между ролями.

Если у вас нет такого разделения обязанностей в вашей организации, вам, возможно, не нужно использовать Бюджеты нарушений Pod.

Как выполнять действия, вызывающие нарушения Pod'ов, на вашем кластере

Если вы являетесь администратором кластера и вам необходимо выполнить действие, вызывающее нарушения Pod'ов, на всех узлах кластера, например обновить узел или системное программное обеспечение, вот несколько вариантов:

  • Учтите время простоя во время обновления.
  • Аварийное переключение на другой полный кластер реплик.
    • Нет простоев, но может быть дорогостоящим как для дублированных узлов, так и для человеческих усилий по организации переключения.
  • Напишите отказоустойчивые приложения и используйте PDB.
    • Нет простоя.
    • Минимальное дублирование ресурсов.
    • Позволяет в большей мере автоматизировать администрирование кластера.
    • Написание устойчивых к сбоям приложений - сложная задача, но работа по допуску добровольных нарушений во многом пересекается с работой по поддержке автоматического масштабирования и повышению устойчивости к недобровольным нарушениям.

Читайте также:


Комментарии

Популярные сообщения из этого блога

Контроллеры в Kubernetes: DaemonSet

Контроллеры в Kubernetes: ReplicaSet

Контроллеры в Kubernetes: StatefulSet