← Kubernetes: хранилище
6 мин · средне · Урок 1 из 2

PersistentVolumeClaim: том, который переживёт Pod

Как PVC и PV дают приложению постоянный диск, что означают accessModes и почему PVC остаётся в Pending без Pod.

Зачем нужно постоянное хранилище

Pod - наименьшая единица, которую запускает Kubernetes. Внутри Pod работает контейнер. По умолчанию Pod не хранит данные надолго. Контейнер упал, kubelet поднял новый, файлы на диске старого пропали. kubelet - это агент Kubernetes на узле, который запускает контейнеры.

Базе данных или очереди такое не подходит. Им нужно хранилище, которое переживёт перезапуск Pod. Этим занимаются два объекта: PVC и PV.

PVC и PV: запрос и ресурс

Pod claimName: data-pvc claimName PVC 1Gi, ReadWriteOnce по классу StorageClass local-path создаёт PV каталог на узле
Цепочка ссылок: Pod называет PVC, PVC называет класс, класс создаёт диск.

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 задаёт, сколько узлов и как могут открыть том одновременно.

У созданного 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    # проверить текущий шаг

Коротко

Дрилл · вопросы как на собесе

Проверь себя без подсказок

Сформулируй ответ вслух или письменно, потом раскрой и честно отметь: знал или нет.

01

Что такое PersistentVolume и PersistentVolumeClaim?

K8S-006

Прошли материал до конца? Отметьте урок пройденным.