Для работы с дисками для данных, которые должны храниться постоянно, Kubenetes предоставляет два типа ресурсов — PersistentVolume и PersistentVolumeClaim.
PersistentVolume — непосредственно система хранения, раздел на жёстком диске, например AWS EBS, подключенном к одному из AWS EC2, и с точки зрения этого кластера является таким же ресурсом как, например, Kubernetes Worker Node.
PersistentVolumeClaim — запрос от пользователя на использование такого диска, аналог Kubernetes pod — поды используют ресурсы Worker Node, а PVC — ресурсы PersistentVolume. По аналогии же с подами — поды запрашивают у рабочей ноды ЦПУ и память, а PVC — необходимый им размер диска, и тип доступа — ReadWriteOnce, ReadOnlyMany или ReadWriteMany, см. AccessModes.
PersistentVolume могут быть созданы двумя способами — динамически (рекомендуемый способ), и статически.
При статичном методе сначала создаётся набор дисков, например EBS, которые затем используются кластером для PersistentVolumeClaim.
В случе, если для PersistentVolumeClaim не удалось найди подходящий PV — кластер может создать отдельный PV конкретно для этого PVC — это и будет динамическое создание PVC.
При этом в PVC должен быть задан Storage Class, и такой класс должен поддерживаться кластером.
К примеру, для AWS EKS по-умолчанию создан StorageClassgp2:
kubectl get storageclass
NAME PROVISIONER AGE
gp2 (default) kubernetes.io/aws-ebs 64d
Содержание
Типы дисков
Для понимания роли PersistentVolume — рассмотрим доступные системы хранения:
Node-local хранение (emptyDir и hostPath)
Cloud volumes (например, awsElasticBlockStore, gcePersistentDisk и azureDiskVolume)
File-sharing volumes, такие как Network File System
Distributed-file systems (например, CephFS, RBD и GlusterFS)
специальные типы разделов, такие как PersistentVolumeClaim, secret и gitRepo
emptyDir и hostPath подключаются к подам, и хранят данные или в памяти, или на диске. Но т.к. они зависимы от подов, их содержимое доступно только пока работает контейнер, и когда контейнере останавливается — данные удаляются.
Cloud volumes, NFS и PersistentVolume разделы независимы от подов, и располагаются вне их.
Создание PersistentVolumeClaim
Static PersistentVolume provisioning
Создание EBS
При Static provisioning — сначала создаётся AWS EBS, и затем объект PersistentVolume, которому явно указывается использование этого EBS.
accessModes: типа доступа, тут ReadWriteOnce — раздел может быть смонтирован только к одной рабочей ноде с правами чтения/записи
storageClassName: тип хранилища, см. ниже
awsElasticBlockStore: тип используемого диска
fsType: тип файловой системы
volumeID: ID AWS EBS диска
Создаём PersistentVolume:
kubectl apply -f pv-static.yaml
persistentvolume/pv-static created
Проверяем:
kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-static 5Gi RWO Retain Available 69s
StorageClass
Параметр storageClassName определяет тип хранилища.
И для PVC, и для PV должен быть задан один и тот же класс, иначе PVC не подключит PV, и STATUS такого PVC будет Pending.
Если для PVC не задан StorageClass — будет использован дефолтный:
kubectl get storageclass -o wide
NAME PROVISIONER AGE
gp2 (default) kubernetes.io/aws-ebs 65d
При этом если StorageClass не указан для PV — он будет создан без указания класса, и PVC с классом по-умолчанию его не подключит, а выдаст ошибку «Cannot bind to requested volume «pvname»: storageClassName does not match«:
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning VolumeMismatch 12s (x17 over 4m2s) persistentvolume-controller Cannot bind to requested volume "pvname": storageClassName does not match
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-static Bound pv-static 5Gi RWO gp2 31s
Dynamic PersistentVolume provisioning
Динамическое создание PersistentVolume аналогично статическому с той разницей, что мы не создаём EBS, и не создаём отдельного ресурса PersistentVolume — вместо этого мы опишем PersistentVolumeClaim, который самостоятельно создаст EBS, и смонтирует его к EC2 WorkerNode:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-dynamic Pending gp2 45s
Но почему статус Pending? Смотрим события:
kubectl describe pvc pvc-dynamic
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal WaitForFirstConsumer 1s (x4 over 33s) persistentvolume-controller waiting for first consumer to be created before binding
Mounted By: <none>
WaitForFirstConsumer
Проверим ещё раз наш дефолтный StorageClass:
kubectl describe sc gp2
Name: gp2
IsDefaultClass: Yes
...
Provisioner: kubernetes.io/aws-ebs
Parameters: fsType=ext4,type=gp2
...
VolumeBindingMode: WaitForFirstConsumer
Events: <none>
Тут VolumeBindingMode определяет, как именно будет создаваться PersistentVolume. При значении Immediate — PV будет создан сразу же при появлении соотвествующего PVC, а при WaitForFirstConsumer — кластер сначала ожидает появления пода, который запросит этот PV, и затем, в зависимости от AvailbiltyZone рабочей ноды, на которой был запущен под, создёт PV.
Давайте создадим поды, которые будут использовать эти PVC.
Использование PersistentVolumeClaim в Pod
Dynamic PersistentVolumeClaim
Опишем под, который будет использовать наш dynamic PVC:
В таком случае, при создании пода, который использует этот PV — Kubernetes сначала проверит, к каким рабочим нодам этот PV можно подключить, и после запустит под на одной из доступных для этого PV ноде.
0s Normal Scheduled Pod Successfully assigned default/pv-static-pod to ip-10-3-47-58.us-east-2.compute.internal
0s Normal SuccessfulAttachVolume Pod AttachVolume.Attach succeeded for volume "pv-static"
0s Normal Pulling Pod Pulling image "nginx"
0s Normal Pulled Pod Successfully pulled image "nginx"
0s Normal Created Pod Created container pv-static-container
0s Normal Started Pod Started container pv-static-container
Удаление PersistentVolume и PersistentVolumeClaim
Когда пользователь удаляет PVC, который используется подом, этот PVC удаляется не сразу — удаление откладывается, пока не будет остановлен использующий его под.
Аналогично, при удалении PV, к которому есть binding от какого-либо PVC, этот PV тоже удаляется не сразу, до тех пор, пока существует связь между PVC и PV.
Когда пользователь заканчивает работу с PersistentVolume, он может удалить его объект из кластера, что бы освободить ресурс AWS EBS (reclaim).
Reclaim policy для PersistentVolume указывает кластеру, что делать с овободившимся диском, и может иметь значение Retained, Recycled или Deleted.
Retain
Retain политика позволяет выполнять ручную очистку диска.
После удаления соответвующего PersistentVolumeClaim, PersistentVolume остаётся, и отмечается как «released«, однако становится недоступен для новых PersistentVolumeClaim, т.к. содержит данные предыдущего PersistentVolumeClaim.
Для того, что бы использовать такой ресурс повторно — можно либо удалить объект PersistentVolume, при этом AWS EBS останется доступен, био вручную удалить данные с диска.
Delete
При Delete — удаление PVC приводит к удалению и соответствующего устройсва, такого как AWS EBS, GCE PD или Azure Disk.
Разделы, созданные автоматически наследуют политику из StorageClass, которая по умолчанию задана в Delete.
Recycle
Устарела. Выполняет удаление с раздела обычным rm -rf.
Пример удаление PV и PVC
Итак, у нас имеется под:
kk get pod pv-static-pod
NAME READY STATUS RESTARTS AGE
pv-static-pod 1/1 Running 0 19s
К которому подключен PVC:
kk get pvc pvc-static
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-static Bound pv-static 50Gi RWO gp2 19h
Который биндится на PV:
kk get pv pv-static
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE