Простое руководство по реализации постоянного хранилища в Kubernetes
В мире оркестрации контейнеров Kubernetes превосходно справляется с управлением stateless-приложениями – теми, которым не нужно сохранять данные между перезапусками или событиями масштабирования. Однако многие современные приложения, такие как базы данных, очереди сообщений и хранилища ключ-значение, по своей природе stateful. Этим приложениям требуется надежный способ постоянного хранения и доступа к данным, даже если Pod'ы, на которых они работают, переносятся или заменяются. Именно здесь в игру вступает постоянное хранилище Kubernetes.
Это руководство разъяснит концепции PersistentVolumes (PV) и PersistentVolumeClaims (PVC), которые являются основными компонентами для управления постоянным хранилищем в Kubernetes. Мы рассмотрим, как определять, запрашивать и связывать хранилище с вашими Pod'ами с помощью практических примеров YAML, что позволит вам уверенно развертывать stateful-приложения в вашем кластере Kubernetes.
Понимание PersistentVolumes (PV) и PersistentVolumeClaims (PVC)
Прежде чем приступить к реализации, крайне важно понять роли PV и PVC:
- PersistentVolume (PV): PV – это часть хранилища в кластере, которая была выделена администратором или динамически выделена с использованием StorageClass. PV являются ресурсами кластера, подобно Node'ам. Их жизненный цикл не зависит от любого отдельного Pod'а, использующего PV. PV абстрагируют детали реализации базового хранилища (например, NFS, iSCSI, блочное хранилище облачного провайдера).
- PersistentVolumeClaim (PVC): PVC – это запрос пользователя на хранилище. Он потребляет ресурсы хранилища, доступные в кластере в виде PV. PVC аналогичны Pod'ам тем, что они потребляют вычислительные ресурсы, и они ограничены пространством имен (namespace). PVC указывает желаемую емкость хранилища, режимы доступа и, опционально, StorageClass.
Такое разделение обязанностей позволяет администраторам кластера выделять и управлять ресурсами хранилища независимо, в то время как разработчики приложений могут запрашивать хранилище, не зная деталей базовой реализации.
Ключевые концепции: Режимы доступа и StorageClass
Две важные концепции, которые следует понять при работе с PV и PVC, это режимы доступа (Access Modes) и StorageClass:
Режимы доступа
Режимы доступа определяют, как том может быть подключен к Pod'у. Доступные режимы доступа:
ReadWriteOnce(RWO): Том может быть подключен для чтения-записи одним узлом.ReadOnlyMany(ROX): Том может быть подключен только для чтения многими узлами.ReadWriteMany(RWX): Том может быть подключен для чтения-записи многими узлами.
Важно отметить, что фактическая поддержка этих режимов зависит от базового поставщика хранилища.
StorageClass
StorageClass предоставляет администраторам способ описания «классов» хранилища, которые они предлагают. Различные классы могут соответствовать уровням качества обслуживания, политикам резервного копирования или произвольным политикам, определяемым администраторами кластера. StorageClass имеет провижионер (provisioner), который выделяет хранилище, и набор параметров для этого провижионера. Когда PVC создается без указания конкретного PV и запрашивает StorageClass, Kubernetes динамически выделяет PV, используя указанный StorageClass.
Реализация постоянного хранилища: Пошаговое руководство
Рассмотрим распространенный сценарий: запрос и использование постоянного хранилища для Pod'а.
Шаг 1: Определение PersistentVolumeClaim (PVC)
Сначала вам нужно создать PVC, который определяет ваши требования к хранилищу. Этот PVC будет действовать как запрос на хранилище от вашего приложения.
Пример pvc.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
В этом примере:
name: my-pvc: Это имя нашего PVC.accessModes: - ReadWriteOnce: Мы запрашиваем хранилище, которое может быть подключено для чтения-записи одним узлом.resources.requests.storage: 1Gi: Мы запрашиваем 1 гигабайт хранилища.
Применение PVC:
Сохраните приведенное выше содержимое в файл с именем pvc.yaml и примените его к вашему кластеру:
kubectl apply -f pvc.yaml
После применения вы можете проверить статус PVC:
kubectl get pvc my-pvc
Вы должны увидеть вывод, указывающий, что PVC находится в состоянии Bound (связан), если подходящий PV доступен или был динамически выделен.
Шаг 2: Создание Pod'а, использующего PVC
Теперь давайте создадим Pod, который будет использовать хранилище, запрошенное нашим PVC. Мы подключим том, предоставленный PVC, в определенную директорию внутри нашего контейнера.
Пример pod-with-pv.yaml:
apiVersion: v1
kind: Pod
metadata:
name: my-stateful-pod
spec:
containers:
- name: my-container
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: my-persistent-storage
mountPath: /usr/share/nginx/html
volumes:
- name: my-persistent-storage
persistentVolumeClaim:
claimName: my-pvc
В этом примере:
volumes: Мы определяем том с именемmy-persistent-storage.persistentVolumeClaim.claimName: my-pvc: Это связывает наш том с PVC, который мы создали ранее.volumeMounts: Внутри определения контейнера мы указываем, куда этот том должен быть подключен (mountPath: /usr/share/nginx/html).
Применение Pod'а:
Сохраните приведенное выше содержимое в файл с именем pod-with-pv.yaml и примените его:
kubectl apply -f pod-with-pv.yaml
Теперь ваш контейнер nginx будет иметь доступ к постоянному хранилищу, определенному my-pvc, по пути /usr/share/nginx/html. Любые данные, записанные по этому пути внутри контейнера, будут сохраняться, даже если Pod будет удален и воссоздан, при условии, что PVC и его базовый PV останутся.
Динамическое выделение с использованием StorageClass
Ручное создание PV может быть громоздким. Kubernetes предлагает динамическое выделение (dynamic provisioning), при котором PV создаются автоматически, когда PVC запрашивает хранилище, которое не может быть удовлетворено существующими PV. Это достигается с помощью StorageClass.
Большинство облачных провайдеров (AWS, GCP, Azure) предлагают предварительно настроенные StorageClass. Вы можете проверить их с помощью:
kubectl get storageclass
Чтобы использовать динамическое выделение, просто добавьте поле storageClassName в определение вашего PVC:
Пример pvc-dynamic.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-dynamic-pvc
spec:
storageClassName: standard # Replace 'standard' with an actual StorageClass name
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
Когда вы применяете этот PVC, Kubernetes будет искать StorageClass с именем standard (или любым другим именем, которое вы укажете) и поручит его провижионеру создать новый PV размером 5Gi и привязать его к этому PVC.
Советы и лучшие практики
- Выбирайте правильный режим доступа: Тщательно продумайте режим доступа, необходимый вашему приложению.
ReadWriteOnceобычно используется для баз данных с одной репликой, тогда какReadWriteManyнеобходим для общих файловых систем, используемых несколькими Pod'ами. - Понимайте производительность хранилища: Различные поставщики хранилищ и StorageClass предлагают разные характеристики производительности (IOPS, пропускная способность). Выбирайте StorageClass, который соответствует потребностям вашего приложения в производительности.
- Стратегия резервного копирования: Постоянное хранилище не означает автоматическое резервное копирование. Реализуйте надежную стратегию резервного копирования для ваших постоянных томов, особенно для критически важных данных.
- Политика высвобождения PV: PV имеют
reclaimPolicy, которая может бытьDelete(по умолчанию),RetainилиRecycle(устарела).Retainполезен для обеспечения того, чтобы данные не были потеряны, если PV удален, но базовое хранилище все еще существует. - Особенности пространства имен: PVC'ы привязаны к пространству имен. Убедитесь, что ваш Pod и PVC находятся в одном пространстве имен для выполнения связывания.
Заключение
Реализация постоянного хранилища является фундаментальным требованием для запуска stateful-приложений в Kubernetes. Понимая и используя PersistentVolumes и PersistentVolumeClaims, а также гибкость StorageClass, вы можете надежно управлять данными вашего приложения. Это руководство предоставило базовые знания и практические примеры, чтобы помочь вам начать работу, позволяя развертывать более сложные и отказоустойчивые stateful-нагрузки в Kubernetes.