Пять решений закрывают почти все задачи постоянного хранения в Kubernetes, но выбирать между ними приходится по трём жёстким параметрам: нужный режим доступа, наличие снапшотов и допустимая задержка операций ввода-вывода.
Короткий ответ для тех, кому решение нужно сегодня:
- Local PV - максимальная скорость (на NVMe легко получить 100 000 IOPS и задержку меньше 100 мкс), но том привязан к ноде и репликации нет.
- NFS - самый быстрый способ получить ReadWriteMany и подключить уже работающую NAS.
- Ceph RBD - распределённая блочная СХД для продакшена: репликация, снапшоты, горизонтальное масштабирование.
- Longhorn - установка одним Helm-чартом, встроенные снапшоты и бэкапы в S3, RWX через NFS-сервер.
- OpenEBS - несколько движков на выбор: Mayastor, cStor, Jiva, LocalPV.
Все пять подключаются через CSI-драйвер, поэтому на уровне манифестов разница минимальна: под получает том через PersistentVolumeClaim, а StorageClass описывает драйвер и его параметры. Расхождение начинается в эксплуатации: сколько нод нужно, кто чинит кластер хранилища в три часа ночи и что произойдёт с данными при отказе диска.
Как выбрать постоянное хранилище для Kubernetes: критерии и контекст
Сравнивать варианты стоит по шести критериям.
- Производительность: IOPS, пропускная способность, задержка чтения и записи на реальном профиле нагрузки.
- Режимы доступа: ReadWriteOnce, ReadOnlyMany, ReadWriteMany, ReadWriteOncePod.
- Снапшоты и клонирование: поддержка CSI VolumeSnapshot из коробки или через внешние инструменты.
- Сложность развёртывания и обслуживания: сколько нод и дисков требует решение, сколько внимания съедает мониторинг и обновления.
- Требования к инфраструктуре: сеть 10GbE, отдельные диски, hugepages, версия ядра.
- Стоимость владения: железо, лицензии, человеко-часы на поддержку.
Выбор определяется профилем нагрузки. PostgreSQL с одним активным подом и своим механизмом репликации обойдётся режимом ReadWriteOnce. Веб-приложению, где несколько подов пишут в общую папку uploads, нужен ReadWriteMany. CI/CD-раннер, распаковывающий артефакты сотнями мелких файлов, чувствителен к задержке метаданных. Кластер из двух нод не потянет Ceph физически.
Перед сравнением драйверов полезно определиться с типом хранилища: блочное, файловое или объектное. Разница в протоколах, архитектуре и сценариях разобрана в материале объектное, блочное и файловое хранилище: как выбрать и не ошибиться. Дальше речь идёт только о вариантах, которые монтируются в поды как диски.
Режимы доступа RWO, ROX, RWX и RWOP: что реально поддерживается
ReadWriteOnce (RWO) означает монтирование тома на чтение и запись только на одной ноде. Это не то же самое, что «один под»: два пода на одной ноде могут работать с таким томом одновременно, а перенести его на другую ноду без размонтирования нельзя. ReadOnlyMany (ROX) разрешает монтировать том на многих нодах только для чтения. ReadWriteMany (RWX) допускает параллельную запись с разных нод. ReadWriteOncePod (RWOP) жёстче всех: том доступен ровно одному поду во всём кластере, режим стабилен с Kubernetes 1.29 и требует поддержки со стороны CSI-драйвера.
| Решение | RWO | ROX | RWX | RWOP | Как сделан RWX |
|---|---|---|---|---|---|
| Local PV | Да | Нет | Нет | Нет | - |
| NFS | Да | Да | Да | Нет | Нативно, протоколом |
| Ceph RBD | Да | Нет | Нет | Ограниченно | Через CephFS |
| Longhorn | Да | Нет | Да | Да | Под share-manager (NFS) |
| OpenEBS | Да | Нет | Частично | Зависит от движка | Отдельный NFS provisioner |
Ключевая ловушка: RWX на блочном хранилище почти всегда означает дополнительный NFS-сервер поверх блочного тома. Longhorn поднимает для этого под share-manager, OpenEBS использует NFS provisioner. Каждый лишний слой добавляет сетевой хоп, и на типовой сети 10GbE пропускная способность падает на 30-50% против чистого блочного доступа. Если приложение умеет работать с RWO, переводить его на RWX ради удобства не стоит.
Снапшоты и клонирование: нативная поддержка и внешние инструменты
Снапшоты томов в Kubernetes делаются через CSI VolumeSnapshot API, группа snapshot.storage.k8s.io. Нужны два компонента: snapshot-controller в кластере и CSI external-snapshotter в драйвере. Без них объект VolumeSnapshot не создастся, а команда вернёт ошибку о неизвестном типе ресурса.
| Решение | Снапшоты | Клонирование | Резервное копирование |
|---|---|---|---|
| Ceph RBD | Нативно через CSI | Да | RBD mirror, Velero |
| Longhorn | Встроенные, бэкап в S3 или NFS | Да | Встроенный движок, Velero |
| OpenEBS cStor, Mayastor | Нативно | Да | Velero |
| NFS | Зависит от сервера: ZFS, NetApp, TrueNAS | Через внешние инструменты | Velero, rsync |
| Local PV | Нет | Нет | Средствами хоста: LVM, ZFS |
Пример VolumeSnapshotClass для Ceph RBD: драйвер и пул указываются в parameters, политика удаления задаёт судьбу снапшота после удаления объекта.
apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshotClass metadata: name: csi-rbdplugin-snapclass driver: rbd.csi.ceph.com deletionPolicy: Delete parameters: clusterID: my-cluster-id pool: rbd
Velero закрывает резервное копирование и восстановление на уровне кластера: сохраняет манифесты и подключает CSI-снапшоты через плагин. Для Local PV Velero бессилен без агента на ноде, потому что снапшот диска снимают средствами хоста. Это ограничение придётся учитывать при планировании стратегии восстановления.
Local PV: максимальная производительность ценой гибкости
Local PV монтирует диск или каталог конкретной ноды напрямую в под. Между приложением и устройством нет ни сети, ни репликации, поэтому задержка сравнима с локальным доступом. На NVMe-диске реально получить 100 000 IOPS при задержке ниже 100 микросекунд, а пропускная способность упирается в шину PCIe, а не в сеть.
Схема простая: администратор создаёт PersistentVolume с полем nodeAffinity, привязывающим том к ноде, а StorageClass не выполняет динамического выделения вовсе.
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: local-nvme provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer reclaimPolicy: Retain
Параметр volumeBindingMode: WaitForFirstConsumer обязателен. Он заставляет планировщик сначала выбрать ноду для пода и только потом привязать том, иначе PV окажется на ноде, куда под не поместится из-за нехватки ресурсов.
Что даёт решение: минимальную задержку, максимальный IOPS, нулевые накладные расходы на сеть, простоту в понимании. Что забирает: отсутствие репликации, жёсткую привязку к ноде, потерю данных при отказе диска или ноды, отсутствие снапшотов и RWX. При падении ноды под не поднимется, пока том не станет доступен.
Оправданные сценарии: PostgreSQL с Patroni, Cassandra, Elasticsearch, ClickHouse, Prometheus TSDB, локальные кэши. Во всех случаях отказоустойчивость обеспечивает само приложение, а не слой хранения. Если данные потерять нельзя, а внешней репликации нет, Local PV для них не подходит. Полезно заранее посчитать IOPS и уровень RAID под нагрузку: методика расчёта и таблицы сравнения собраны в статье системы хранения данных (СХД) в 2026.
NFS: простота и RWX, но с оговорками по производительности
NFS отдаёт каталоги по сети отдельный сервер, а поды монтируют их как обычные тома. Подключение бывает статическим, когда PV описывает сервер и путь вручную, и динамическим через CSI-драйвер вроде nfs.csi.k8s.io.
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-client provisioner: nfs.csi.k8s.io parameters: server: 10.0.0.10 share: /export/data mountOptions: "nfsvers=4.1" reclaimPolicy: Delete volumeBindingMode: Immediate
Сильные стороны: единственное из пяти решений, где RWX и ROX работают нативно, без прослоек. Можно подключить существующую NAS и не покупать ничего дополнительно. Настройка занимает минуты, а тома доступны большому числу подов одновременно. Для общих файлов, веб-контента, CI/CD и домашних лабораторий этого хватает.
Слабые стороны: сервер становится единой точкой отказа, если не собран HA-кластер. Производительность упирается в сеть и в диск сервера, типичный диапазон на гигабитном канале - 2 000-10 000 IOPS при задержке 1-5 мс. Нативных снапшотов на уровне Kubernetes нет, всё зависит от возможностей сервера: ZFS, NetApp или TrueNAS умеют снимать снапшоты, обычный export в ext4 не умеет. Блокировки и кэширование требуют аккуратности, а версия протокола влияет на поведение: v3 проще, v4.1 даёт лучшую работу с блокировками и состояние сессий.
Частые грабли: root squash превращает запись от uid 0 в permission denied, а несовпадение uid и gid между подом и сервером ломает права на файлы. Сообщение stale file handle в логах означает, что каталог на сервере переехал или экспорт перемонтирован. Как выбирать между NAS, NFS, SMB и iSCSI для контейнеров, разобрано в отдельном руководстве программные системы хранения для виртуализации и контейнеров.
Ceph RBD: распределённая СХД для требовательных нагрузок
Ceph RBD - блочное устройство внутри Ceph. Данные разбиваются на объекты, раскладываются по OSD и реплицируются, а клиент собирает их обратно через librbd или krbd. Порядок величины на сети 10GbE с репликацией x3: 10 000-50 000 IOPS на том при задержке 1-3 мс.
Плюсы: репликация и самовосстановление, снапшоты и клоны без копирования данных, горизонтальное масштабирование добавлением OSD, предсказуемое поведение под нагрузкой баз данных. Минусы: развёртывание и обслуживание требуют компетенций (минимум три ноды, лучше пять, отдельные диски под OSD, отдельная сеть для репликации, 8-16 ГБ RAM на узел OSD, мониторинг состояния PG). Чувствительность к сети высокая: на 1GbE решение задыхается на пересборке реплик.
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: ceph-rbd-ssd provisioner: rbd.csi.ceph.com parameters: clusterID: rook-ceph pool: replicapool imageFeatures: layering csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph reclaimPolicy: Delete allowVolumeExpansion: true volumeBindingMode: Immediate
Типичные ошибки при первом запуске: неверное имя пула, отсутствие секрета с ключами, несовпадение clusterID в StorageClass и в ceph.conf, не загруженный модуль krbd на нодах. Развёртывание Ceph в Kubernetes через Rook с готовыми манифестами пошагово разобрано в руководстве интеграция систем хранения данных с Kubernetes: PersistentVolume, NFS, Rook/Ceph.
Longhorn: облачное хранилище для Kubernetes с простой установкой
Longhorn собирает распределённое блочное хранилище из дисков самих нод. Установка занимает несколько минут: чарт Helm разворачивается в неймспейс longhorn-system, после чего в кластере появляются драйвер, UI и контроллеры.
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: longhorn-3replicas provisioner: driver.longhorn.io allowVolumeExpansion: true reclaimPolicy: Delete volumeBindingMode: Immediate parameters: numberOfReplicas: "3" staleReplicaTimeout: "30" fsType: "ext4"
Плюсы: простая установка и понятный веб-интерфейс, встроенные снапшоты и бэкапы в S3 или NFS, расписания (recurring jobs) для автоматических снапшотов, репликация тома на несколько нод, RWX через share-manager, восстановление тома на другой ноде. Порядок производительности: 5 000-20 000 IOPS, что покрывает большинство рабочих нагрузок среднего кластера.
Минусы: нужен отдельный диск на каждой ноде (по умолчанию каталог /var/lib/longhorn), запись уходит на все реплики сразу, поэтому сеть становится узким местом, а пересборка реплики после сбоя заметно просаживает отзывчивость тома. Для тяжёлых баз данных с интенсивной записью может понадобиться тюнинг числа реплик и размера блока. RWX работает через NFS-прослойку со всеми её накладными расходами.
Что проверить до старта: пакет open-iscsi на всех нодах, включённый распространение монтирований, файловые системы ext4 или xfs, зарезервированное место на диске. Параметр storageReserved по умолчанию оставляет часть ёмкости, и его стоит поднять, иначе кластер упрётся в нехватку места при заполнении диска. Сценарии: средние продакшен-кластеры, CI/CD, тестовые среды, edge-инсталляции.
OpenEBS: гибкость и выбор движков под задачу
OpenEBS - набор движков с разными свойствами, и это одновременно сила и сложность решения. Движки перечислены ниже.
- Mayastor - NVMe over Fabrics поверх SPDK, самая быстрая опция, требует hugepages и выделенного диска, на порядок быстрее cStor.
- cStor - ZFS-подобный движок со снапшотами и репликами, в новых версиях переведён в режим поддержки.
- Jiva - простые реплики на уровне iSCSI, подходит для небольших кластеров и устаревших ядер.
- LocalPV - движки HostPath, LVM и ZFS для локальных дисков с управлением через Kubernetes.
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: openebs-mayastor provisioner: io.openebs.csi-mayastor parameters: repl: "3" protocol: nvmf reclaimPolicy: Delete volumeBindingMode: Immediate --- apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: openebs-cstor provisioner: cstor.csi.openebs.io parameters: cas-type: cstor cstorPoolCluster: cstor-disk-pool replicaCount: "3"
Mayastor требует hugepages (обычно 1024 страницы по 2 МиБ на ноду), ядро с поддержкой NVMe-oF и диск, отданный под пул. На этом стеке реально получить 20 000-100 000 IOPS, но и требования к железу соответствующие. cStor и Jiva проще, зато уступают в скорости. До развёртывания сверьте матрицу совместимости с версией Kubernetes: движки обновляются с разной скоростью, и несовпадение версий приводит к тому, что поды движка не стартуют.
Сравнительная таблица: производительность, снапшоты, режимы доступа, сложность
| Решение | IOPS (порядок) | Снапшоты | Доступ | Сложность | Требования | Сценарии |
|---|---|---|---|---|---|---|
| Local PV | 50 000-150 000 | Нет | RWO | Низкая | NVMe или SSD на каждой ноде | БД с репликацией в приложении, Prometheus, кэши |
| NFS | 2 000-10 000 | Зависит от сервера | RWO, ROX, RWX | Низкая | NFS-сервер, сеть | Общие файлы, CI/CD, веб-контент, лаборатория |
| Ceph RBD | 10 000-50 000 | Нативно | RWO | Высокая | 3+ ноды, 10GbE, отдельные диски | Продакшен, базы данных, крупные кластеры |
| Longhorn | 5 000-20 000 | Нативно, бэкап в S3 | RWO, RWX | Средняя | Диск на ноде, open-iscsi | Средние кластеры, CI/CD, тесты, edge |
| OpenEBS | 20 000-100 000 (Mayastor) | Нативно (cStor, Mayastor) | RWO, RWX через NFS | Средняя и высокая | Hugepages и NVMe для Mayastor | От edge до продакшена, эксперименты |
Цифры приблизительные: они получены на кластерах с сетью 10GbE, NVMe-дисками, репликацией x3 и размером блока 4К. На SATA-SSD значения ниже в два-три раза, на 1GbE сеть становится главным ограничением для всех распределённых вариантов. Свои замеры лучше снимать через fio с профилем, повторяющим рабочую нагрузку: случайное чтение блоками 4К для баз данных, последовательная запись блоками 1 МБ для логов и архивов.
Типичные ошибки при динамическом выделении томов и их решение
Большинство инцидентов с хранилищем в Kubernetes сводится к шести сценариям.
- PVC висит в Pending. Причины по частоте: в кластере нет StorageClass по умолчанию, provisioner не запущен, отсутствует секрет для Ceph, закончилась ёмкость в пуле. Диагностика начинается с описания PVC и событий.
- Multi-Attach error при монтировании. Том в режиме RWO уже подключён к другой ноде, а под пытается стартовать на новой. Лечится либо ожиданием отключения, либо сменой режима доступа, либо переводом приложения на одну реплику.
- Permission denied в NFS. Проверяйте root squash, uid и gid процесса в контейнере, права на каталог экспорта.
- Нехватка места в Longhorn. Диск достиг резерва, новые реплики не создаются. Поднимите параметр storageReserved и освободите ёмкость, удалив старые снапшоты.
- Ошибки Ceph. Неверный пул, отсутствующий keyring, не загруженный модуль krbd. Проверяется состоянием кластера и логами CSI-подов.
- Данные исчезли после удаления PVC. Сработала reclaimPolicy: Delete. Для критичных томов политику Retain задают заранее, на этапе создания StorageClass.
kubectl get pvc -A kubectl describe pvc my-claim -n default kubectl get events -n default --sort-by=.lastTimestamp kubectl get csidrivers kubectl logs -n kube-system deploy/csi-provisioner -c csi-provisioner
Чек-лист перед разбором инцидента: убедиться, что StorageClass существует и помечен как default; проверить наличие и корректность секретов драйвера; сверить квоты и свободное место в пуле; проверить сетевую доступность между нодами и сервером хранилища; посмотреть события по PVC, PV и поду драйвера. В девяти случаях из десяти причина находится на одном из этих пяти шагов.
Итоговые рекомендации: какое хранилище выбрать под ваш сценарий
Максимальная скорость и минимальная задержка: Local PV с репликацией на уровне приложения. ReadWriteMany с минимумом усилий: NFS с HA-сервером. Продакшен с высокими требованиями к отказоустойчивости и объёму: Ceph RBD. Средний кластер, где важны простая установка, снапшоты и бэкапы в S3: Longhorn. Гибкость и разные профили нагрузки на одном кластере: OpenEBS с Mayastor для быстрых томов и LocalPV для остального.
Решения комбинируются. Нормальная практика - держать несколько StorageClass: local-nvme для Prometheus и баз данных с собственной репликацией, longhorn-3replicas для приложений без репликации, nfs-client для общих файлов. Классы помечаются как default по одному, чтобы PVC без явного storageClassName не попадал туда, где ему не место.
Порядок действий выглядит так. Сначала выписать требования: режим доступа, объём, IOPS на операцию записи, нужны ли снапшоты, допустимое время простоя. Затем собрать стенд и прогнать fio с реалистичным профилем, а не с абстрактным тестом. После этого переводить сервисы по одному, начиная с наименее критичных. Мониторинг задержки и свободного места настроить до первого продакшен-тома, а не после инцидента.
Бэкап не отменяется ни для одного из пяти решений. Снапшот тома защищает от ошибки оператора, но не от потери всей площадки. Копия в S3, на NFS или на отдельный кластер остаётся обязательным элементом, проверенным восстановлением хотя бы раз в квартал.
Когда обслуживать собственный кластер хранилища не хочется, часть задач закрывает облако. Например, Timeweb Cloud предоставляет серверы, хранилище и управляемый Kubernetes, где слой хранения уже настроен, а выбор между локальными дисками и сетёвыми томами сводится к параметрам манифеста. Такой вариант подходит для быстрого старта и для сервисов, которые не привязаны к собственной площадке. Если же данные растут быстрее кластера, стоит заранее посчитать объёмы и схему миграции: практические подходы к хранению больших массивов собраны в статье хранение больших данных и массивов.