Что такое StatefulSet в Kubernetes?

Ответ

StatefulSet — это контроллер рабочей нагрузки в Kubernetes, предназначенный для развертывания и управления stateful-приложениями, которым требуется сохранение состояния, стабильные сетевые идентификаторы и гарантированный порядок развертывания.

Ключевые отличия от Deployment:

  • Стабильные идентификаторы подов: Каждому поду присваивается предсказуемое и неизменяемое имя (например, app-0, app-1), которое сохраняется при перезапуске.
  • Стабильное сетевое имя: Каждый под получает DNS-имя по шаблону: $(pod-name).$(service-name).$(namespace).svc.cluster.local.
  • Упорядоченное развертывание и масштабирование: Поды создаются и удаляются последовательно (от 0 до N-1), что критично для кластерных приложений.
  • Устойчивое хранилище: Используя volumeClaimTemplates, каждому поду выделяется свой уникальный PersistentVolumeClaim (PVC). При пересоздании пода он подключается к тому же тому.

Типичные сценарии использования:

  • Кластеры баз данных (MySQL, PostgreSQL, MongoDB).
  • Системы обмена сообщениями (Kafka, RabbitMQ).
  • Кэши и хранилища данных (Redis, Elasticsearch, Cassandra).

Пример манифеста для StatefulSet с MySQL:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql-hs # Обязательно указывается Headless Service
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
  volumeClaimTemplates: # Шаблон для создания PVC для каждого пода
  - metadata:
      name: mysql-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi

Ответ 18+ 🔞

А, StatefulSet! Ну это, блядь, такая штука в кубере, когда твоему приложению нельзя просто так взять и переехать на новое место, как бомжу под мостом. Ему там своя койка нужна, свой шкафчик и имя, чтобы не путали с другими.

Если простыми словами — это для тех приложений, которые помнят. Ну, как бабушка, которая тебя в детстве по попе шлёпала, и ты до сих пор не можешь спокойно слышать звук ремня. Им нужно состояние сохранять, сеть стабильную и чтоб всё по порядку.

Чем он от обычного Deployment отличается, ёпта?

  • Имена подов — на века. Тут не будет этих рандомных app-xyz123. Тут всё чинно-благородно: app-0, app-1. Перезапустился под — имя его не меняется. Как паспорт, блядь. Удобно.
  • Сеть тоже не подведёт. У каждого пода свой собственный адрес в сети, по которому его можно найти. Типа mysql-1.mysql-service.default.svc.cluster.local. Предсказуемо, как восход солнца после хорошей пьянки.
  • Порядок — всё. Создаются и удаляются они строго по очереди: сначала нулевой, потом первый и так далее. Нельзя второго запустить, пока первый не встал как вкопанный. И наоборот, при удалении — сначала последнего грохнут. Это чтобы в кластерах, типа баз данных, не было каши в репликации.
  • Диски — родные. Самое сокровенное. Каждому поду через volumeClaimTemplates выдают его личный, именной жесткий диск (PersistentVolumeClaim). Упал под, воскрес — а данные его ждут. Как верная собака. В Deployment'е же при пересоздании под прикручивается новый, пустой том, и все твои гигабайты логов накрываются медным тазом.

Где эту хрень использовать? Да везде, где приложение не тупая статика, а хитрая жопа со своим характером:

  • Базы данных всякие (MySQL, Postgres, Mongo) — им же репликацию настраивать надо.
  • Очереди сообщений (Kafka, RabbitMQ) — там тоже свой порядок важен.
  • Разные Elasticsearch, Redis, Cassandra — короче, всё, что stateful.

Вот тебе пример, как это выглядит, на случай MySQL:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql-hs # Вот это ОБЯЗАТЕЛЬНО! Без Headless Service — нихуя не заработает.
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
  volumeClaimTemplates: # А вот это магия! Для каждого пода свой PVC создаст.
  - metadata:
      name: mysql-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi

Короче, если твоё приложение — не безмозглая статика, а что-то посерьёзнее, что данные терять не хочет, то StatefulSet — твой выбор. Просто помни, что это овердохуища ответственности: удалишь StatefulSet не глядя — и твои PVC с данными могут остаться висеть сиротами, если специально не почистишь. Так что, э, бошка думай, прежде чем что-то делать.