StatefulSet¶
StatefulSet — это встроенный ресурс (API-объект) платформы оркестрации контейнеров Kubernetes, предназначенный для управления группами подов (pod), которым требуется стабильная идентичность, уникальные сетевые имена и постоянное хранение данных. В отличие от ресурса Deployment, который ориентирован на stateless (без сохранения состояния) приложения, StatefulSet гарантирует, что каждый под в наборе имеет детерминированное имя, порядок запуска и остановки, а также привязку к собственному тому (volume) для хранения данных.
¶История и предпосылки
StatefulSet был введён в Kubernetes версии 1.5 (декабрь 2016 года) как замена экспериментального ресурса PetSet, который появился в версии 1.3. PetSet, в свою очередь, был разработан для решения проблемы управления stateful-приложениями (базы данных, очереди сообщений, кэши) в контейнерной среде, где традиционные подходы Kubernetes (ReplicaSet, Deployment) не обеспечивали необходимой стабильности идентичности подов. Основной недостаток PetSet заключался в неполной реализации семантики «домашнего питомца» (pet) — каждый под должен быть уникальным, а не взаимозаменяемым, как в стаде (cattle). StatefulSet исправил эти недостатки, добавив поддержку упорядоченного обновления, graceful shutdown и более гибкую модель масштабирования.
¶Архитектура и ключевые характеристики
¶Идентичность подов
Каждый под, управляемый StatefulSet, получает уникальное, предсказуемое имя, которое формируется по шаблону: <имя StatefulSet>-<порядковый номер>. Нумерация начинается с 0. Например, для StatefulSet с именем my-db будут созданы поды my-db-0, my-db-1, my-db-2 и так далее. Это имя остаётся неизменным на протяжении всего жизненного цикла пода, даже после перезапуска или перепланирования на другой узел кластера. При удалении пода и его повторном создании под тем же именем он получает тот же порядковый номер.
¶Сетевые имена
Каждый под StatefulSet получает стабильное DNS-имя, основанное на его имени. Внутри кластера Kubernetes поды доступны по адресу вида <имя пода>.<имя сервиса>.<namespace>.svc.cluster.local. Это позволяет другим компонентам приложения обращаться к конкретному экземпляру stateful-приложения, не завися от его IP-адреса, который может меняться. Для этого StatefulSet обычно использует headless-сервис (сервис без ClusterIP), который не балансирует трафик, а возвращает список DNS-записей для всех подов.
¶Упорядоченное развёртывание и масштабирование
StatefulSet запускает поды строго последовательно, в порядке возрастания порядкового номера, и ждёт, пока каждый под перейдёт в состояние Running и Ready, прежде чем запустить следующий. При масштабировании вверх (увеличении количества реплик) новые поды добавляются в конце очереди. При масштабировании вниз (уменьшении количества реплик) поды удаляются в обратном порядке — начиная с самого старшего номера. Это гарантирует, что при уменьшении количества реплик сначала будет остановлен под с наибольшим номером, что критично для приложений, где данные распределены по экземплярам.
¶Упорядоченное обновление
StatefulSet поддерживает стратегию обновления RollingUpdate, при которой поды обновляются по одному, в порядке убывания номеров (начиная с самого старшего). Это позволяет сначала обновить «менее важный» экземпляр, проверить его работоспособность и только затем переходить к следующему. Также доступна стратегия OnDelete, при которой поды обновляются только после их явного удаления администратором.
¶Хранение данных
StatefulSet тесно связан с механизмом PersistentVolumeClaim (PVC). Каждый под может иметь собственный PVC, который монтируется в файловую систему пода. При удалении пода PVC не удаляется автоматически, что позволяет сохранить данные при перепланировании пода на другой узел. При масштабировании вниз PVC для удалённых подов также остаются в кластере, если не указано иное. Это делает StatefulSet подходящим для приложений, где каждый экземпляр хранит собственные данные (например, базы данных с шардированием).
¶Применение
StatefulSet используется для развёртывания приложений, которые требуют стабильной идентичности и сохранения состояния. Наиболее распространённые сценарии:
- Базы данных: MySQL, PostgreSQL, MongoDB, Cassandra, CockroachDB, TiDB. Каждый экземпляр базы данных — отдельный узел кластера, имеющий свой набор данных.
- Системы очередей и сообщений: Apache Kafka, RabbitMQ, Redis (в кластерном режиме), NATS. Каждый брокер или узел очереди имеет уникальный идентификатор и хранит часть данных.
- Распределённые файловые системы и хранилища: Ceph, MinIO, GlusterFS. Каждый под управляет своим набором дисков.
- Приложения, требующие фиксированных сетевых имён: например, серверы приложений, которые подключаются к другим компонентам по имени пода.
¶Ограничения и особенности
- StatefulSet не поддерживает автоматическое масштабирование на основе нагрузки (Horizontal Pod Autoscaler) в полной мере, так как изменение количества реплик может нарушить упорядоченность и привести к потере данных. Масштабирование обычно выполняется вручную или через операторы.
- При удалении StatefulSet поды не удаляются автоматически, если не указана политика
podManagementPolicy: OrderedReady(по умолчанию). Для полного удаления набора подов необходимо удалить их вручную или использоватьkubectl delete statefulset <имя> --cascade=orphan. - StatefulSet не обеспечивает автоматическое перераспределение данных при масштабировании — это задача оператора или самого приложения (например, для Cassandra требуется ручное перебалансирование).
- Для работы с StatefulSet необходимо наличие динамического провайдера PersistentVolume (например, CSI-драйвера) или предварительно созданных PersistentVolume.
¶Пример конфигурации
Ниже приведён упрощённый манифест StatefulSet для базы данных MySQL:
```yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql spec: serviceName: mysql replicas: 3 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers:
- name: mysql
image: mysql:8.0 ports:
- containerPort: 3306
volumeMounts:
- name: data
mountPath: /var/lib/mysql volumeClaimTemplates:
- metadata:
name: data spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 10Gi ```
В этом примере serviceName указывает на headless-сервис mysql, который обеспечивает DNS-имена для подов (например, mysql-0.mysql). volumeClaimTemplates автоматически создаёт PVC для каждого пода, привязывая к нему том размером 10 ГБ.
¶Критика и альтернативы
StatefulSet критикуется за сложность управления stateful-приложениями в Kubernetes. Он требует от разработчика глубокого понимания механизмов хранения и сетевой идентичности. В ответ на это сообщество Kubernetes разработало концепцию операторов (operators) — программных расширений, которые автоматизируют рутинные задачи (резервное копирование, восстановление, масштабирование, обновление) для конкретных stateful-приложений. Например, операторы для PostgreSQL (Crunchy Data, Zalando), для MySQL (Oracle MySQL Operator, Presslabs), для Kafka (Strimzi) и другие. Операторы часто используют StatefulSet в качестве основы, но добавляют поверх него дополнительную логику.
Альтернативой StatefulSet в некоторых случаях может быть использование Deployment с общими томами (например, NFS) или DaemonSet для приложений, которые должны работать на каждом узле кластера. Однако эти подходы не обеспечивают стабильной идентичности подов и подходят только для ограниченного круга задач.
¶Источники
- Документация Kubernetes: «StatefulSets» (kubernetes.io/docs/concepts/workloads/controllers/statefulset/)
- Kubernetes in Action, 2nd Edition, Marko Lukša, Manning Publications, 2020
- The Kubernetes Book, Nigel Poulton, 2022
- «PetSet vs StatefulSet: The Evolution of Stateful Applications in Kubernetes», статья на The New Stack, 2017
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →


