PersistentVolumeClaim: том, который переживёт Pod
Как PVC и PV дают приложению постоянный диск, что означают accessModes и почему PVC остаётся в Pending без Pod.
Зачем нужно постоянное хранилище
Pod - наименьшая единица, которую запускает Kubernetes. Внутри Pod работает контейнер. По умолчанию Pod не хранит данные надолго. Контейнер упал, kubelet поднял новый, файлы на диске старого пропали. kubelet - это агент Kubernetes на узле, который запускает контейнеры.
Базе данных или очереди такое не подходит. Им нужно хранилище, которое переживёт перезапуск Pod. Этим занимаются два объекта: PVC и PV.
PVC и PV: запрос и ресурс
PersistentVolumeClaim (PVC) это запрос на хранилище от приложения. В нём пишут, сколько места нужно и в каком режиме доступа.
PersistentVolume (PV) это выделенный объём хранилища в кластере.
PVC и PV связываются (bind), после чего Pod монтирует PVC как обычный каталог. PVC просит, PV предоставляет.
PV обычно создаётся автоматически. За это отвечает provisioner. Это
плагин хранилища, привязанный к StorageClass (классу хранилища). В
небольших локальных кластерах это local-path (k3s) или standard
(kind, minikube), в AWS -
CSI-драйвер EBS (ebs.csi.aws.com). Сам Kubernetes диски не создаёт,
это делает плагин: встроенных в ядро провизионеров облаков больше нет,
всё хранилище идёт через CSI.
Минимальный YAML
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
StorageClass здесь не указан, поэтому берётся класс по умолчанию.
Поле resources.requests.storage задаёт размер. PVC живёт в namespace,
как и Pod.
accessModes: режим доступа
accessModes задаёт, сколько узлов и как могут открыть том
одновременно.
ReadWriteOnce(RWO) - один узел на запись. Обычный выбор для блочного хранилища вроде AWS EBS через CSI-драйвер.ReadOnlyMany(ROX) - несколько узлов только на чтение.ReadWriteMany(RWX) - несколько узлов на запись. Работает только на сетевых файловых системах (NFS, CephFS).
У созданного PVC accessModes и storageClassName уже не поменять:
ошибся - удаляй и создавай заново. А вот размер расширяется, если у
StorageClass стоит allowVolumeExpansion: true. Тогда достаточно
поднять resources.requests.storage, уменьшать нельзя.
Допустимые значения: ReadWriteOnce, ReadOnlyMany,
ReadWriteMany, ReadWriteOncePod. Опечатка вроде ReadWriteOne
приведёт к ошибке.
WaitForFirstConsumer: PVC ждёт Pod
StorageClass задаёт момент создания PV полем volumeBindingMode. У
локальных классов обычно стоит WaitForFirstConsumer. PV создаётся не
сразу, а когда появится Pod, который использует PVC.
Поэтому PVC в режиме WaitForFirstConsumer остаётся в статусе
Pending, пока на него не сошлётся Pod. После запуска Pod PVC
переходит в Bound. Ждать Bound без Pod бесполезно.
Pending у PVC не всегда поломка. При WaitForFirstConsumer это
штатное состояние: PV создаётся под конкретный Pod, и пока Pod не
появился, привязывать нечего.
Подключение к Pod
spec:
volumes:
- name: data
persistentVolumeClaim:
claimName: data-pvc
containers:
- name: app
volumeMounts:
- name: data
mountPath: /data
volumes объявляет источник через claimName (имя PVC).
volumeMounts подключает его в контейнер по пути mountPath. Имя в
volumeMounts.name должно совпадать с именем в volumes.
PVC переживает удаление Pod
PVC живёт отдельно от Pod. Удаление Pod не трогает PVC и данные на
диске. Можно пересоздать Pod и снова смонтировать тот же том. Чтобы
удалить данные, PVC удаляют явно командой
kubectl delete pvc data-pvc.
Состояние хранилища смотрят так:
kubectl get pvc
kubectl get pv
kubectl describe pvc data-pvc
kubectl get storageclass
kubectl get sc -o jsonpath='{.items[?(@.metadata.annotations.storageclass\.kubernetes\.io/is-default-class=="true")].metadata.name}'
Последняя команда печатает имя класса по умолчанию.
Полезные команды
kubectl explain pvc.spec
kubectl explain pvc.spec.accessModes
kubectl get sc
kubectl get pv
kubectl describe sc <имя-класса>
Домашка
Теорию закрепляет задание на своём кластере: 2 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.
./run.sh start k8s-pvc # развернуть стартовое состояние
./run.sh verify k8s-pvc # проверить текущий шаг
Коротко
- PVC - запрос на хранилище, PV - сам выделенный объём. Их связка называется bind.
- PV создаёт provisioner из StorageClass. Kubernetes сам диски не выделяет, всё идёт через CSI-драйвер.
accessModesиstorageClassNameпосле создания PVC не меняются, размер расширяется только приallowVolumeExpansion: true.- При
volumeBindingMode: WaitForFirstConsumerPVC висит вPending, пока на него не сошлётся Pod. - В Pod том подключают через
volumes.persistentVolumeClaim.claimNameиvolumeMounts.mountPathс одинаковымname.
Дрилл · вопросы как на собесе
Проверь себя без подсказок
Сформулируй ответ вслух или письменно, потом раскрой и честно отметь: знал или нет.
Что такое PersistentVolume и PersistentVolumeClaim?
K8S-006Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс