Часть 11 из серии статей об изучении k8s!

Указатель всей серии

  1. Основы k8s
  2. Создать кластер k8s одной командой
  3. Первое размещение контейнера в k8s
  4. Зачем нам Pod
  5. Важные поля конфигурации модуля
  6. Под проектные объемы
  7. Проверка работоспособности и восстановление pod-контейнера
  8. Модель контроллера k8s
  9. Развертывание k8s
  10. Топология с отслеживанием состояния k8s

В прошлой статье я рассказал, как StatefulSet гарантирует топологическое состояние экземпляра приложения и поддерживает его стабильность в процессе удаления и повторного создания Pod. В этой статье я расскажу о механизме управления StatefulSet для состояния хранилища.

Требование постоянного объема

Ранее я упоминал, что чтобы объявить Volume в модуле, вы просто добавляете поле spec.volumes в модуль. Затем вы можете определить в этом поле определенный тип объема, например hostPath. Но что, если вы не знаете, какие типы томов использовать? В частности, как разработчик приложения вы можете даже ничего не знать о проектах постоянного хранения (таких как Ceph, GlusterFS и т. Д.), А также не знаете, как построен кластер k8s в вашей компании, и вы, вероятно, не знаете не нужно знать. Например, давайте посмотрим на Ceph RBD тип объема:

apiVersion: v1
kind: Pod
metadata:
  name: rbd
spec:
  containers:
    - image: kubernetes/pause
      name: rbd-rw
      volumeMounts:
      - name: rbdpd
        mountPath: /mnt/rbd
  volumes:
    - name: rbdpd
      rbd:
        monitors:
        - '10.16.154.78:6789'
        - '10.16.154.82:6789'
        - '10.16.154.83:6789'
        pool: kube
        image: foo
        fsType: ext4
        readOnly: true
        user: admin
        keyring: /etc/ceph/keyring
        imageformat: "2"
        imagefeatures: "layering"

Очевидно, если вы не знаете Ceph RBD, вы понятия не имеете, что означает приведенный выше YAML. И адрес, имя пользователя и авторизованное расположение файла сервера хранения, соответствующего этому Ceph RBD, также отображаются через файл YAML. Это типичный пример «передержки» информации.

Вот почему в более поздней версии k8s был представлен набор объектов API, называемых Persistent Volume Claim (PVC) и Persistent Volume (PV), что значительно снизило порог для пользователей, позволяющих объявлять и использовать постоянный том.

Например, с PVC и PV разработчик может легко определить объект Volume в k8s:

  • Определите PVC и объявите атрибуты желаемого тома
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pv-claim
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
  • В приложении Pod заявите об использовании этого PVC:
apiVersion: v1
kind: Pod
metadata:
  name: pv-pod
spec:
  containers:
    - name: pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: pv-storage
  volumes:
    - name: pv-storage
      persistentVolumeClaim:
        claimName: pv-claim

Как видите, в приведенном выше определении нам нужно только объявить его тип persistentVolumeClaim, а затем указать имя PVC, не заботясь об определении самого Volume. На этом этапе, пока вы создаете этот объект PVC, k8s автоматически привяжет к нему квалифицированный том.

Но вы можете спросить, откуда взялись квалифицированные Volume?

Ответ - это объекты PV (Persistent Volume), поддерживаемые командой DevOps. Давайте посмотрим на определение PV:

kind: PersistentVolume
apiVersion: v1
metadata:
  name: pv-volume
  labels:
    type: local
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  rbd:
    monitors:
    - '10.17.164.78:6789'
    - '10.17.164.82:6789'
    - '10.17.164.83:6789'
    pool: kube
    image: foo
    fsType: ext4
    readOnly: true
    user: admin
    keyring: /etc/ceph/keyring

Это определение размером 10 ГБCeph RBD Volume. Таким образом, k8s свяжет этот PV с PVC объектом, который вы только что создали. Следовательно, конструкция PVC и PV в k8s фактически аналогична идее «интерфейса» и «реализации». Разработчикам нужно только знать и использовать «интерфейс», а именно: PVC; а DevOps несут ответственность за привязку конкретной реализации: PV.

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

Хранение StatefulSet

Давайте воспользуемся тем же StatefulSet примером из моей последней статьи Топология k8s StatefulSet:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.9.1
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 2Gi

На этот раз мы добавили дополнительное поле volumeClaimTemplates в этот StatefulSet YAML. Как видно из названия, он похож на шаблон Pod в Deployment. Другими словами, все модули, управляемые этим StatefulSet, объявят соответствующий PVC; и определение этого PVC происходит из поля шаблона volumeClaimTemplates. Что еще более важно, имени PVC будет присвоен номер, точно такой же, как у Pod.

После того, как PVC будет успешно привязан к PV, он войдет в состояние Bound, что означает, что Pod можно смонтировать и использовать PV.

Если вы все еще не понимаете PVC, запомните следующий вывод: PVC на самом деле представляет собой особый том. Просто какой тип тома PVC, вы можете узнать только после того, как он будет привязан к PV.

Итак, после того, как мы используем kubectl create для создания StatefulSet, мы увидим, что в кластере k8s появятся два PVC:

$ kubectl create -f statefulset_example.yaml
$ kubectl get pvc -l app=nginx
NAME        STATUS    VOLUME         CAPACITY   ACCESSMODES   AGE
www-web-0   Bound     pvc-15c268c7   2Gi        RWO           48s
www-web-1   Bound     pvc-15c79307   2Gi        RWO           48s

Мы видим, что оба PVC находятся в состоянии Bound. Pod web-0 будет использовать www-web-0 PVC и смонтировать свой PV. То же самое для Pod web-1.

Теперь, если вы записываете файлы на том Pod, они будут сохранены в его PV.

Что еще более важно, даже если вы удалите два модуля с помощью команды kubectl delete, эти файлы на томе будут постоянными и будут доступны для новых модулей.

Постоянное хранилище подов

Давайте подробнее рассмотрим, почему файлы на томе являются постоянными.

Прежде всего, когда вы удаляете Pod, например web-0, PVC и PV, соответствующие этому модулю, не будут удалены, а данные, которые были записаны в этот том, будут по-прежнему храниться в служба удаленного хранения.

После удаления модуля контроллер StatefulSet обнаружит, что модуль с именем web-0 исчез. Следовательно, контроллер воссоздает новый Pod с именем web-0, чтобы «исправить» это несоответствие. В определении этого нового Pod объекта имя PVC, которое он объявляет, по-прежнему называется: www-web-0. Поскольку определение этого PVC по-прежнему происходит из шаблона PVC (volumeClaimTemplates), который является стандартным процессом для StatefulSet создания Pod.

Следовательно, после создания этого нового модуля web-0, когда k8s ищет для него PVC с именем www-web-0, он все равно найдет те же самыеPVC и PV.

Заключение

Прежде всего, StatefulSet controller напрямую управляет модулями. Это потому, что разные экземпляры Pod в StatefulSet немного отличаются в ReplicaSet. StatefulSet отличает эти экземпляры путем добавления заранее определенного числа к имени модуля.

Во-вторых, k8s использует Headless Service для создания записей DNS с тем же номером на DNS-сервере для этих пронумерованных модулей. Пока StatefulSet может гарантировать, что числа в именах модулей остаются неизменными, записи DNS, аналогичные web-0.nginx.default.svc.cluster.local в службе, также не изменятся, а данные модуля будут проанализированы из эта запись не изменится.

В-третьих, StatefulSet также выделяет и создает PVC с тем же номером для каждого Pod. Таким образом, k8s может связать соответствующий PV с этим PVC через механизм постоянного тома, тем самым гарантируя, что каждый под имеет независимый том. В этом случае, даже если Pod будет удален, соответствующие PVC и PV все равно будут сохранены. Таким образом, когда Pod воссоздан, k8s найдет PVC с тем же номером для него, смонтирует том, соответствующий этому PVC, и получит данные, ранее сохраненные в томе.

StatefulSet на самом деле представляет собой особый вид развертывания, и его уникальная особенность состоит в том, что каждый из его подов пронумерован. Более того, этот номер будет отражен в идентификационной информации, такой как имя модуля и имя хоста. Это не только представляет собой порядок создания Pod, но и важный сетевой идентификатор для Pod (то есть уникальный и доступный идентификатор во всем кластере).

С этим механизмом StatefulSet использует две стандартные функции в k8s: Headless Service и PV/PVC для реализации состояния топологии и состояния хранилища Pod.

Надеюсь, вам понравилась моя статья, и до встречи в следующей!

Больше контента на plainenglish.io