Перейти к основному содержимому

Развертывание Kubernetes против StatefulSets

· 11 мин. чтения

1. Обзор

Kubernetes (K8s) — это система оркестрации контейнеров с открытым исходным кодом. Это позволяет нам автоматизировать развертывание, масштабирование и управление контейнерными приложениями.

В этом руководстве мы обсудим два разных способа развертывания нашего приложения (модулей) в Kubernetes с использованием разных ресурсов Kubernetes. Ниже приведены два разных ресурса, которые Kubernetes предоставляет для развертывания модулей:

Давайте начнем с рассмотрения разницы между приложением с сохранением состояния и приложением без сохранения состояния.

2. Приложения с сохранением состояния и без сохранения состояния

Ключевое различие между приложениями с сохранением состояния и приложениями без сохранения состояния заключается в том, что приложения без сохранения состояния не «хранят» данные. С другой стороны, для приложений с отслеживанием состояния требуется резервное хранилище . Например, такие приложения, как базы данных Cassandra, MongoDB и MySQL, требуют определенного типа постоянного хранилища, чтобы выдерживать перезапуски службы.

Сохранение состояния имеет решающее значение для запуска приложения с отслеживанием состояния. Но для службы без сохранения состояния любой поток данных обычно является временным. Кроме того, состояние хранится только в отдельной серверной службе, такой как база данных. Любое связанное хранилище обычно является эфемерным. Например, если контейнер перезапускается, все сохраненное теряется. По мере того как организации внедряют контейнеры, они, как правило, начинают с контейнеров без сохранения состояния, поскольку их легче внедрить.

Kubernetes хорошо известен тем, что управляет сервисами без сохранения состояния. Рабочая нагрузка развертывания больше подходит для работы с приложениями без сохранения состояния. Что касается развертывания, модули взаимозаменяемы. В то время как StatefulSet сохраняет уникальный идентификатор для каждого модуля, которым он управляет. Он использует один и тот же идентификатор всякий раз, когда ему нужно перепланировать эти модули. В этой статье мы обсудим это подробнее.

3. Развертывание

3.1. Понимание развертывания : основы

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

Сначала мы определяем наше развертывание Kubernetes, а затем развертываем его. Затем Kubernetes будет работать над тем, чтобы все модули, управляемые развертыванием, соответствовали всем установленным нами требованиям. Развертывание — это супервизор для подов. Это дает нам детальный контроль над тем, как и когда развертывается новая версия модуля. Он также обеспечивает контроль, когда нам нужно откатиться к предыдущей версии.

В Kubernetes Deployment с репликой 1 контроллер проверит, равно ли текущее состояние желаемому состоянию ReplicaSet, т. е. 1. Если текущее состояние равно 0, он создаст ReplicaSet. ReplicaSet дополнительно создаст модули. Когда мы создаем развертывание Kubernetes с именем web-app , оно создаст ReplicaSet с именем web-app-<replica-set-id>. Эта реплика далее создаст модуль с именем web-app-<replica-set->-<pod-id> .

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

3.2. Компоненты развертывания в Kubernetes

Ниже приведены основные компоненты развертывания Kubernetes :

  • `Шаблон развертывания`
  • постоянный объем
  • обслуживание

Во-первых, давайте создадим наш шаблон развертывания и сохраним его как « deployment.yaml» . В приведенном ниже шаблоне мы также подключаем постоянный том:

apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-deployment
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2
maxUnavailable: 1
selector:
matchLabels:
app: web-app
replicas: 3
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app
image: hello-world:nanoserver-1809
volumeMounts:
- name: counter
mountPath: /app/
volumes:
- name: counter
persistentVolumeClaim:
claimName: counter

В приведенном ниже шаблоне у нас есть PersistentVolumeClaim :

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: counter
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Mi
storageClassName: default

3.3. Выполнение развертывания в Kubernetes

Прежде чем мы выполним наше развертывание , нам нужна служба для доступа к вышеуказанному развертыванию . Давайте создадим сервис типа NodePort и сохраним его как service.yaml :

apiVersion: v1
kind: Service
metadata:
name: web-app-service
spec:
ports:
- name: http
port: 80
nodePort: 30080
selector:
name: web-app
type: NodePort

Сначала мы запускаем шаблон службы с помощью следующей команды kubectl apply :

kubectl apply -f service.yaml

Затем мы запускаем ту же команду для шаблона развертывания:

kubectl apply -f deployment.yaml

Кроме того, чтобы получить подробное описание развертывания, запустим команду kubectl описать :

kubectl describe deployment web-app-deployment

Вывод будет примерно таким:

Name:                web-app-deployment
Namespace: default
CreationTimestamp: Tue, 30 Aug 2016 18:11:37 -0700
Labels: app=web-app
Annotations: deployment.kubernetes.io/revision=1
Selector: app=web-app
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 2 max surge
Pod Template:
Labels: app=web-app
Containers:
web-app:
Image: spring-boot-docker-project:1
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: web-app-deployment-1771418926 (3/3 replicas created)
No events.

В приведенном выше разделе мы наблюдаем, что Deployment внутри создает ReplicaSet . Затем внутри этого ReplicaSet создаются поды . В будущем, когда мы обновим текущее развертывание, оно создаст новый ReplicaSet . Затем он будет постепенно перемещать модули из старого набора реплик в новый с контролируемой скоростью.

Если при обновлении произойдет ошибка, новый ReplicaSet никогда не будет находиться в состоянии Ready. Старый ReplicaSet больше не прекратит работу, что гарантирует 100% безотказную работу в случае неудачного обновления. В Kubernetes Deployment мы также можем вручную выполнить откат к предыдущему набору реплик , если наша новая функция не работает должным образом.

4. Наборы состояний

4.1. Понимание StatefulSet s: основы

В Kubernetes Deployment мы относимся к нашим модулям как к крупному рогатому скоту, а не как к домашним животным. Если один из членов крупного рогатого скота заболеет или умрет, мы можем легко заменить его, купив новую голову. Такое действие незаметно. Точно так же, если один модуль выходит из строя, он запускает другой. В StatefulSet подам даются имена, и с ними обращаются как с домашними животными. Если кто-то из ваших питомцев заболел, это сразу заметно. То же самое и в случае с StatefulSet s , поскольку он взаимодействует с модулями по их имени.

StatefulSet предоставляет каждому поду два стабильных уникальных идентификатора. Во-первых, Network Identity позволяет нам назначать поду одно и то же DNS-имя независимо от количества перезапусков . IP-адреса могут по-прежнему отличаться, поэтому потребители должны полагаться на DNS-имя (или следить за изменениями и обновлять внутренний кеш).

Во- вторых, Storage Identity остается прежним . Network Identity всегда получает один и тот же экземпляр Storage, независимо от того, на каком узле он перепланирован.

StatefulSet также является контроллером, но в отличие от Kubernetes Deployment , он не создает ReplicaSet , а создает модуль с уникальным соглашением об именах. Каждый pod получает DNS-имя по шаблону: <statefulset name>-<ordinal index>. Например, для StatefulSet с именем mysql это будет mysql-0 .

Каждая реплика набора с отслеживанием состояния будет иметь свое собственное состояние, и каждый из модулей будет создавать свой собственный PVC (Persistent Volume Claim). Таким образом, StatefulSet с 3 репликами создаст 3 модуля, каждый из которых имеет собственный том, то есть всего 3 PVC. Поскольку StatefulSet работает с данными, мы должны быть осторожны при остановке экземпляров pod, предоставляя необходимое время для сохранения данных из памяти на диск. По-прежнему могут быть веские причины для принудительного удаления, например, при сбое узла Kubernetes.

4.2. Безголовый сервис

Для приложения с отслеживанием состояния требуются модули с уникальным идентификатором (именем хоста). Один модуль должен иметь доступ к другим модулям с четко определенными именами. Для работы StatefulSet требуется безголовая служба. Безголовая служба — это служба со служебным IP . Таким образом, он напрямую возвращает IP-адреса наших связанных модулей. Это позволяет нам напрямую взаимодействовать с модулями, а не через прокси. Это так же просто, как указать None для .spec.clusterIP.

Безголовая служба не имеет IP-адреса. Внутри он создает необходимые конечные точки для предоставления модулей с DNS-именами. Определение StatefulSet включает ссылку на безголовую службу, но мы должны создать ее отдельно.

4.3. Компоненты StatefulSet в Kubernetes

Ниже приведены основные компоненты StatefulSet s :

  • StatefulSet
  • постоянный объем
  • Безголовый сервис

Сначала мы создаем шаблон StatefulSet :

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumes:
- name: www
persistentVolumeClaim:
claimName: myclaim

Во-вторых, мы создаем PersistentVolume, упомянутый в шаблоне StatefulSet :

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi

Наконец, теперь мы создаем безголовый сервис для указанного выше StatefulSet :

apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx

4.4. Выполнение StatefulSet в Kubernetes

У нас есть готовые шаблоны для всех трех компонентов. Теперь давайте запустим команду create kubectl для создания StatefulSet :

