Поиск по сайту:

Что такое StatefulSets в Kubernetes? Когда вы должны их использовать?


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

StatefulSet может развертывать приложения, которым необходимо надежно идентифицировать конкретные реплики, развертывать обновления в заранее определенном порядке или стабильно получать доступ к томам хранилища. Они применимы ко многим различным вариантам использования, но чаще всего используются для баз данных и других типов постоянных хранилищ данных.

В этой статье вы узнаете, что такое StatefulSets, как они работают и когда их следует использовать. Мы также рассмотрим их ограничения и ситуации, когда лучше использовать другие объекты Kubernetes.

Что такое наборы состояний?

Делая поды частью StatefulSet, вы даете Kubernetes указание планировать и масштабировать их гарантированным образом. Каждому поду присваивается уникальный идентификатор, который сохраняется за любым замещающим подом.

К имени пода добавляется порядковый индекс, который определяет его порядок во время операций планирования. StatefulSet с именем mysql, содержащий три реплики, создаст следующие именованные поды:

  • mysql-1
  • mysql-2
  • mysql-3

Поды используют свои имена в качестве имени хоста, поэтому другие службы, которым необходим надежный доступ ко второй реплике StatefulSet, могут подключаться к mysql-2. Даже если конкретный под, который запускает mysql-2, будет перенесен позже, его идентификатор перейдет к его замене.

StatefulSets также обеспечивает удаление модулей в порядке, обратном их созданию. Если StatefulSet уменьшен до одной реплики, mysql-3 гарантированно выйдет первым, а затем mysql-2. Это поведение не применяется, когда весь StatefulSet удален, и его можно отключить, задав для поля podManagementPolicy StatefulSet значение Parallel.

Варианты использования StatefulSet

StatefulSets обычно используются для запуска реплицированных приложений, в которых отдельные поды имеют разные роли. Например, вы можете развернуть базу данных MySQL с основным экземпляром и двумя репликами только для чтения. Обычный ReplicaSet или Deployment не подходят, потому что вы не можете надежно идентифицировать модуль, на котором запущена первичная реплика.

StatefulSet решает эту проблему, гарантируя, что каждый Pod в ReplicaSet сохраняет свою идентичность. Другие ваши службы могут надежно подключаться к mysql-1 для взаимодействия с первичной репликой. Наборы реплик также обеспечивают запуск новых подов только тогда, когда работает предыдущий под. Это гарантирует, что реплики только для чтения будут созданы после того, как основная реплика будет запущена и готова предоставить свои данные.

Целью StatefulSets является размещение невзаимозаменяемых реплик внутри Kubernetes. В то время как поды в приложении без сохранения состояния эквивалентны друг другу, рабочие нагрузки с отслеживанием состояния требуют преднамеренного подхода к развертыванию, масштабированию и завершению.

StatefulSets интегрируются с локальными постоянными томами для поддержки постоянного хранилища, привязанного к каждой реплике. Каждый под получает доступ к своему собственному тому, который будет автоматически повторно присоединен, когда реплика будет перенесена на другой узел.

Создание StatefulSet

Вот пример манифеста YAML, который определяет набор с отслеживанием состояния для запуска MySQL с основным узлом и двумя репликами:

apiVersion: v1
kind: Service
metadata:
  name: mysql
  labels:
    app: mysql
spec:
  ports:
    - name: mysql
      port: 3306
  clusterIP: None
  selector:
    app: mysql
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  serviceName: mysql
  replicas: 3
  template:
    metadata:
      labels:
        app: mysql
    spec:
      initContainers:
      - name: mysql-init
        image: mysql:8.0
        command:
        - bash
        - "-c"
        - |
          set -ex
          [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
          ordinal=${BASH_REMATCH[1]}
          echo [mysqld] > /mnt/conf/server-id.cnf
          # MySQL doesn't allow "0" as a `server-id` so we have to add 1 to the Pod's index
          echo server-id=$((1 + $ordinal)) >> /mnt/conf/server-id.cnf
          if [[ $ordinal -eq 0 ]]; then
            printf "[mysqld]\nlog-bin" > /mnt/conf/primary.cnf
          else
            printf "[mysqld]\nsuper-read-only" /mnt/conf/replica.cnf
          fi          
        volumeMounts:
        - name: config
          mountPath: /mnt/conf
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ALLOW_EMPTY_PASSWORD
          value: "1"
        ports:
        - name: mysql
          containerPort: 3306
        volumeMounts:
        - name: config
          mountPath: /etc/mysql/conf.d
        - name: data
          mountPath: /var/lib/mysql
          subPath: mysql
        livenessProbe:
          exec:
            command: ["mysqladmin", "ping"]
          initialDelaySeconds: 30
          periodSeconds: 5
          timeoutSeconds: 5
        readinessProbe:
          exec:
            command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 1
      volumes:
      - name: config
        emptyDir: {}
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi

Это довольно длинный манифест, поэтому давайте раскроем, что происходит.

  • Безголовая служба создается путем установки для ее clusterIP значения None. Он привязан к StatefulSet и предоставляет сетевые идентификаторы для своих модулей.
  • StatefulSet создается для хранения модулей MySQL. Поле replicas указывает, что будут запущены три модуля. На автономную службу ссылается поле serviceName.
  • В StatefulSet создается контейнер инициализации, который предварительно заполняет файл внутри каталога конфигурации, смонтированного с использованием постоянного тома. Контейнер запускает сценарий Bash, который устанавливает порядковый номер работающего пода. Когда индекс равен 0, Pod создается первым в StatefulSet, поэтому он становится основным узлом MySQL. Остальные поды настроены как реплики. Соответствующий файл конфигурации записывается в том, откуда впоследствии он будет доступен для контейнера MySQL.
  • Контейнер MySQL создается с томом конфигурации, подключенным к правильному каталогу MySQL. Это гарантирует, что экземпляр MySQL будет настроен либо как основной, либо как реплика, в зависимости от того, будет ли он первым запускаться в StatefulSet.
  • Проверки работоспособности и готовности используются для определения готовности экземпляра MySQL. Это предотвращает запуск следующих друг за другом подов в StatefulSet до тех пор, пока не будет запущен предыдущий, гарантируя, что реплики MySQL не будут существовать до того, как будет запущен основной узел.

Обычный Deployment или ReplicaSet не может реализовать этот рабочий процесс. Как только ваши поды запустятся, вы можете масштабировать StatefulSet вверх или вниз, не рискуя разрушить первичный узел MySQL. Kubernetes гарантирует соблюдение установленного порядка подов.

# Create the MySQL StatefulSet
$ kubectl apply -f mysql-statefulset.yaml

# Scale up to 5 Pods - a MySQL primary and 4 MySQL replicas
$ kubectl scale statefulset mysql --replicas=5

Последовательные обновления

StatefulSet реализует скользящие обновления, когда вы меняете их спецификацию. Контроллер StatefulSet заменит каждый Pod в последовательном обратном порядке, используя постоянно назначенные порядковые индексы. Сначала будет удален и заменен mysql-3, затем mysql-2 и mysql-1. mysql-2 не будет обновляться до тех пор, пока новый модуль mysql-3 не перейдет в состояние Running.

Механизм непрерывного обновления также включает поддержку поэтапного развертывания. Установка поля .spec.updateStrategy.rollingUpdate.partition в манифесте StatefulSet указывает Kubernetes обновлять только модули с порядковым индексом, большим или равным данному разделу.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  serviceName: mysql
  replicas: 3
  updateStrategy:
    rollingUpdate:
      partition: 1
  template:
    ...
  volumeClaimTemplates:
    ...

В этом примере операции обновления будут нацелены только на модули с индексом 1 или выше. Первый под в StatefulSet не получит новую спецификацию, пока раздел не будет понижен или удален.

Ограничения

У StatefulSets есть некоторые ограничения, о которых вы должны знать, прежде чем использовать их. Эти распространенные ошибки могут сбить вас с толку, когда вы начнете развертывать приложения с отслеживанием состояния.

  • Удаление StatefulSet не гарантирует, что поды будут закрыты в порядке, указанном их идентификаторами.
  • Удаление StatefulSet или уменьшение количества его реплик не приведет к удалению связанных томов. Это защищает от случайной потери данных.
  • Использование последовательных обновлений может создать ситуацию, при которой возникает недопустимое неисправное состояние. Это происходит, когда вы предоставляете конфигурацию, которая никогда не переходит в состояние «Работает» или «Готово» из-за проблемы с вашим приложением. Возврат к хорошей конфигурации не решит проблему, потому что Kubernetes неопределенно долго ждет, пока плохой под станет готовым. Вы должны вручную разрешить ситуацию, удалив ожидающие или неудавшиеся поды.

В StatefulSets также отсутствует механизм изменения размера томов, связанных с каждым подом. Вам нужно вручную отредактировать каждый постоянный том и соответствующее ему утверждение постоянного тома, а затем удалить StatefulSet и осиротить его поды. Создание нового StatefulSet с измененной спецификацией позволит Kubernetes восстановить потерянные модули и изменить размер томов.

Когда не следует использовать StatefulSet

Вы должны использовать StatefulSet только тогда, когда отдельные реплики имеют свое собственное состояние. StatefulSet не нужен, когда все реплики имеют одно и то же состояние, даже если оно постоянное.

В этих ситуациях вы можете использовать обычный ReplicaSet или Deployment для запуска своих модулей. Любые подключенные тома будут совместно использоваться всеми модулями, что является ожидаемым поведением для систем без сохранения состояния.

StatefulSet не добавляет ценности, если вам не нужны индивидуальные постоянные хранилища или идентификаторы липких реплик. Неправильное использование StatefulSet может вызвать путаницу, предполагая, что поды сохраняют состояние, хотя на самом деле они выполняют рабочую нагрузку без сохранения состояния.

Краткое содержание

StatefulSets предоставляют постоянные удостоверения для реплицированных модулей Kubernetes. Каждому поду присваивается порядковый индекс, который назначается последовательно. Когда Pod перепланируется, его замена наследует его идентичность. StatefulSet также гарантирует, что поды будут завершены в порядке, обратном их созданию.

StatefulSets позволяет Kubernetes размещать приложения, требующие плавного непрерывного развертывания, стабильных сетевых идентификаторов и надежного доступа к постоянному хранилищу. Они подходят для любой ситуации, когда реплики в наборе подов имеют собственное состояние, которое необходимо сохранить.

StatefulSet не нужно использовать, если ваши реплики не имеют состояния, даже если они хранят некоторые постоянные данные. Развертывания и наборы реплик больше подходят, когда отдельные реплики не нужно идентифицировать или масштабировать в согласованном порядке.




Все права защищены. © Linux-Console.net • 2019-2024