Самовосстановление в Kubernetes: как оркестратор обеспечивает отказоустойчивость приложений | AdminWiki

Самовосстановление в Kubernetes: как оркестратор обеспечивает отказоустойчивость приложений

15 августа 2026 10 мин. чтения
Содержание статьи

Введение: почему Kubernetes называют self-healing системой

Когда в Kubernetes ломается контейнер, удаляется под или выходит из строя узел, оркестратор может автоматически восстановить рабочее состояние: перезапустить контейнер, создать новый под или разместить его на другом узле. Но Kubernetes восстанавливает только то, что описано в желаемом состоянии и поддерживается контроллерами. Корректное поведение liveness и readiness probes, доступность ресурсов, хранилища и сетевых зависимостей требуют настройки и проверки со стороны администратора.

Этот принцип называется self-healing. Kubernetes постоянно сравнивает фактическое состояние кластера с желаемым, описанным в манифестах, и устраняет расхождения. ReplicaSet и StatefulSet поддерживают нужное количество подов, liveness-проба обнаруживает зависание контейнера, readiness-проба управляет допуском к трафику, а scheduler размещает новые поды на доступных узлах.

Когда self-healing не спасает

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

  • у пода нет контроллера, который должен поддерживать количество реплик;
  • liveness-проба проверяет недоступную базу данных и вызывает ложные перезапуски;
  • readiness-проба настроена неверно, поэтому неработоспособный под продолжает получать трафик;
  • для stateful-приложения недоступен PVC или требуется восстановление данных;
  • на узлах недостаточно CPU или памяти для запуска новых подов;
  • сетевой раздел сохраняется дольше допустимого времени, а причины сбоя не устранены.

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

Краткая карта механизмов самовосстановления

Для быстрой диагностики полезно разделять ответственность компонентов:

МеханизмЧто делаетКогда не помогает
ReplicaSetПоддерживает заданное количество подов и создает замену удаленному или упавшему поду.Не решает проблемы с образом, ресурсами, конфигурацией или недоступным узлом.
StatefulSetВосстанавливает stateful-поды со стабильными именами и привязанными PVC.Не восстанавливает поврежденные данные и не заменяет настройку репликации базы данных.
livenessОбнаруживает зависание контейнера и инициирует его перезапуск через kubelet.При неверной проверке вызывает ложные перезапуски или не обнаруживает неисправность.
readinessИсключает неготовый под из балансировки и не перезапускает контейнер.Не исправляет саму причину недоступности и не защищает от ошибок внутри приложения, если endpoint настроен формально.
PDBОграничивает число подов, которые можно добровольно сделать недоступными одновременно.Не защищает от падения ноды и других непроизвольных сбоев.
rolling updateПостепенно заменяет поды при обновлении, сохраняя заданный уровень доступности.Не спасает от неработоспособной новой версии без корректной readiness-пробы и стратегии отката.

Ключевые механизмы самовосстановления: контроллеры и пробы

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

ReplicaSet: гарантия количества подов

ReplicaSet следит за тем, чтобы в кластере всегда работало заданное количество подов. Если под удален вручную или упал из-за ошибки, ReplicaSet создает новый. Контроллер работает в цикле reconcile: получает текущее состояние, сравнивает с желаемым и выполняет корректирующие действия.

ReplicaSet обычно не используется напрямую. Им управляет Deployment, который добавляет стратегии обновления версий и откаты. При удалении пода ReplicaSet создает замену в течение секунд, если на узле или в кластере есть необходимые ресурсы. Это базовый уровень самовосстановления для stateless-приложений: веб-серверов, API и микросервисов.

Ограничение ReplicaSet: он не подходит для stateful-приложений, которым нужны стабильные идентификаторы и постоянные тома. Для таких задач используется StatefulSet. Подробнее о работе контроллеров и их архитектуре читайте в разборе механизмов watch и reconcile loop.

StatefulSet: самовосстановление для stateful-приложений

StatefulSet сохраняет стабильные идентификаторы подов и привязку к постоянным томам. Каждый под получает предсказуемое имя вида mysql-0, mysql-1, mysql-2. При падении пода StatefulSet пересоздает его с тем же именем и тем же PersistentVolumeClaim, если том доступен и может быть подключен. Сам по себе StatefulSet не гарантирует сохранность данных при повреждении хранилища.

StatefulSet также управляет порядком запуска и остановки подов. При масштабировании вниз он удаляет поды по одному, начиная с последнего. При восстановлении после сбоя поды запускаются в обратном порядке. Это важно для кластерных систем, где важны порядок инициализации и стабильные сетевые идентификаторы.

Пример: под с базой данных postgres-1 упал. StatefulSet пересоздает его с тем же именем и подключает тот же PVC. Данные не теряются, если PVC и сама система хранения исправны; восстановление репликации зависит от настроек базы данных. Если вам нужен полный пример настройки StatefulSet с постоянными томами, смотрите руководство по отказоустойчивому кластеру.

