← Back to notes

StatefulSet и
DaemonSet


Deployment создаёт взаимозаменяемые Pod. Stateful-приложения требуют стабильного имени Pod, собственного хранилища для каждой реплики, предсказуемого порядка запуска. Другим workload-ам нужен один агент на каждом узле. Для этих задач — StatefulSet и DaemonSet.

[source: kubernetes.io/docs/concepts/workloads/controllers/statefulset/]

StatefulSet

StatefulSet управляет stateful-приложениями со стабильной идентичностью Pod и постоянным хранилищем.

Чем отличается от Deployment

Свойства StatefulSet

Стабильная сетевая идентичность:

  • Pod именуются <statefulset-name>-<ordinal>: postgres-0, postgres-1, postgres-2
  • Каждый Pod получает стабильный DNS: <pod-name>.<headless-service>.<namespace>.svc.cluster.local

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

  • Pod создаются последовательно: pod-0 → pod-1 → pod-2
  • Каждый следующий стартует только после готовности предыдущего (readinessProbe)
  • При удалении — обратный порядок: pod-2 → pod-1 → pod-0

Стабильное хранилище:

  • volumeClaimTemplates создают отдельный PVC для каждого Pod
  • При пересоздании Pod привязывается к тому же PVC — данные сохраняются
  • При удалении Pod PVC не удаляются автоматически

Headless Service

StatefulSet требует Headless Service (clusterIP: None). Он не балансирует трафик — обеспечивает DNS-записи для каждого Pod напрямую.

apiVersion: v1
kind: Service
metadata:
  name: postgres-headless
spec:
  clusterIP: None
  selector:
    app: postgres
  ports:
    - port: 5432
      targetPort: 5432

Манифест StatefulSet

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres-headless
  replicas: 3
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:16
          ports:
            - containerPort: 5432
          env:
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: pg-secret
                  key: password
          volumeMounts:
            - name: pg-data
              mountPath: /var/lib/postgresql/data
          readinessProbe:
            exec:
              command:
                - pg_isready
                - -U
                - postgres
            initialDelaySeconds: 10
            periodSeconds: 5
  volumeClaimTemplates:
    - metadata:
        name: pg-data
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 10Gi
        storageClassName: fast-ssd

Результат:

  • Pod: postgres-0, postgres-1, postgres-2
  • PVC: pg-data-postgres-0, pg-data-postgres-1, pg-data-postgres-2
  • DNS: postgres-0.postgres-headless.default.svc.cluster.local

Масштабирование StatefulSet

# Масштабирование  последовательно
kubectl scale statefulset postgres --replicas=5

# Статус
kubectl get statefulsets
kubectl get sts

# Детали
kubectl describe sts postgres

# Удалить Pod (StatefulSet пересоздаст с тем же именем и PVC)
kubectl delete pod postgres-2

Типичные use cases для StatefulSet

  • Базы данных: PostgreSQL, MySQL, MongoDB
  • Очереди сообщений: Kafka, RabbitMQ
  • Кеши с репликацией: Redis Sentinel/Cluster
  • Распределённые хранилища: Elasticsearch, Cassandra, etcd

DaemonSet

DaemonSet гарантирует, что на каждом (или выбранном) узле кластера запущен ровно один экземпляр Pod.

[source: kubernetes.io/docs/concepts/workloads/controllers/daemonset/]

Поведение

  • При добавлении нового узла — DaemonSet автоматически создаёт Pod на нём
  • При удалении узла — Pod удаляется вместе с ним
  • При удалении DaemonSet — удаляются все его Pod

Манифест DaemonSet

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  labels:
    app: fluentd
spec:
  selector:
    matchLabels:
      app: fluentd
  template:
    metadata:
      labels:
        app: fluentd
    spec:
      containers:
        - name: fluentd
          image: fluent/fluentd:v1.17
          resources:
            requests:
              cpu: 100m
              memory: 200Mi
            limits:
              cpu: 200m
              memory: 400Mi
          volumeMounts:
            - name: varlog
              mountPath: /var/log
              readOnly: true
      volumes:
        - name: varlog
          hostPath:
            path: /var/log

Выбор узлов

По умолчанию DaemonSet запускает Pod на всех узлах. Для ограничения используются nodeSelector и tolerations:

spec:
  template:
    spec:
      nodeSelector:
        node-type: monitoring
      tolerations:
        - key: node-role.kubernetes.io/control-plane
          operator: Exists
          effect: NoSchedule

tolerations позволяют запускать Pod на control plane узлах с taint NoSchedule по умолчанию.

Стратегии обновления DaemonSet

spec:
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1

Типичные use cases для DaemonSet

  • Сбор логов: Fluentd, Filebeat, Fluent Bit
  • Мониторинг: Prometheus Node Exporter, Datadog Agent
  • Сетевые плагины: Calico, Cilium, Weave
  • Хранилища: Ceph, Longhorn агенты

Когда использовать

StatefulSet — стабильная идентичность Pod (имя, DNS) или собственное хранилище: БД, очереди, кластеризованные системы, важный порядок запуска/остановки.

DaemonSet — агент на каждом узле: логирование, мониторинг, сетевые агенты, storage agents.

Deployment — stateless, взаимозаменяемые Pod.

Типичные ошибки

StatefulSet без Headless Service. serviceName должен ссылаться на существующий Headless Service. Без него Pod создадутся, но DNS-записи для них — нет.

Удалить StatefulSet, ожидая удаления PVC. PVC не удаляются автоматически — это защита данных. Удаляй PVC вручную после StatefulSet.

Scale down ждёт по одному Pod. Идёт последовательно pod-2 → pod-1. Для Kafka, Cassandra убедись, что данные реплицированы перед уменьшением реплик.

DaemonSet без resource limits. Агент на каждом узле без limits может монополизировать ресурсы. Всегда задавай requests и limits.

DaemonSet вместо Deployment с nodeSelector. DaemonSet не позволяет задать replicas. Если нужно "N Pod на узлах с label X" — это Deployment с nodeSelector + HPA.

Альтернативы

Helm charts для stateful приложений (Bitnami charts для PostgreSQL, Redis, Kafka) — production-ready StatefulSet с probes, limits, backup.

Операторы — для сложных stateful систем (PostgreSQL Operator, Kafka Operator) предоставляют CRD и управляют репликацией, failover, backup.

Native sidecar containers вместо DaemonSet — alpha в 1.28, beta on-by-default в 1.29, stable в 1.33. Для logging-агентов с изоляцией по namespace можно запускать sidecar в Pod приложения вместо node-wide DaemonSet (глава 02).


10: Probes

12: Job и CronJob

StatefulSet и DaemonSet | Aleksandr Suprun