← Назад к вопросам

Что такое StatefulSet?

2.0 Middle🔥 131 комментариев
#Docker, Kubernetes и DevOps

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# StatefulSet в Kubernetes

Определение

StatefulSet — это Kubernetes ресурс для управления приложениями, которым требуется:

  • Уникальная идентичность для каждого pod'а
  • Стабильное имя хоста и DNS
  • Упорядоченное развертывание/удаление
  • Persistent storage (постоянное хранилище)
  • Состояние (stateful) — pod должен помнить кто он такой

Основные характеристики

StatefulSet vs Deployment

ХарактеристикаStatefulSetDeployment
Pod идентичностьУникальнаяОдноразовая
Имя pod'аapp-0, app-1, app-2app-xyz123, app-abc456
Порядок развертыванияПоследовательный (app-0 → app-1)Параллельный
StoragePersistentVolume требуетсяОбычно ephemeral
МасштабированиеМедленнееБыстрее
ИспользованиеБД, кеши, очередиВеб-сервисы, API

Как StatefulSet работает

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql-cluster
spec:
  serviceName: mysql  # ВАЖНО! Headless Service для DNS
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        ports:
        - containerPort: 3306
        volumeMounts:
        - name: mysql-storage
          mountPath: /var/lib/mysql
  # ВАЖНО! Persistent storage для каждого pod'а
  volumeClaimTemplates:
  - metadata:
      name: mysql-storage
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi
---
# Headless Service (без ClusterIP)
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  clusterIP: None  # ← Headless!
  selector:
    app: mysql
  ports:
  - port: 3306

Идентичность pod'ов

Уникальное имя

# При создании StatefulSet с 3 репликами:
kubectl get pods

NAME              READY   STATUS
mysql-cluster-0   1/1     Running   ← Индекс 0
mysql-cluster-1   1/1     Running   ← Индекс 1
mysql-cluster-2   1/1     Running   ← Индекс 2

# При удалении pod'а:
# kubectl delete pod mysql-cluster-1
# Kubernetes создаёт новый mysql-cluster-1 (ТОТ ЖЕ ИМЯ!)
# А не случайное имя

Stable DNS

Кажды pod получает stable DNS имя:

# Headless Service mysql с label selector app: mysql
# создаёт DNS записи:

mysql-cluster-0.mysql.default.svc.cluster.local
mysql-cluster-1.mysql.default.svc.cluster.local
mysql-cluster-2.mysql.default.svc.cluster.local

# Другие pod'ы могут обращаться:
mysql-cluster-1.mysql  # Сокращённая форма в том же namespace

Упорядоченное развертывание

При масштабировании UP

kubectl scale statefulset mysql-cluster --replicas=5

# Развертывание последовательное:
Время:  mysql-cluster-0   mysql-cluster-1   mysql-cluster-2   mysql-cluster-3   mysql-cluster-4
0s      Running           Running           Running
10s     Ready             Ready             Ready             Creating
20s     Ready             Ready             Ready             Running
30s     Ready             Ready             Ready             Ready              Creating
40s     Ready             Ready             Ready             Ready              Running

При масштабировании DOWN

kubectl scale statefulset mysql-cluster --replicas=1

# Удаление в обратном порядке:
40s     mysql-cluster-2 завершается
30s     mysql-cluster-1 завершается
20s     mysql-cluster-0 остаётся (Single replica)

Этот порядок критичен для приложений вроде консенсус-кластеров (Zookeeper, etcd, Elasticsearch).

Persistent Storage

volumeClaimTemplates

Создаёт отдельный PersistentVolume для каждого pod'а:

volumeclaimtemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 50Gi

Результат:

kubectl get pvc

NAME                STATUS   VOLUME
data-mysql-0      Bound    pvc-12345
data-mysql-1      Bound    pvc-67890
data-mysql-2      Bound    pvc-24680

# Каждый pod имеет собственный volume!
# Даже если pod удалится и пересоздастся, volume сохранится

Praktical Use Cases

1. Database Cluster (MySQL, PostgreSQL)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres-ha
spec:
  serviceName: postgres
  replicas: 3
  # ...
  volumeClaimTemplates:
  - metadata:
      name: postgres-storage
    spec:
      storageClassName: fast-ssd
      resources:
        requests:
          storage: 100Gi

Почему: PostgreSQL нужна уникальная идентичность для репликации, stable DNS, и персистентное хранилище.

2. Message Queue (RabbitMQ, Kafka)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: kafka-cluster
spec:
  serviceName: kafka
  replicas: 3
  # ...

Почему: Kafka брокеры должны иметь стабильные имена хостов для gossip протокола, и нужны local volumes для данных.

3. Search Engine (Elasticsearch)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: elasticsearch
spec:
  serviceName: elasticsearch
  replicas: 3
  # ...

Почему: Nodes должны отслеживать свой индекс, плюс требуется large persistent storage.

4. In-Memory Cache (Redis Cluster)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-cluster
spec:
  serviceName: redis
  replicas: 6  # Minumum для cluster mode
  # ...

Инициализация и управление состоянием

Init Container для setup

spec:
  template:
    spec:
      initContainers:
      - name: init-mysql
        image: mysql:8.0
        command:
        - bash
        - -c
        - |
          set -ex
          ordinal=${HOSTNAME##*-}  # Получаем индекс: 0, 1, 2
          if [[ $ordinal -eq 0 ]]; then
            # Это primary node
            mysql --user=root --password=$MYSQL_ROOT_PASSWORD \
              -e "SET GLOBAL server_id=$(( ordinal + 1 ));"
          else
            # Это replica node
            mysql --user=root --password=$MYSQL_ROOT_PASSWORD \
              -e "CHANGE MASTER TO MASTER_HOST='mysql-0.mysql.default', ..."
          fi

Lifecycle Hooks

preStop для graceful shutdown

spec:
  template:
    spec:
      containers:
      - name: app
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh", "-c", "sleep 15"]
        # Даёшь 15 сек на graceful shutdown перед force kill

Мониторинг StatefulSet'а

# Посмотреть статус
kubectl describe statefulset mysql-cluster

# Посмотреть pod'ы
kubectl get pods -l app=mysql

# Посмотреть PVC'и
kubectl get pvc

# Логи pod'а
kubectl logs mysql-cluster-0

# Exec в pod
kubectl exec -it mysql-cluster-0 -- bash

Важные различия от Deployment

# Deployment — для stateless приложений
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  # Любые pod'ы с одинаковой configuration
  # Быстрое масштабирование
  # Нет persistent storage

---

# StatefulSet — для stateful приложений
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres  # ТРЕБУЕТСЯ!
  replicas: 3
  # Упорядоченные pod'ы (postgres-0, postgres-1, postgres-2)
  # Медленное, но контролируемое масштабирование
  # Требуется persistent storage
  volumeClaimTemplates: [ ... ]

Итоговый ответ

StatefulSet — это Kubernetes ресурс для приложений, которым нужна идентичность и состояние:

  • Уникальные имена pod'ов (app-0, app-1, app-2)
  • Стабильные DNS имена
  • Упорядоченное развертывание
  • Persistent storage для каждого pod'а

Используй для баз данных, очередей, кешей, поисковых движков, а не для веб-сервисов (используй Deployment).

Что такое StatefulSet? | PrepBro