Выбор хранилища для Kubernetes в 2026 упирается в четыре вопроса: какой режим доступа нужен приложению, умеет ли драйвер выделять тома автоматически, что произойдёт при отказе узла и сколько человеко-часов в месяц вы готовы отдать на эксплуатацию. Ответы на них сужают список быстрее любых бенчмарков.
Короткий ответ для типовых случаев. База данных на bare-metal с собственной репликацией: локальные NVMe через TopoLVM, режим RWO. Универсальное отказоустойчивое хранилище в кластере на 5-10 узлов: Ceph RBD с тремя репликами. Кластер до 5 узлов, где важна простота: Longhorn. Общий каталог для нескольких подов: NFS или CephFS в режиме RWX. Managed-кластер в облаке: блочные диски провайдера через его CSI-драйвер.
Ниже критерии, разбор пяти категорий решений, таблица сравнения, рекомендации для PostgreSQL, MySQL, Kafka и Elasticsearch, а также типовые ошибки, которые ломают продакшен через месяц после запуска.
Ключевые критерии выбора хранилища для Kubernetes
Для stateful-нагрузок семь параметров решают почти всё.
- Режим доступа (RWO, ROX, RWX, RWOP). Определяет, сколько узлов и подов могут работать с томом одновременно.
- Динамическое выделение томов через CSI. Без него каждый PersistentVolume создаётся руками, а это не масштабируется.
- Производительность: IOPS на 4 КБ, latency p99, throughput на последовательных операциях.
- Отказоустойчивость: RPO и RTO, поведение при отказе узла, диска и всей зоны.
- Сложность эксплуатации: сколько специалистов нужно, как часто обновлять и что делать при деградации.
- Стоимость: TCO на 3 года, включая железо, лицензии, администрирование, электроэнергию и бэкапы.
- Функции уровня данных: снапшоты, клонирование, расширение тома, шифрование, тонкое выделение.
Для stateless-подов выбор хранилища почти не важен: под перезапускается на любом узле, состояние живёт во внешнем сервисе. StatefulSet цепляет к поду конкретный PVC, и под уже не переедет туда, где тома нет. PostgreSQL с fsync на каждую транзакцию ждёт ответа диска, поэтому latency хранилища напрямую превращается в задержку коммита. Приложение, которое отдаёт общий каталог загрузок десяти подам, требует RWX и получает сетевую файловую систему с её задержками. Отсюда правило: сначала профиль нагрузки, потом бренд СХД, а не наоборот.
Инфраструктура задаёт жёсткие рамки. В облаке у вас нет своих дисков, зато есть managed-тома с гарантиями провайдера. На bare-metal доступны локальные NVMe, но их отказоустойчивость нужно строить самому. В гибридной схеме часть нагрузки уезжает в облако, и тогда критично, переносим ли StorageClass между площадками без переписывания манифестов.
Режимы доступа: RWO, ROX, RWX и когда какой нужен
Режимы задаются в поле accessModes у PersistentVolumeClaim. Их четыре.
- ReadWriteOnce (RWO): том монтируется для чтения и записи на один узел. Несколько подов на том же узле писать могут, на разных узлах - нет.
- ReadOnlyMany (ROX): много узлов читают, запись запрещена. Подходит для раздачи статики, справочников, ML-датасетов.
- ReadWriteMany (RWX): много узлов читают и пишут. Нужен для общих каталогов, очередей на файловой системе, совместной работы приложений.
- ReadWriteOncePod (RWOP): том достаётся ровно одному поду в кластере. Стабильно с Kubernetes 1.29, полезен там, где второй писатель означает порчу данных, например SQLite или приложение с блокировкой на уровне файла.
Практика выглядит так. PostgreSQL, MySQL, Kafka, Elasticsearch работают в RWO: у каждого своя реплика данных на уровне приложения. Веб-серверы, отдающие общую медиатеку, берут ROX. Каталог загрузок Nextcloud, общие конфигурации, артефакты сборки, файловый обмен между микросервисами - RWX.
Драйверы поддерживают режимы выборочно, и это самая частая причина «вечного» Pending у PVC. Локальные тома (TopoLVM, LocalPV) умеют только RWO и RWOP. Блочные драйверы (Ceph RBD, облачные диски) тоже RWO. CephFS и NFS дают RWX и ROX. Longhorn отдаёт RWX через NFS-сервер (share-manager), который поднимается отдельным подом на каждый том. Если в accessModes указать RWX, а драйвер его не умеет, PVC останется в Pending без внятной ошибки в событиях.
Цена RWX - сеть. Любая распределённая файловая система добавляет 0.5-3 мс к операции и упирается в пропускную способность канала при мелких случайных записях. Для баз данных это плохой выбор, для общих каталогов - нормальный.
Динамическое выделение томов и роль CSI-драйверов
CSI (Container Storage Interface) - стандарт gRPC-интерфейса между Kubernetes и системой хранения. Драйвер реализует два набора вызовов: контроллерные (CreateVolume, DeleteVolume, CreateSnapshot, ControllerExpandVolume) и узловые (NodeStageVolume, NodePublishVolume, NodeUnpublishVolume). Плюс вспомогательные сайдкары: external-provisioner, external-attacher, external-resizer, external-snapshotter, node-driver-registrar.
Цепочка при создании тома: приложение через StatefulSet объявляет volumeClaimTemplates, из него рождается PVC. Provisioner читает StorageClass, вызывает CreateVolume у драйвера, получает PV и биндит его с PVC. Attacher создаёт объект VolumeAttachment, kubelet на нужном узле вызывает NodeStageVolume и NodePublishVolume. Под стартует с примонтированным томом. Ручного создания PV в этой схеме нет.
StorageClass задаёт главное: provisioner, параметры пула, reclaimPolicy, allowVolumeExpansion, volumeBindingMode. Последний параметр критичен для локальных и зональных томов: WaitForFirstConsumer откладывает создание до планирования пода, иначе том появится в зоне, где нет свободного места, или на узле, к которому под не привяжется.
Пример StorageClass для Ceph RBD:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: ceph-rbd-ssd provisioner: rbd.csi.ceph.com parameters: clusterID: ceph-prod pool: kube-ssd imageFeatures: layering csi.storage.k8s.io/fstype: ext4 reclaimPolicy: Delete allowVolumeExpansion: true volumeBindingMode: WaitForFirstConsumer
Пример StorageClass для Longhorn с тремя репликами:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: longhorn-3replicas provisioner: driver.longhorn.io parameters: numberOfReplicas: "3" staleReplicaTimeout: "30" reclaimPolicy: Delete allowVolumeExpansion: true
Снапшоты и клоны тоже идут через CSI. Объекты VolumeSnapshotClass и VolumeSnapshot позволяют снять снимок, а новый PVC можно создать из снимка через dataSource. Расширение тома работает в одну сторону: уменьшить PVC нельзя, при этом не все драйверы умеют расширять том без перезапуска пода, и тогда PVC застревает в состоянии FileSystemResizePending.
Статическое выделение и in-tree плагины остались для legacy. Плагины для AWS, GCE, Azure, Ceph перевели на CSI-миграцию в релизах 1.23-1.27, новые драйверы в дерево Kubernetes не добавляют. Если в манифестах всё ещё фигурируют awsElasticBlockStore или rbd в разделе volumes, это технический долг с известной датой истечения.
Обзор вариантов: локальные диски, распределённые СХД, NFS и облачные решения
Четыре категории покрывают почти все сценарии: локальные диски под управлением CSI-драйвера, распределённые программные СХД, сетевые файловые системы и облачные блочные диски. Ниже ключевые особенности каждой, с цифрами, которые стоит проверять на своей нагрузке. Подробное сравнение блочного, файлового и объектного подходов приведено в отдельном разборе объектное, блочное и файловое хранилище.
Локальные диски с TopoLVM: максимальная производительность
TopoLVM - CSI-драйвер, который нарезает логические тома LVM из локальной группы томов на узле и отдаёт их подам. Планировщик учитывает остаток места на узле, поэтому под приезжает туда, где том реально поместится. Режим доступа - RWO или RWOP.
Производительность упирается только в диск. Один корпоративный NVMe даёт 500 000+ IOPS на случайном чтении 4 КБ и 3-7 ГБ/с на последовательных операциях, latency держится в пределах 0.1-0.2 мс. Сети в этой схеме нет вообще.
Плата за скорость - отсутствие репликации. PV жёстко привязан к узлу через nodeAffinity, при отказе узла том недоступен, а данные на нём теряются, если нет копии на другом узле или в бэкапе. Схема работает, когда отказоустойчивость обеспечивает само приложение: PostgreSQL со streaming replication и synchronous_standby_names, MySQL с Group Replication, Elasticsearch с number_of_replicas: 1, Kafka с replication.factor: 3.
Что нужно подготовить: пакет lvm2 на всех узлах, заранее созданную VG на выделенных дисках, расчёт ёмкости с запасом 20-30% и StorageClass с volumeBindingMode: WaitForFirstConsumer. Для тестовых стендов проще OpenEBS LocalPV или local-path-provisioner, они не требуют LVM, но и не считают свободное место.
Ceph для Kubernetes: универсальное отказоустойчивое хранилище
Ceph даёт три интерфейса в одном кластере: RBD (блочные тома, RWO) для баз данных и очередей, CephFS (файловая система, RWX и ROX) для общих каталогов, RGW (S3-совместимый шлюз) для бэкапов и объектных данных. Данные раскладываются алгоритмом CRUSH, а пул обычно настраивают с size: 3 и min_size: 2.
Минимальная конфигурация: 3 узла с мониторами, лучше 5, отдельная сеть 10 или 25 Гбит/с под репликацию, OSD на NVMe для горячих пулов и на HDD для холодных. При size 3 полезная ёмкость равна трети сырой. Ждать чудес от latency не стоит: на 10 Гбит/с с тремя репликами реально получить 0.5-2 мс и несколько сотен МБ/с на том, на NVMe-OSD с 25 Гбит/с показатели выше в разы.
Отказоустойчивость высокая: кластер переживает отказ узла и диска, тома остаются доступными, снапшоты и клоны работают через CSI. Эксплуатация дорогая. Восстановление после замены диска (backfill) грузит сеть и поднимает latency, PG autoscaler нужно настраивать, а не оставлять по умолчанию, апгрейды Ceph требуют порядка и понимания порядка операций.
Для кластера из 3-5 узлов с одной командой на всё Ceph часто избыточен. Для среднего и крупного продакшена с потребностью в RWX, снапшотах и едином пуле хранения он остаётся базовым выбором. Сравнение Ceph с ZFS и GlusterFS по архитектуре и стоимости владения разобрано в материале ZFS, Ceph и GlusterFS.
Longhorn: простота и отказоустойчивость для небольших кластеров
Longhorn - распределённое блочное хранилище, которое живёт внутри Kubernetes. Каждый том - цепочка реплик (по умолчанию 3) из разреженных файлов на дисках разных узлов, доступ через iSCSI-таргет движка v1. Для движка v2 используется SPDK и NVMe-oF, там нужны выделенные диски и NVMe-совместимое ядро.
Сильные стороны: установка одним набором манифестов, веб-интерфейс, автоматическая перестройка реплики после отказа узла, снапшоты, бэкапы в S3 или NFS, DR-том для переноса между кластерами, RWX через share-manager. Отдельный плюс - восстановление тома из бэкапа без внешних инструментов.
Ограничения предсказуемы. Репликация синхронная, поэтому запись считается завершённой после подтверждения от самой медленной реплики; на 1 Гбит/с один том редко выдаёт больше 100-150 МБ/с. Перестройка реплики после смены узла прокачивает весь объём тома по сети. Требуется open-iscsi на всех узлах, а свободное место на дисках расходуется с запасом на реплики и снапшоты.
Longhorn хорошо подходит кластерам на 3-5 узлов: внутренние сервисы, CI, небольшие базы, stateful-приложения без экстремальных требований к IOPS. Для Kafka с миллионом сообщений в секунду или OLTP-базы с жёстким p99 стоит смотреть в сторону локальных NVMe.
NFS как хранилище для Kubernetes: когда оправдано
NFS остаётся самым простым способом получить RWX. В Kubernetes его подключают через NFS CSI-драйвер или provisioner подкаталогов, а не через удалённый in-tree плагин. Преимущества прагматичные: уже существующая NAS или файловый сервер, общий каталог для десятков подов, снапшоты средствами СХД, отсутствие новой распределённой системы.
Ограничения тоже конкретны. Одиночный NFS-сервер - единая точка отказа, кластеризация требует DRBD, Pacemaker или перехода на CephFS и подобные системы. Задержка на локальной сети с SSD-массивом держится около 1-3 мс, на 10 Гбит/с крупные файлы читаются на 300-800 МБ/с, но случайная запись 4 КБ упирается в несколько тысяч IOPS. Блокировки NFSv3 конфликтуют с некоторыми СУБД, поэтому NFSv4.1 и выше предпочтительнее, а флаги nconnect и размеры rsize/wsize стоит поднять до 256 КБ - 1 МБ.
Рекомендация прямая: NFS для логов, медиа, общих конфигураций, артефактов сборки, датасетов на чтение. Для PGDATA и InnoDB NFS - плохая идея, если вы не измерили fsync latency и не готовы держать её в пределах миллисекунды. Требования к программным СХД для контейнеров и виртуальных машин с матрицей выбора собраны в статье программные системы хранения для виртуализации и контейнеров.
Облачные решения: AWS EBS, GCP Persistent Disk, Yandex Disk
Облачный блочный диск - managed-том, который цепляется к узлу через CSI-драйвер провайдера. Простота максимальная: нет Ceph, нет LVM, снапшоты и расширение доступны из коробки, репликация внутри зоны обеспечена провайдером.
Цифры для ориентира. AWS EBS gp3 даёт базовые 3000 IOPS и 125 МБ/с независимо от размера, а выше - за доплату: до 16 000 IOPS и 1000 МБ/с на том. io2 Block Express уходит дальше, до сотен тысяч IOPS. Том привязан к зоне доступности, поэтому узел должен находиться в той же зоне, иначе том не примонтируется. GCP предлагает pd-balanced и pd-ssd, а Hyperdisk позволяет задавать IOPS и пропускную способность отдельно от объёма. В Yandex Cloud сетевые диски network-ssd наращивают IOPS пропорционально размеру, есть вариант network-ssd-nonreplicated с более высокими показателями, но без избыточности. Лимиты и формулы начисления меняются, поэтому перед закупкой сверяйтесь с актуальной документацией провайдера.
Минусы тоже известны: привязка к провайдеру, плата за IOPS и снапшоты, ограничения пропускной способности на уровне типа инстанса, дороговизна при больших объёмах. Ориентировочно 10 ТБ в EBS gp3 обойдётся около 800 долларов в месяц, что за три года дороже собственного NVMe-массива, зато без администрирования.
Managed Kubernetes с блочными томами, снапшотами и балансировщиками без собственной Ceph-инсталляции можно поднять на облачных платформах, например Timeweb Cloud. Для гибридных схем выбирайте переносимый слой вроде Ceph или Longhorn, чтобы StorageClass не привязывал кластер к одному провайдеру.
Сравнение решений по отказоустойчивости, сложности и стоимости
Таблица ниже сводит пять категорий по критериям, которые чаще всего определяют решение.
| Решение | Режимы доступа | Отказоустойчивость | Сложность эксплуатации | Стоимость | Когда выбирать |
|---|---|---|---|---|---|
| TopoLVM, OpenEBS LocalPV | RWO, RWOP | Низкая: отказ узла делает том недоступным | Средняя: LVM, планирование ёмкости, nodeAffinity | Железо плюс администрирование | БД и очереди с репликацией на уровне приложения, bare-metal |
| Ceph RBD и CephFS | RWO, RWX, ROX | Высокая: 3 реплики, переживает отказ узла и диска | Высокая: 3-5 узлов, отдельная сеть, мониторинг OSD | Железо плюс время инженера | Универсальное хранилище для среднего и крупного кластера |
| Longhorn | RWO, RWX через share-manager | Высокая при 3 репликах | Низкая: манифесты, UI, автоматическая перестройка | Железо плюс 10-20% ресурсов на реплики | Кластеры на 3-5 узлов, внутренние сервисы, CI |
| NFS, NAS | RWX, ROX | Зависит от сервера: одиночный узел - SPOF | Низкая | Существующая инфраструктура или железо | Общие каталоги, логи, медиа, артефакты |
| Облачные диски: EBS, PD, network-ssd | RWO, RWX через файловые сервисы | Высокая в пределах зоны | Низкая: managed-сервис | Оплата за объём, IOPS и снапшоты | Managed-кластеры, отсутствие желания вести СХД |
Как выбрать между простотой и надёжностью
Простота и надёжность редко уживаются в одном решении. Longhorn ставится за час, но при синхронной репликации на 1 Гбит/с потолок по пропускной способности тома ниже, чем у локального NVMe. Ceph переживает потерю узла без потери данных, но требует дисциплины при обновлениях и мониторинга latency OSD. Локальные диски дают лучшую производительность при нулевой отказоустойчивости на уровне хранилища.
Решение удобно принимать от цифр, а не от вкуса. Зафиксируйте RPO и RTO для каждой нагрузки. Если допустимо потерять час данных и пережить простой, локальные диски с ежечасным бэкапом в объектное хранилище закрывают задачу дешевле всего. Если RPO равно нулю, нужна либо синхронная репликация на уровне приложения, либо распределённая СХД с size 3 и min_size 2. Посчитайте, сколько часов в месяц уйдёт на эксплуатацию: 2-4 часа для Longhorn, 8-20 часов для Ceph в кластере средней руки, и умножьте на стоимость инженеро-часа.
Учёт стоимости: TCO и скрытые расходы
TCO складывается из пяти частей: оборудование, лицензии, администрирование, инфраструктурные расходы и бэкапы. Пример для bare-metal: 3 узла по 4 NVMe 3.84 ТБ дают около 46 ТБ сырой ёмкости, с тройной репликацией Ceph остаётся примерно 15 ТБ полезной. К этому добавляются серверы, 25 Гбит/с коммутатор, ИБП, электроэнергия и охлаждение. Если кластер обслуживает выделенный инженер хотя бы на четверть ставки, за три года это сопоставимо со стоимостью железа.
Облако переворачивает структуру расходов. Плата за объём предсказуема, но плата за IOPS и снапшоты в io2 измеряется в единицах на провизионированный IOPS в месяц, а снимки тарифицируются за гигабайт-месяц. Дороже всего обходится трафик между зонами при попытке примонтировать том к узлу в другой зоне, что вообще не сработает. Скрытые статьи: тонкое выделение в Ceph и Longhorn позволяет продать больше ёмкости, чем есть на дисках, и однажды это заканчивается исчерпанием пула и отказом записи для всего кластера.
Экономия, которая работает: снапшоты вместо полных копий, объектное хранилище для бэкапов вместо второго массива, единый пул хранения вместо отдельной СХД под каждый сервис, отказ от лицензий там, где открытые Ceph или Longhorn закрывают задачу.
Практические рекомендации для stateful-приложений и баз данных
Конкретные профили нагрузки диктуют выбор. Ниже ориентиры для четырёх распространённых систем, которые стоит перепроверить тестом.
Выбор хранилища для PostgreSQL и MySQL
Для реляционных СУБД важнее всего запись на 4-8 КБ и latency fsync. Коммит транзакции ждёт ответа диска, поэтому в продакшене цель - p99 коммита в пределах 1-2 мс. Для базы на 100-300 ГБ с умеренной нагрузкой достаточно 5000-10 000 случайных IOPS записи и запаса по latency.
Два рабочих варианта. Первый: локальные NVMe через TopoLVM плюс синхронная репликация PostgreSQL (synchronous_commit: on, synchronous_standby_names) или MySQL Group Replication. Отказ узла приводит к переключению на реплику, RPO равно нулю при подтверждении записи на обоих узлах. Второй: Ceph RBD с size 3 и min_size 2, снапшотами и клонами для быстрых копий стендов. Он проще в части отказоустойчивости, но требует мониторинга latency OSD, чтобы всплески backfill не превращались в рост времени коммита.
Что не стоит делать: держать PGDATA на NFS, ставить одну реплику Longhorn или Ceph с min_size 1 и рассчитывать на снапшоты как на бэкап. CSI-снапшот согласован на уровне блока, то есть crash-consistent, и для СУБД его нужно сочетать с pg_start_backup()/pg_stop_backup() или применять логический дамп. Проверенный путь: VolumeSnapshot для быстрых откатов плюс pgBackRest или mysqldump --single-transaction в объектное хранилище для настоящего восстановления.
Пример StorageClass под PostgreSQL на Ceph RBD:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: ceph-rbd-postgres provisioner: rbd.csi.ceph.com parameters: clusterID: ceph-prod pool: kube-nvme imageFeatures: layering csi.storage.k8s.io/fstype: xfs reclaimPolicy: Retain allowVolumeExpansion: true volumeBindingMode: WaitForFirstConsumer
Обратите внимание на reclaimPolicy: Retain. Для баз данных удаление PVC не должно автоматически уничтожать том, иначе человеческая ошибка в namespace стирает данные быстрее, чем сработает бэкап.
Хранилище для Kafka и Elasticsearch
Kafka ценит пропускную способность и предсказуемую latency последовательной записи. Данные защищены репликацией внутри кластера (replication.factor: 3, min.insync.replicas: 2), поэтому хранилище может быть локальным: NVMe или SATA SSD в режиме RWO. Один брокер на NVMe прокачивает сотни МБ/с, а общий потолок кластера чаще ограничен сетью 10-25 Гбит/с, а не дисками. Сетевые СХД для Kafka берут редко: добавленные миллисекунды бьют по времени подтверждения записи и роняют производительность продюсеров.
Elasticsearch нагружает случайным чтением и постоянными merge-операциями, поэтому ему нужны IOPS и место. Локальные SSD или Ceph RBD подходят одинаково хорошо, потому что у Elasticsearch своя репликация (number_of_replicas). Учитывайте пороги заполнения диска: по умолчанию кластер уходит в read-only при 95% и перестаёт размещать шарды при 85%, так что ёмкость планируется с запасом. Снапшоты Elasticsearch удобно писать в S3-совместимое хранилище, отдельного тома под них не требуется.
Перед продакшеном прогоните нагрузку внутри пода через PVC, а не на голом железе. Минимальный набор для fio:
fio --name=randwrite --ioengine=libaio --direct=1 --bs=4k \
--iodepth=64 --rw=randwrite --size=4G --runtime=120 \
--group_reporting
fio --name=randread --ioengine=libaio --direct=1 --bs=4k \
--iodepth=64 --rw=randread --size=4G --runtime=120 \
--group_reporting
fio --name=seqwrite --ioengine=libaio --direct=1 --bs=1M \
--iodepth=16 --rw=write --size=8G --runtime=120 \
--group_reporting
Смотрите на p99 latency, а не только на средние IOPS: именно хвост распределения определяет время коммита и поведение при пиках. Дополнительный тест - отказ: погасите узел или OSD под нагрузкой и проверьте, что под перезапустился, а том вернулся в строй за предсказуемое время. Сценарии работы с растущими объёмами и сбором данных через Kafka описаны в руководстве хранение больших данных: сбор и миграция.
Типичные ошибки и подводные камни при выборе хранилища
Большинство инцидентов с хранилищем в Kubernetes вызвано не выбором технологии, а деталями настройки. Список того, что ломается чаще всего.
- NFS под базу данных без предварительного измерения fsync latency. Запись формально работает, а коммиты растягиваются на десятки миллисекунд.
- RWX там, где драйвер его не поддерживает. Локальные диски и облачные блочные тома не дают RWX, PVC висит в Pending, а в событиях нет внятного объяснения.
- volumeBindingMode: Immediate для локальных и зональных томов. Под планируется в другой домен доступности и не может примонтировать том.
- Единственная реплика в Longhorn или min_size 1 в Ceph. Отказ одного узла останавливает нагрузку, хотя железо формально исправно.
- Отсутствие мониторинга. Без алертов на Pending PVC, ошибки VolumeAttachment, latency OSD и заполнение пула вы узнаете о проблеме от пользователей.
- Недооценка восстановления в Ceph. Backfill после замены диска поднимает latency по всему кластеру, если сеть и настройки не рассчитаны на такой поток.
- Тонкое выделение без контроля. Пул на 10 ТБ с суммарными PVC на 30 ТБ однажды закончится, и запись откажет сразу у всех потребителей.
- Снапшоты вместо бэкапов. Снимок живёт в том же кластере и в том же пуле, отказ кластера уничтожает и данные, и снимки.
- Одна зона доступности в расчёте на высокую доступность. EBS и аналоги привязаны к зоне, и сбой зоны уносит нагрузку целиком.
- Устаревшие in-tree плагины в манифестах. Они остались от старых релизов и не работают на новых версиях Kubernetes.
Ошибки при миграции и смене хранилища
Смена CSI-драйвера не переносит данные автоматически. PV привязан к драйверу и его пулу, поэтому переезд выглядит так: поднимите новый StorageClass, создайте новый PVC, запустите вспомогательный под с двумя томами и скопируйте данные. Пример команды для побайтового переноса с сохранением прав:
rsync -aHAX --numeric-ids --info=progress2 \ /old-data/ /new-data/
Для баз данных файловое копирование требует остановки записи. Меньше простоя даёт логическая репликация: поднимите реплику на новом хранилище, дождитесь синхронизации, переключите трафик, затем удалите старый том. Для файловых нагрузок сделайте rsync дважды: первый проход по горячим данным, второй - после короткой заморозки записи, и сверьте размеры и контрольные суммы.
Что мешает на этом пути. volumeClaimTemplates в StatefulSet неизменяем, поэтому смену хранилища делают через новый StatefulSet или пересоздание с флагом --cascade=orphan и последующим возвратом подов. Расширение тома работает только в сторону увеличения. Некоторые драйверы не умеют расширяться на лету, и PVC остаётся в FileSystemResizePending до перезапуска пода. Снапшот одного драйвера нельзя восстановить в томе другого драйвера, поэтому снапшоты как инструмент миграции годятся только внутри одной системы хранения.
Перед переездом проверьте восстановление, а не только создание копии: разверните тестовый PVC из бэкапа, поднимите приложение, сверьте количество записей. Обратный путь тоже стоит протестировать, иначе откат превратится в отдельный аварийный проект.
Итоговый алгоритм выбора хранилища для Kubernetes
Рабочая последовательность из семи шагов, которая экономит недели споров.
- Опишите профиль нагрузки: доля случайных и последовательных операций, размер блока, требуемые IOPS, latency p99, объём и скорость роста.
- Определите режим доступа и требования к консистентности: RWO для СУБД и очередей, RWX для общих каталогов, RWOP там, где второй писатель недопустим.
- Зафиксируйте RPO и RTO для каждой нагрузки. Нулевой RPO требует синхронной репликации на уровне приложения или СХД с несколькими копиями.
- Оцените инфраструктуру: bare-metal, облако или гибрид, количество узлов, зоны, сеть, свободные слоты под NVMe.
- Соберите 2-3 кандидата. Типовой шорт-лист: TopoLVM для производительности, Ceph для универсальности, Longhorn для простоты, NFS или CephFS для RWX, облачные диски для managed-кластеров.
- Прогоните fio через PVC в реальном сценарии, добавьте тест отказа узла или реплики и замерьте время восстановления. Сверьте цифры с требованиями из шага 1.
- Посчитайте TCO на три года с учётом администрирования и запускайте в прод с мониторингом, алертами и проверенным восстановлением из бэкапа.
Ориентиры по выбору укладываются в одну строку каждый. Максимальная производительность на своём железе: локальные NVMe с TopoLVM и репликацией в приложении. Универсальное хранилище с RWX и снапшотами: Ceph. Быстрый старт в кластере на 3-5 узлов: Longhorn. Общие файловые ресурсы: NFS или CephFS. Managed-кластер без собственной СХД: блочные диски провайдера. Практическое сравнение Local PV, NFS, Ceph RBD, Longhorn и OpenEBS с примерами StorageClass собрано в отдельном разборе сравнение систем хранения для Kubernetes.
Начните с одного узла и одного тома: поднимите выбранный драйвер, создайте PVC, прогоните fio на 4 КБ с iodepth 64, погасите узел под нагрузкой и посмотрите, как ведёт себя приложение и сколько времени занимает восстановление. Эти три замера дадут больше, чем любое сравнение в интернете.