# PersistentVolume

> Абстракция постоянного хранилища в Kubernetes — тома, переживающие перезапуск подов; запрашиваются через PersistentVolumeClaim и создаются динамически по StorageClass.

Источник: https://llmdocs.ru/wiki/persistentvolume/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Объекты**: PersistentVolume, PersistentVolumeClaim, StorageClass
- **Связанный контроллер**: StatefulSet
- **Режимы доступа**: RWO, ROX, RWX, RWOP
- **Интерфейс драйверов**: Container Storage Interface (CSI)
- **Политики возврата**: Retain, Delete
- **Примеры хранилищ**: облачные диски, NFS, Ceph (Rook), Longhorn, local-path
**PersistentVolume** (PV, постоянный том) — объект [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), представляющий кусок хранилища в кластере: облачный диск, сетевую папку NFS, том в Ceph или каталог на узле. В отличие от файловой системы контейнера, которая исчезает вместе с [подом](https://llmdocs.ru/wiki/pod.md), данные на PersistentVolume сохраняются при перезапуске, пересоздании и переносе пода на другой узел. Поэтому именно через PV в Kubernetes запускают базы данных, очереди и всё, что хранит состояние.

## Три объекта

Хранилище в Kubernetes разделено на роли администратора и разработчика:[1]

| Объект | Кто создаёт | Что описывает |
|---|---|---|
| **PersistentVolume** | администратор или автоматически | конкретный том: размер, тип, где находится |
| **PersistentVolumeClaim** (PVC) | разработчик | заявку: «нужно 10 ГиБ, запись с одного узла» |
| **StorageClass** | администратор | «тип хранилища» и драйвер, создающий тома по заявкам |

Под ссылается не на PV, а на PVC — так манифест приложения не зависит от того, где кластер работает: в облаке, на собственном железе или на ноутбуке.

## Пример

```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data
spec:
  accessModes: [ReadWriteOnce]
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 10Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: db
spec:
  containers:
    - name: postgres
      image: postgres:17
      volumeMounts:
        - name: data
          mountPath: /var/lib/postgresql/data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: data
```

## Динамическое выделение

В современных кластерах PV почти никогда не создают вручную. Когда появляется PVC с указанным StorageClass, **провижинер** — драйвер CSI — сам создаёт диск у провайдера и соответствующий PV, после чего связывает его с заявкой (статус `Bound`).[2] Один StorageClass обычно помечен как класс по умолчанию.

```yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
```

Режим `WaitForFirstConsumer` откладывает создание тома, пока под не назначен на узел, — иначе диск может оказаться в другой зоне доступности, чем под.

## Режимы доступа

- **ReadWriteOnce (RWO)** — чтение и запись с одного узла; типично для блочных дисков.
- **ReadOnlyMany (ROX)** — только чтение с многих узлов.
- **ReadWriteMany (RWX)** — запись с многих узлов; нужна файловая система с общим доступом (NFS, CephFS, облачные файловые хранилища).
- **ReadWriteOncePod (RWOP)** — запись только из одного пода во всём кластере.

Частая ошибка — ждать от облачного блочного диска режима RWX: он не поддерживается, и под на втором узле не запустится.

## Жизненный цикл и политики

Когда PVC удаляют, судьба тома определяется политикой `reclaimPolicy`: **Delete** — диск удаляется вместе с данными (по умолчанию для динамических томов), **Retain** — PV остаётся в статусе `Released`, и данные можно восстановить вручную. Для важных баз данных разумно использовать `Retain` и всё равно делать резервные копии. Тома можно увеличивать (`allowVolumeExpansion`) — уменьшать нельзя. Механизм **VolumeSnapshot** создаёт снимки томов средствами хранилища.[4]

## StatefulSet

Для приложений с состоянием используется контроллер **StatefulSet**: в отличие от [Deployment](https://llmdocs.ru/wiki/deployment-replicaset.md), он даёт подам стабильные имена (`db-0`, `db-1`) и через `volumeClaimTemplates` создаёт каждому реплике свой PVC, который сохраняется при пересоздании пода.[3] Сложные системы с репликацией и переключением обычно разворачивают через [оператор](https://llmdocs.ru/wiki/kubernetes-operator.md), который сам управляет StatefulSet и томами.

## CSI и типы хранилищ

**Container Storage Interface** — стандарт, по которому производители хранилищ пишут драйверы для Kubernetes и других оркестраторов, не меняя код самого Kubernetes.[5] Распространённые варианты:

- **Облачные диски** — AWS EBS, Google Persistent Disk, Azure Disk, диски Yandex Cloud.
- **Локальные тома** — `local-path-provisioner` (по умолчанию в [k3s](https://llmdocs.ru/wiki/k3s.md)): быстро, но данные привязаны к узлу.
- **Распределённые** — Rook/Ceph, Longhorn, OpenEBS: реплицируют данные между узлами собственного кластера.
- **NFS** — простой вариант для RWX.

## Диагностика

```bash
kubectl get pvc,pv
kubectl describe pvc data        # события: почему не Bound
kubectl get storageclass
```

Если PVC висит в `Pending`, причины обычно три: нет подходящего StorageClass, драйвер не установлен или заявка требует неподдерживаемый режим доступа.

## См. также

- [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md)
- [Pod](https://llmdocs.ru/wiki/pod.md)
- [Оператор Kubernetes](https://llmdocs.ru/wiki/kubernetes-operator.md)
- [ConfigMap и Secret](https://llmdocs.ru/wiki/configmap-secret.md)

## Источники

1. [Kubernetes Docs — Persistent Volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/)
2. [Kubernetes Docs — Storage Classes](https://kubernetes.io/docs/concepts/storage/storage-classes/)
3. [Kubernetes Docs — StatefulSets](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/)
4. [Kubernetes Docs — Volume Snapshots](https://kubernetes.io/docs/concepts/storage/volume-snapshots/)
5. [Container Storage Interface specification](https://github.com/container-storage-interface/spec)