kubectl create -f statefulset.yaml

Он создаст три модуля с именами web-0, web-1, web-2 . Мы можем проверить правильность создания с помощью get pods :

kubectl get pods
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 1m
web-1 1/1 Running 0 46s
web-2 1/1 Running 0 18s

Мы также можем проверить работающую службу:

kubectl get svc nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP None < none > 80/TCP 2m

StatefulSet не создает ReplicaSet , поэтому мы не можем откатить StatefulSet до предыдущей версии. Мы можем только удалить или увеличить/уменьшить Statefulset . Если мы обновим StatefulSet , он также выполнит RollingUpdate, т. е. один модуль реплики выйдет из строя, а обновленный модуль появится. Точно так же следующий модуль реплики выйдет из строя таким же образом.

Например, мы меняем изображение указанного выше StatefulSet . Сеть -2 завершится, и как только она завершится полностью, будет воссоздана сеть-2 , и в то же время будет завершена работа сети-1 . То же самое происходит для следующей реплики, т . е. web-0 . Если при обновлении произойдет ошибка, то только веб-2 будет недоступен, а веб-1 и веб-0 по- прежнему будут работать на предыдущей стабильной версии. В отличие от развертывания , мы не можем выполнить откат к какой-либо предыдущей версии StatefulSet .

Удаление и/или уменьшение StatefulSet не приведет к удалению томов, связанных с StatefulSet . Это обеспечивает безопасность данных, что, как правило, более ценно, чем автоматическая очистка всех связанных ресурсов StatefulSet . После удаления StatefulSets нет никаких гарантий по завершению подов. Чтобы добиться упорядоченного и корректного закрытия модулей в StatefulSet, перед удалением можно уменьшить StatefulSet до 0.

4.5. Использование StatefulSet

StatefulSet позволяет нам развертывать приложения с отслеживанием состояния и кластерные приложения. Они сохраняют данные в постоянном хранилище, таком как постоянные диски Compute Engine. Они подходят для развертывания Kafka, MySQL, Redis, ZooKeeper и других приложений (требующих уникальных, постоянных идентификаторов и стабильных имен хостов).

Например, кластер базы данных Solr управляется несколькими экземплярами Zookeeper. Чтобы такое приложение работало правильно, каждый экземпляр Solr должен знать об экземплярах Zookeeper, которые его контролируют. Точно так же экземпляры Zookeeper сами устанавливают соединения друг с другом для выбора главного узла. Благодаря такому дизайну кластеры Solr являются примером приложений с отслеживанием состояния. Другие примеры приложений с отслеживанием состояния включают кластеры MySQL, Redis, Kafka, MongoDB и другие. В таких сценариях используются StatefulSet .

5. Развертывание против StatefulSet s

Давайте посмотрим на основные различия между Deployment и StatefulSet :

      | **Развертывание**    | **StatefulSet**   | 
| Развертывание используется для развертывания приложений без сохранения состояния. | `StatefulSet` используется для развертывания приложений с отслеживанием состояния. |
| Капсулы взаимозаменяемы | Поддоны не взаимозаменяемы. Каждый модуль имеет постоянный идентификатор, который сохраняется при любом изменении расписания. |
| Имена подов уникальны | Имена подов идут в последовательном порядке |
| Сервис необходим для взаимодействия с модулями в развертывании. | Безголовая служба отвечает за сетевую идентификацию модулей. |
| Указанный объект PersistentVolumeClaim используется всеми репликами модуля. Другими словами, общий объем | Указаны шаблоны VolumeClaimTemplates, чтобы каждый модуль реплики получал связанный с ним уникальный объект PersistentVolumeClaim. Другими словами, нет общего тома |

Развертывание Kubernetes — это ресурсный объект в Kubernetes, который предоставляет декларативные обновления для приложений. Развертывание позволяет нам описать жизненный цикл приложения. Например, какие изображения использовать для приложения, сколько модулей должно быть и как их следует обновлять.

StatefulSet больше подходят для приложений с отслеживанием состояния . Для приложения с отслеживанием состояния требуются модули с уникальным идентификатором (например, именем хоста). Модуль сможет связаться с другими модулями с четко определенными именами. Для подключения к модулям требуется безголовая служба. Безголовая служба не имеет IP-адреса. Внутри он создает необходимые конечные точки для предоставления модулей с DNS-именами.

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

6. Заключение

В этом руководстве мы рассмотрели два способа развертывания в Kubernetes: Statefulset и Deployment . Мы увидели их основные характеристики и компоненты и, наконец, сравнили их.