Отказоустойчивый кластер Kubernetes: настройка автоматического восстановления и самовосстановления | AdminWiki

Отказоустойчивый кластер Kubernetes: настройка автоматического восстановления и самовосстановления

27 июля 2026 10 мин. чтения

Отказоустойчивость кластера Kubernetes выстраивается на четырех механизмах: автоматический контроль здоровья подов через liveness и readiness probes, защита критичных сервисов с помощью Pod Disruption Budget, сохранение состояния приложений в StatefulSets с PersistentVolume и обновление без простоя через стратегию rolling update. Каждый из этих компонентов решает конкретную задачу, и пропуск любого из них оставляет брешь в защите продакшен-среды.

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

Почему отказоустойчивость в Kubernetes - это не только реплики

Три реплики веб-приложения создают иллюзию надежности. Реальность сложнее: администратор выполняет kubectl drain на узле, и все три пода одновременно уходят в Terminating. Или контейнер зависает из-за дедлока в коде, но процесс продолжает работать, а kubelet считает его живым. Или база данных теряет все записи после пересоздания пода, потому что хранилище было эфемерным.

Полноценная отказоустойчивость требует четырех слоев защиты:

  • Контроль здоровья - liveness probe перезапускает зависший контейнер, readiness probe исключает неготовый под из балансировки.
  • Защита от прерываний - Pod Disruption Budget гарантирует минимальное количество работающих реплик при обслуживании узлов.
  • Сохранение данных - StatefulSet с PersistentVolume привязывает хранилище к конкретному поду и сохраняет его при пересоздании.
  • Безопасные обновления - rolling update с правильно подобранными maxSurge и maxUnavailable заменяет поды без потери доступности.

Разберем каждый слой с примерами конфигураций и типичными ошибками.

Автоматический контроль здоровья подов: liveness и readiness probes

Kubelet выполняет проверки здоровья контейнеров по заданному расписанию. Liveness probe отвечает на вопрос «жив ли процесс?», readiness probe - «готов ли он принимать трафик?». Разница принципиальна: при провале liveness контейнер перезапускается, при провале readiness под исключается из эндпоинтов сервиса, но продолжает работать.

Три типа проверок покрывают большинство сценариев:

  • httpGet - HTTP GET-запрос к указанному порту и пути. Код ответа 200–399 считается успехом.
  • tcpSocket - попытка установить TCP-соединение. Подходит для баз данных и не-HTTP сервисов.
  • exec - выполнение команды внутри контейнера. Нулевой код возврата означает успех.

Подробное руководство по настройке probes с готовыми YAML для баз данных и веб-приложений разобрано в отдельной статье. Здесь сосредоточимся на конфигурациях, критичных для отказоустойчивости.

Liveness probe: перезапуск пода при сбое

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

Рабочий пример для веб-приложения с эндпоинтом /healthz:

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 15
  periodSeconds: 20
  failureThreshold: 3

Эндпоинт /healthz должен возвращать 200 OK, если приложение способно отвечать на запросы. Реализация на стороне приложения проверяет состояние основного цикла обработки, а не внешних сервисов. Параметр initialDelaySeconds задает задержку перед первой проверкой - 15 секунд достаточно для запуска большинства контейнеров. periodSeconds определяет интервал между проверками, failureThreshold - количество последовательных провалов до перезапуска. При failureThreshold: 3 под будет перезапущен через 15 + 20*3 = 75 секунд после зависания.

Readiness probe: управление трафиком

Readiness probe предотвращает отправку запросов на под, который еще не готов к работе: загружает кеш, выполняет миграции, устанавливает соединения с базой. Без readiness probe новый под получает трафик сразу после старта и отвечает ошибками.

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

Эндпоинт /ready возвращает 200 OK только после полной инициализации приложения. initialDelaySeconds здесь больше, чем у liveness - 30 секунд на прогрев. При провале readiness kubelet удаляет IP пода из эндпоинтов сервиса, но не перезапускает контейнер. После восстановления проверки под возвращается в балансировку.

Типичные ошибки при настройке probes

Пять ошибок, которые приводят к каскадным сбоям в production:

  1. failureThreshold: 1 при долгих проверках. Любая кратковременная задержка вызывает перезапуск. Минимальное значение - 3.
  2. exec-проверка с тяжелой командой. Скрипт, который пишет в базу или читает большой файл, нагружает контейнер каждые 10 секунд. Проверка должна быть легковесной.
  3. liveness проверяет внешние зависимости. Недоступность базы данных перезапускает все веб-поды, создавая лавину рестартов. Внешние зависимости проверяет readiness.
  4. Отсутствие graceful shutdown. Приложение не обрабатывает SIGTERM и обрывает соединения. Настройте terminationGracePeriodSeconds с запасом.
  5. Одинаковые параметры для всех контейнеров. Время запуска Java-приложения и Go-микросервиса отличается на порядок. Подбирайте initialDelaySeconds индивидуально.

Защита критичных сервисов с помощью Pod Disruption Budget (PDB)

Pod Disruption Budget - это ресурс Kubernetes, который задает минимальное количество подов, которые должны оставаться доступными при добровольных прерываниях. Добровольные прерывания инициируются администратором или контроллером кластера: drain узла, удаление deployment, обновление нод, дефрагментация кластера. Аппаратные сбои и падение узлов PDB не контролирует.

PDB оперирует двумя параметрами:

  • minAvailable - минимальное количество подов, которые должны оставаться в статусе Ready.
  • maxUnavailable - максимальное количество подов, которые могут быть недоступны.

Выбор параметра зависит от приоритета: minAvailable гарантирует доступность, maxUnavailable позволяет быстрее проводить обслуживание.

Настройка PDB: minAvailable vs maxUnavailable

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

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

Selector должен совпадать с метками подов, которые защищает PDB. Команда kubectl get pdb покажет текущий статус бюджета: количество разрешенных прерываний, текущее количество здоровых подов и ожидаемое.

maxUnavailable подходит для сервисов, где скорость обслуживания важнее гарантированной доступности. Например, для фонового обработчика очередей с 5 репликами можно задать maxUnavailable: 2, разрешив одновременное отключение двух подов.

PDB и эвакуация узлов: как это работает вместе

Практический сценарий: администратор выполняет kubectl drain для обслуживания узла, на котором работают два пода защищенного сервиса. Kubernetes проверяет PDB и видит требование minAvailable: 2. Если на других узлах осталось только два пода, эвакуация заблокируется с ошибкой:

error when evicting pods: Cannot evict pod as it would violate the pod's disruption budget.

Правильный порядок действий: сначала добавить новый узел и дождаться перераспределения подов, затем drain старого. Либо временно увеличить количество реплик перед обслуживанием. Слишком строгий PDB с minAvailable равным общему количеству реплик полностью блокирует любые операции обслуживания - используйте его только для действительно критичных сервисов.

Сохранение состояния приложений: StatefulSets и PersistentVolume

Deployment создает поды со случайными именами и общим хранилищем. При перезапуске под теряет идентичность, а данные в эфемерном хранилище удаляются. StatefulSet решает эту проблему: каждый под получает стабильное имя (statefulset-name-0, statefulset-name-1), собственный PersistentVolume и упорядоченное развертывание.

Выбор контроллера для конкретной рабочей нагрузки разобран в сравнительном руководстве по Deployment, StatefulSet, DaemonSet и Job. Для stateful-приложений - баз данных, очередей сообщений, распределенных хранилищ - StatefulSet обязателен.

Создание StatefulSet с постоянным хранилищем

Пример StatefulSet для PostgreSQL с тремя репликами и автоматическим созданием PersistentVolume через volumeClaimTemplates:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres
  replicas: 3
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:16
        volumeMounts:
        - name: data
          mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 10Gi

volumeClaimTemplates создает отдельный PVC для каждого пода: data-postgres-0, data-postgres-1, data-postgres-2. При удалении и пересоздании пода PVC и связанный с ним PV сохраняются, данные не теряются. Удаление самого StatefulSet не удаляет PVC - это сделано намеренно для защиты от случайной потери данных.

Стабильные сетевые идентификаторы обеспечиваются через headless-сервис. Под postgres-0 всегда доступен по имени postgres-0.postgres.namespace.svc.cluster.local, что критично для репликации и кластеризации баз данных.

Управление данными: снапшоты и бэкапы PV

PersistentVolume защищает данные при перезапуске пода, но не заменяет резервное копирование. Выход из строя дискового массива, ошибка администратора или повреждение файловой системы уничтожат данные вместе с PV. Два инструмента для защиты:

  • CSI снапшоты - моментальные снимки тома на уровне провайдера хранилища. Восстановление занимает секунды, но снапшоты живут в том же хранилище.
  • Velero - резервное копирование всего кластера или отдельных неймспейсов во внешнее объектное хранилище. Полное аварийное восстановление кластера Kubernetes от etcd до приложений описано в соответствующем руководстве.

Настройте регулярные бэкапы до первого инцидента. Минимальная конфигурация: ежедневный снапшот CSI с хранением за 7 дней и еженедельный полный бэкап Velero в S3-совместимое хранилище.

Обновление без простоя: стратегия Rolling Update

Rolling update постепенно заменяет поды старой версии новыми, сохраняя доступность сервиса. Два параметра управляют процессом:

  • maxSurge - сколько дополнительных подов можно создать сверх желаемого количества. Позволяет ускорить обновление за счет временного увеличения ресурсов.
  • maxUnavailable - сколько подов могут быть недоступны в процессе обновления. Значение 0 гарантирует, что трафик не прервется ни на секунду.

Настройка rolling update для нулевого простоя

Конфигурация для сервиса, который должен оставаться доступным при любых обстоятельствах:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    ...

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

Эта стратегия требует readiness probe. Без нее новый под мгновенно получает статус Ready и начинает принимать трафик, не завершив инициализацию. Готовые production-манифесты с probes и rolling update для веб-приложений и API собраны в руководстве по управлению приложениями через Deployment.

Откат обновления: как быстро восстановить предыдущую версию

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

kubectl rollout undo deployment/api

Откат использует ту же стратегию rolling update, поэтому при maxUnavailable: 0 он пройдет без прерывания трафика. Проверьте историю ревизий перед откатом:

kubectl rollout history deployment/api

Для отката к конкретной ревизии укажите флаг --to-revision. Важное условие: readiness probe должна корректно работать и для предыдущей версии, иначе откат приведет к недоступности сервиса.

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

Типичный микросервисный сценарий: веб-приложение с API и базой данных PostgreSQL. API-сервис разворачивается через Deployment с probes, PDB и rolling update. База данных - через StatefulSet с PersistentVolume. Связка обеспечивает отказоустойчивость на всех уровнях.

Deployment для API:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
      - name: api
        image: api:1.0.0
        ports:
        - containerPort: 8080
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 20
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
          failureThreshold: 3
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: api

StatefulSet для PostgreSQL приведен в разделе выше. Взаимодействие компонентов: API-поды проходят проверку readiness перед приемом трафика, liveness перезапускает зависшие контейнеры, PDB защищает от одновременного отключения при обслуживании узлов, rolling update заменяет версии без простоя. PostgreSQL хранит данные на PersistentVolume, которые сохраняются при перезапуске подов.

Для продакшен-среды добавьте мониторинг здоровья подов и узлов. Метрики CPU, памяти, сети и диска с готовыми PromQL-запросами для диагностики неисправностей разобраны в руководстве по Kubernetes troubleshooting.

Ограничения и подводные камни

Описанные механизмы покрывают основные сценарии отказоустойчивости, но имеют границы применимости:

  • PDB не защищает от аппаратных сбоев. Внезапное падение узла с двумя подами при minAvailable: 2 приведет к недоступности сервиса. Единственная защита - распределение реплик по разным физическим узлам через podAntiAffinity.
  • Probes требуют тонкой настройки под каждое приложение. Универсальных параметров не существует. Тестируйте конфигурацию под нагрузкой и имитируйте сбои зависимостей.
  • StatefulSets усложняют масштабирование. Упорядоченное создание и удаление подов замедляет операции. Горизонтальное масштабирование базы данных требует настройки репликации на уровне приложения.
  • Rolling update не спасает от ошибок в новой версии. Если релиз содержит баг, который проявляется через 10 минут работы, rolling update успешно заменит все поды, и сервис упадет полностью. Для защиты от таких сценариев нужны canary-релизы и постепенное переключение трафика.
  • PV не заменяет бэкапы. Повреждение данных на томе не лечится перезапуском пода. Регулярное резервное копирование обязательно.

Для дальнейшего углубления изучите архитектуру контроллеров Kubernetes. Понимание того, как работают watch и reconcile loop внутри Deployment и StatefulSet, помогает диагностировать неочевидные проблемы. Детальный разбор этих механизмов с практическими методиками диагностики - в статье об архитектуре взаимодействия контроллеров Kubernetes.

Если вы разворачиваете кластер в облаке, обратите внимание на облачную инфраструктуру Timeweb Cloud с готовыми серверами, VDS и поддержкой Kubernetes. Это позволяет сосредоточиться на настройке отказоустойчивости, а не на управлении физическим железом.

Поделиться:
Сохранить гайд? В закладки браузера