Пробы живости (liveness) и готовности (readiness): контроль состояния

Пробы проверяют состояние контейнера изнутри. Liveness-проба отвечает на вопрос: жив ли процесс? Если проба не проходит несколько раз подряд, kubelet перезапускает контейнер. Readiness-проба отвечает на вопрос: готов ли контейнер принимать трафик? Если нет, под исключается из балансировки сервиса, но не перезапускается.

Разница принципиальна. Liveness лечит зависания и deadlock'и. Readiness защищает от отправки трафика в под, который еще загружается или временно не может обрабатывать запросы. Типичный пример: приложение стартует 30 секунд и загружает данные в память. Readiness-проба с initialDelaySeconds: 30 не пустит трафик до готовности. Liveness-проба с тем же delay начнет проверять живость только после старта.

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

Типовые сценарии отказов и реакция Kubernetes

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

Падение ноды: пересоздание подов на других узлах

Когда узел выходит из строя, kubelet на нем перестает отправлять heartbeat в control plane. Через заданное время узел помечается как NotReady. Затем, после истечения pod-eviction-timeout, controller-manager инициирует эвакуацию подов: контроллеры создают замены, а scheduler размещает их на здоровых узлах.

Процесс выглядит так: kubelet замолчал, control plane пометил узел NotReady, таймаут истек, Deployment Controller запросил создание новых подов, scheduler разместил их на доступных нодах. Для stateless-приложений восстановление может занимать несколько минут. Для stateful-приложений с PVC на локальных дисках может потребоваться ручное вмешательство.

Рекомендация: проверяйте значение pod-eviction-timeout и связанные параметры в зависимости от критичности сервисов. Уменьшение таймаута сокращает время простоя, но увеличивает риск ложной эвакуации при временных сетевых проблемах.

Зависание контейнера: liveness-проба перезапускает

Контейнер может зависнуть без падения процесса: deadlock, бесконечный цикл или исчерпание ресурсов. Liveness-проба обнаруживает это и перезапускает контейнер. Типы проб: HTTP GET, TCP socket и exec-команда.

Пример конфигурации HTTP liveness-пробы:

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 15
  periodSeconds: 10
  timeoutSeconds: 5
  failureThreshold: 3

Kubelet выполняет проверку каждые 10 секунд. После трех неудачных попыток контейнер перезапускается. Параметр initialDelaySeconds дает приложению время на запуск до первой проверки.

Риск: слишком агрессивные пробы с коротким periodSeconds и низким failureThreshold вызывают ненужные перезапуски при временных замедлениях. Для приложений с длительными операциями увеличьте timeoutSeconds или используйте корректно настроенные параметры запуска.

Потеря сети: как Kubernetes обрабатывает сетевые сбои

Kubernetes различает отказ узла и сетевую изоляцию. Если kubelet не может связаться с control plane, узел помечается как NotReady, но поды на нем могут продолжать работать. Это ключевое отличие от полного падения ноды: приложения могут быть доступны для клиентов, но control plane не видит их состояние.

При восстановлении связи состояние синхронизируется: kubelet отправляет актуальный статус подов, control plane обновляет информацию. Если сетевой раздел длится дольше pod-eviction-timeout, поды эвакуируются, и после восстановления связи возможен запуск дубликатов. Для предотвращения проблем проверяйте правила эвакуации, используйте PodDisruptionBudget для добровольных disruptions и правильно настраивайте readiness-пробы.

Readiness-проба с проверкой сетевой доступности зависимостей, например базы данных или кэша, автоматически уберет под из балансировки при сетевом сбое, не перезапуская его.

Практическая настройка проб для высокой доступности

Правильная конфигурация проб определяет стабильность системы. Ошибки здесь приводят к ложным перезапускам или пропуску реальных сбоев.

Типовые ошибки проб и симптомы в проде

  • Liveness проверяет базу данных или внешний API. При кратковременной недоступности зависимости поды начинают циклически перезапускаться.
  • Слишком маленький initialDelaySeconds. Приложение еще запускается, но liveness уже фиксирует ошибку, из-за чего возникает CrashLoopBackOff.
  • Слишком короткие timeoutSeconds и periodSeconds. При нагрузке endpoint не успевает ответить, хотя процесс работоспособен; в логах появляются ложные отказы проб.
  • Одинаковые проверки для liveness и readiness. Временная недоступность зависимости приводит одновременно к потере трафика и перезапуску контейнера.
  • Проверка только TCP-порта. Порт открыт, но приложение не готово обрабатывать запросы; сервис продолжает направлять трафик в неисправный под.
  • Нет startup-логики для долгого запуска. Медленно стартующие Java-приложения и базы данных получают преждевременные liveness-отказы.

При диагностике сопоставляйте состояние пода, события и логи приложения. Частые перезапуски, рост счетчика restarts и сообщения probe failed нужно анализировать вместе, а не исправлять увеличением всех таймаутов подряд.

