Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → StatefulSet: приложения с состоянием в Kubernetes

StatefulSet: стабильный идентификатор и своё хранилище для каждого пода

StatefulSet: нумерация подов, headless-сервис, volumeClaimTemplates, порядок развёртывания и когда состояние лучше вынести из кластера.

Прямой ответ

StatefulSet — контроллер для приложений, которым нужны стабильный сетевой идентификатор и собственное хранилище на каждый экземпляр. Deployment даёт поды со случайными именами и общим томом; StatefulSet даёт предсказуемость.

Три гарантии StatefulSet:

  1. Стабильное имя пода. Поды нумеруются: pg-0, pg-1, pg-2. Имя сохраняется при перезапуске, в отличие от случайного суффикса в Deployment.
  2. Стабильное хранилище. volumeClaimTemplates создаёт отдельный PVC на каждый под. После перезапуска pg-1 подключает тот же том, что и раньше.
  3. Порядок развёртывания и завершения. Поды создаются последовательно от 0 до N−1, каждый следующий — после готовности предыдущего. Завершение идёт в обратном порядке.
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: pg
spec:
  serviceName: pg-headless        # обязателен headless-сервис
  replicas: 3
  selector:
    matchLabels: { app: pg }
  template:
    metadata:
      labels: { app: pg }
    spec:
      containers:
        - name: postgres
          image: postgres:16
          resources:
            requests: { cpu: 500m, memory: 1Gi }
            limits:   { memory: 2Gi }
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests: { storage: 50Gi }

Для работы DNS нужен headless-сервис (clusterIP: None). Тогда каждый под получает запись вида pg-1.pg-headless.namespace.svc.cluster.local, и приложение может обращаться к конкретному экземпляру по имени. Это необходимо для репликации, где узлы должны знать друг друга.

Важная деталь эксплуатации: PVC не удаляется вместе с подом. Уменьшение replicas оставляет тома, чтобы данные не терялись при случайном масштабировании. В новых версиях поведение настраивается через persistentVolumeClaimRetentionPolicy, но по умолчанию тома сохраняются, и их удаление — отдельная ручная операция.

Практика: когда применять и как эксплуатировать

Когда StatefulSet оправдан:

  1. Кластеры с репликацией и выбором лидера. База данных, очередь, координатор — там, где узлы обмениваются данными и должны различать друг друга.
  2. Приложения, привязанные к конкретному тому. Обработка данных, где каждый экземпляр владеет своим разделом.
  3. Системы, требующие стабильного имени в конфигурации. Список узлов задан в конфиге и не должен меняться.

Когда лучше Deployment:

  1. Приложение не хранит состояние. Stateless-сервис с внешним хранилищем проще и быстрее масштабируется.
  2. Состояние можно вынести из кластера. Управляемая база или отдельный кластер БД снимают задачу резервного копирования, обновлений и восстановления с платформы приложений — о репликации в статье про реплики PostgreSQL.
  3. Нужно быстрое масштабирование. Последовательный запуск подов медленнее параллельного.

Рекомендации:

  1. Задавайте ресурсы явно. База данных с классом BestEffort вытесняется первой; детали — в статье про requests и limits.
  2. Проверяйте корректное завершение. Остановка базы по SIGKILL приводит к восстановлению при старте. Нужны корректный обработчик сигнала и достаточный terminationGracePeriodSeconds — см. graceful shutdown.
  3. Планируйте резервное копирование. Наличие тома не означает наличия копии. Резервное копирование и проверка восстановления — отдельная задача, не решаемая StatefulSet.
  4. Используйте partition для поэтапного обновления. Поле updateStrategy.rollingUpdate.partition останавливает обновление на заданном номере, что позволяет проверить новую версию на одном узле.
  5. Следите за привязкой к зоне. Том с режимом ReadWriteOnce привязан к узлу и зоне доступности; при сбое зоны под не запустится в другой зоне, пока том не будет перенесён.
  6. Не смешивайте роли в одном StatefulSet. Основной узел и реплики имеют разные требования к ресурсам и разные профили нагрузки.

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

Контекст: PostgreSQL работал в StatefulSet из трёх подов. После обновления версии один из узлов не поднялся, и часть данных оказалась недоступна.

  1. Диагностика. Под pg-2 находился в состоянии CrashLoopBackOff. В логах — ошибка несовместимости формата каталога данных: том остался от предыдущей версии.
  2. Причина 1. Обновление образа выполнялось для всех подов одновременно, а не поэтапно, поэтому проверить совместимость на одном узле было невозможно.
  3. Причина 2. Резервной копии, пригодной для восстановления, не существовало: задача копирования выполнялась, но восстановление ни разу не проверялось, и архивы имели неверные права.
  4. Действия. (а) Восстановили данные из копии недельной давности, потеряв часть транзакций; (б) ввели поэтапное обновление через partition с проверкой репликации между шагами; (в) настроили регулярное резервное копирование с автоматической проверкой восстановления на отдельном стенде; (г) добавили проверку готовности, которая учитывает состояние репликации, а не только доступность порта; (д) приняли решение перенести основную базу на управляемый сервис, оставив в кластере только нагрузки без состояния.
  5. Результат. Последующие обновления проходили по одному узлу с проверкой; время восстановления после сбоя сократилось до 20 минут благодаря проверенной процедуре.

Вывод: StatefulSet решает задачу идентичности и хранилища, но не отвечает за сохранность данных. Резервное копирование, порядок обновлений и проверка восстановления остаются задачей команды.

FAQ

Чем StatefulSet отличается от Deployment с общим томом? Deployment не гарантирует ни имён, ни порядка, ни отдельного тома на экземпляр. Общий том с режимом ReadWriteMany подходит для файлов, но не для базы данных, где каждый узел управляет собственными файлами.

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

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

Нужен ли StatefulSet для Redis или Kafka? Если они работают в кластерном режиме с репликацией — да, из-за требования к стабильным именам и собственным томам. Одиночный экземпляр кэша без персистентности работает и в Deployment.

Источники: Kubernetes docs (StatefulSet, headless services, persistent volumes) — ссылки в шапке.