Параметры проб: как избежать ложных срабатываний

Каждый параметр пробы влияет на поведение системы:

  • initialDelaySeconds: задержка перед первой проверкой. Учитывайте реальное время запуска приложения. Для Java-приложений с длительной инициализацией устанавливайте значение по результатам измерений, а не по шаблону.
  • periodSeconds: интервал между проверками. Значение 10 секунд подходит для большинства приложений. Слишком частое выполнение создает лишнюю нагрузку.
  • timeoutSeconds: таймаут ожидания ответа. Для HTTP-проб достаточно 5 секунд, если endpoint отвечает быстро. Для exec-проб с тяжелыми командами увеличьте значение.
  • failureThreshold: количество неудач до срабатывания. Значение 3-5 предотвращает ложные перезапуски при кратковременных замедлениях.
  • successThreshold: количество успехов для перехода в рабочее состояние. Для readiness-проб значение 1 обычно достаточно.

Главное правило: liveness-проба не должна проверять внешние зависимости. Если приложение живо, но база данных недоступна, liveness должна проходить. Иначе контейнер будет перезапускаться без пользы. Внешние зависимости проверяет readiness-проба.

Примеры конфигурации: HTTP, TCP, exec пробы

HTTP-проба для веб-сервиса:

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5
  failureThreshold: 3
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10
  failureThreshold: 3

TCP-проба для базы данных, где HTTP-эндпоинта нет:

livenessProbe:
  tcpSocket:
    port: 5432
  initialDelaySeconds: 20
  periodSeconds: 10
  failureThreshold: 3
readinessProbe:
  tcpSocket:
    port: 5432
  initialDelaySeconds: 5
  periodSeconds: 5
  failureThreshold: 3

Exec-проба для проверки файла или процесса:

livenessProbe:
  exec:
    command:
    - cat
    - /tmp/healthy
  initialDelaySeconds: 10
  periodSeconds: 15
  failureThreshold: 3

Перед деплоем тестируйте пробы локально. Проверьте, что эндпоинты отвечают ожидаемым кодом, а команды завершаются за разумное время. Готовые production-манифесты с настроенными пробами и ограничениями ресурсов найдете в руководстве по Deployment.

Стратегии обновления и лимиты ресурсов для отказоустойчивости

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

Rolling update: обновление без простоя

Rolling update постепенно заменяет старые поды новыми, сохраняя доступность сервиса. Параметры maxSurge и maxUnavailable управляют процессом. maxSurge: 1 позволяет создать один дополнительный под сверх желаемого количества. maxUnavailable: 0 запрещает удалять старые поды до готовности новых.

Пример для deployment с 3 репликами: при обновлении версии Kubernetes создает один новый под, ждет его готовности, затем удаляет один старый. В любой момент доступно минимум 3 пода, если кластер располагает необходимыми ресурсами. Для критичных сервисов устанавливайте maxUnavailable: 0 и maxSurge: 1.

Сравнение стратегий обновления: Rolling Update, Blue-Green и Canary разобрано в отдельном руководстве.

Лимиты ресурсов: предотвращение каскадных отказов

Requests и limits определяют, сколько CPU и памяти получает под. Requests используются планировщиком для размещения подов. Limits ограничивают максимальное потребление. Без лимитов один под может занять всю память узла и вызвать OOM kill других контейнеров.

Пример установки ресурсов:

resources:
  requests:
    memory: "256Mi"
    cpu: "250m"
  limits:
    memory: "512Mi"
    cpu: "500m"

Рекомендации: устанавливайте requests на уровне среднего потребления, limits с запасом, подтвержденным метриками. Используйте мониторинг для определения фактических значений. Метрики CPU, памяти и сети для диагностики описаны в руководстве по troubleshooting.

PodDisruptionBudget: защита от добровольных disruptions

PodDisruptionBudget (PDB) ограничивает количество одновременно недоступных подов при добровольных disruptions: дренаже узла, обновлении кластера или обслуживании. PDB не защищает от непроизвольных сбоев, таких как падение ноды.

Пример PDB для deployment с 3 репликами:

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

При дренаже узла система не позволит удалить больше одного пода одновременно. Для критичных сервисов устанавливайте minAvailable на уровне N-1, где N - количество реплик, если такой уровень доступности соответствует архитектуре приложения. Если вы используете облачную инфраструктуру для Kubernetes, обратите внимание на Timeweb Cloud с готовыми кластерами и гибким масштабированием ресурсов.

Заключение: самовосстановление как фундамент надежности

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

ReplicaSet и StatefulSet гарантируют, что нужное количество подов будет поддерживаться контроллерами. Liveness-пробы перезапускают зависшие контейнеры. Readiness-пробы управляют трафиком. Rolling update обновляет без простоя. Лимиты ресурсов защищают узлы от перегрузки. PDB сохраняет доступность при обслуживании.

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

Поделиться: