Выберите продукт

Kubernetes StorageClass, PV и PVC: почему PVC Pending и как это чинить (provisioner, topology, access modes)

Если PVC в Kubernetes остаётся в Pending, значит подходящий PV не найден или не создан. В статье разбираем цепочку StorageClass → PV → PVC, dynamic provisioning через CSI, влияние volumeBindingMode и topology, а также частые ошибки с accessModes. Плюс — какие events смотреть в kubectl describe pvc.
Kubernetes StorageClass, PV и PVC: почему PVC Pending и как это чинить (provisioner, topology, access modes)

Зачем вообще нужны StorageClass, PV и PVC

Подсистема хранения Kubernetes устроена так, чтобы приложение описывало потребность в диске декларативно, а платформа решала, где и как создать том. У этого подхода есть типичный побочный эффект: том не создаётся, PVC висит в Pending, а Pod’ы не стартуют.

Три базовых объекта, которые важно не путать:

  • PV (PersistentVolume) — конкретный ресурс хранения в кластере: диск, LUN, каталог NFS и т.п.
  • PVC (PersistentVolumeClaim) — запрос на хранение: «хочу 20Gi, такой-то режим доступа, такой-то класс».
  • StorageClass — политика, по которой создаются PV (обычно динамически): какой provisioner использовать, какие параметры передать драйверу и как привязывать том к ноде/зоне.

В идеальном сценарии вы создаёте PVC, Kubernetes выбирает StorageClass, внешний CSI-provisioner создаёт PV в бэкенде, и PVC переходит в состояние Bound.

Как выглядит проблема: PVC Pending и что это реально значит

Статус Pending у PVC означает: Kubernetes пока не смог найти существующий PV или не смог создать новый PV под требования PVC. Почти все причины укладываются в несколько категорий:

  • не задан storageClassName и нет default StorageClass;
  • StorageClass есть, но не работает CSI provisioner (контроллерная часть драйвера) или указан неверный provisioner;
  • конфликт параметров (например, accessModes, volumeMode, размер, selector);
  • особенности volumeBindingMode (например, ожидание первого потребителя);
  • ограничения topology (зона/регион/конкретная нода) — том нельзя создать «там, где нужно»;
  • лимиты/квоты/ошибки API хранилища (ресурсы кончились, запрет политиками, нет прав).

Правильный подход — не гадать, а читать события: Kubernetes почти всегда пишет понятную причину в events у PVC и у Pod.

Мини-чеклист диагностики: что выполнить в первую очередь

1) Посмотреть PVC и связанные события

kubectl get pvc -A
kubectl describe pvc -n NAMESPACE PVC_NAME

Команда kubectl describe pvc — самая полезная: внизу вывода будет раздел Events. Там обычно прямо написано, что не так: нет StorageClass, provisioner не найден, ошибка драйвера, ожидание из-за binding mode и т.д.

2) Проверить StorageClass и ключевые поля

kubectl get storageclass
kubectl describe storageclass STORAGECLASS_NAME
kubectl get storageclass STORAGECLASS_NAME -o yaml

Сфокусируйтесь на полях:

  • provisioner — должен совпадать с CSI-драйвером, который реально установлен в кластере;
  • volumeBindingMode — влияет на то, будет ли PVC ждать Pod;
  • parameters — специфичны для драйвера, опечатки и неподдерживаемые значения часто ломают provisioning;
  • allowedTopologies (если есть) — может жёстко ограничить зоны/сегменты.

3) Проверить PV (если provisioning статический или PV уже появился)

kubectl get pv
kubectl describe pv PV_NAME

Если PV существует, но PVC всё равно Pending, обычно PV «не матчится» по условиям: класс, режимы доступа, volumeMode, размер или есть nodeAffinity, которую не удаётся удовлетворить.

4) Проверить состояние CSI-компонентов

При dynamic provisioning важны две части: controller (provisioner/attacher и т.п.) и node plugin. Быстрые проверки:

kubectl get csidrivers
kubectl get pods -A | grep -i csi
kubectl get events -A --sort-by=.metadata.creationTimestamp

Если в events встречается provisioner not found, failed to provision volume или rpc error — почти всегда проблема в CSI-компонентах, их RBAC или параметрах StorageClass.

Схема цепочки StorageClass → PV → PVC и dynamic provisioning через CSI

Если вы поднимаете Kubernetes на выделенных виртуальных машинах и хотите предсказуемое поведение дисков и сети, удобнее сразу закладывать инфраструктуру под stateful-нагрузки. Для этого обычно выбирают VDS — проще контролировать ресурсы и диагностику.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

StorageClass и dynamic provisioning: как это работает на практике

Dynamic provisioning — это автоматическое создание PV при появлении PVC. Внешний provisioner (контроллер CSI) отслеживает новые PVC, делает вызовы к драйверу, а тот создаёт том в бэкенде.

Ключевое поле StorageClass — provisioner. Если строка неверная или драйвер не установлен, PVC останется Pending.

Частые сообщения в events:

no persistent volumes available for this claim and no storage class is set

и:

waiting for a volume to be created either by the external provisioner

Первое обычно означает: в PVC не задан storageClassName, а default StorageClass в кластере отсутствует. Второе — Kubernetes ждёт внешний provisioner, но тот не создаёт PV (не запущен контроллер, ошибка прав, неверные parameters или отказ/лимит со стороны хранилища).

Проверка default StorageClass

Если вы иногда создаёте PVC без storageClassName, вам важно понимать, есть ли default-класс:

kubectl get storageclass -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.annotations.storageclass\.kubernetes\.io/is-default-class}{"\n"}{end}'

Если default нет — поведение предсказуемее: просто указывайте storageClassName явно во всех манифестах.

Volume binding mode: Immediate vs WaitForFirstConsumer

volumeBindingMode — частая причина «почему PVC Pending, хотя всё вроде настроено». Особенно в кластерах с зонами или с локальными томами.

  • Immediate — PV создаётся сразу при создании PVC.
  • WaitForFirstConsumer — PVC может оставаться Pending, пока не появится Pod, который использует PVC, и пока Scheduler не выберет ноду/зону. Только после этого будет выбран подходящий топологический домен и создаться PV.

Практический симптом: вы создали PVC и ждёте Bound, но видите Pending без явных ошибок. Если StorageClass использует WaitForFirstConsumer — это нормально. Поднимите Pod/StatefulSet, который монтирует PVC, и уже потом смотрите события у Pod и PVC.

Topology: почему том нельзя создать в нужной зоне или на нужной ноде

Topology — это ограничения «где может жить том». В облаках это обычно зона/регион, в on-prem — пул/стойка/узел, для локальных дисков — конкретная нода.

Topology проявляется минимум в двух местах:

  • в StorageClass — через allowedTopologies и/или параметры драйвера;
  • в PV — через nodeAffinity (ограничения по нодам/зонам).

Симптомы конфликтов topology

  • PVC Pending, в events упоминания о невозможности выбрать сегмент topology или создать том в нужной зоне;
  • Pod тоже Pending из-за планирования, а рядом «подвисает» PVC;
  • PV создан, но Pod не планируется, потому что PV привязан к зоне A, а Pod из-за affinity/taints фактически может попасть только в зону B.

Что проверять руками

kubectl get nodes -o wide
kubectl get nodes --show-labels
kubectl describe pod -n NAMESPACE POD_NAME
kubectl get pv PV_NAME -o yaml

В YAML PV ищите nodeAffinity и topology-ключи вроде topology.kubernetes.io/zone или topology.kubernetes.io/region (точные ключи зависят от драйвера и окружения).

Если у вас небольшой кластер на виртуальных машинах, топология часто «ломается» из-за несогласованных меток нод. В таких случаях либо упрощайте StorageClass (без излишних ограничений), либо приводите метки/планирование в порядок так, чтобы stateful-нагрузка не пыталась переезжать туда, где том создать нельзя.

Access modes: почему ReadWriteOnce не монтируется «как вы ожидали»

Access modes описывают, как том может быть примонтирован к Pod’ам/нодам. Это частая причина ситуаций «добавил реплик — часть Pod’ов не стартует».

  • ReadWriteOnce (RWO) — чтение/запись, обычно присоединение к одной ноде одновременно.
  • ReadOnlyMany (ROX) — только чтение многим.
  • ReadWriteMany (RWX) — чтение/запись многим (обычно сетевое/распределённое хранилище).
  • ReadWriteOncePod — чтение/запись только одному Pod (поддержка зависит от версии Kubernetes и драйвера).

Ключевой момент: режим в PVC — это запрос. Драйвер обязан уметь его выполнить. Если вы запросили RWX, а StorageClass создаёт только «обычные» блочные диски с RWO, provisioning может завершиться ошибкой или том будет непригоден для ваших ожиданий.

Как быстро понять, что именно не совпало

kubectl describe pvc -n NAMESPACE PVC_NAME
kubectl get pvc -n NAMESPACE PVC_NAME -o yaml

Сравните spec.accessModes у PVC и у PV (если PV уже есть). Если PV не появляется — события у PVC обычно явно говорят, что запрошенный режим не поддерживается.

Если у вас много небольших сайтов/панелей и нужен простой сценарий с предсказуемыми лимитами и бэкапами, часто удобнее разместить вспомогательные сервисы на виртуальном хостинге, а stateful-компоненты кластера вынести на отдельные узлы.

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

PV/PVC совпадение: какие поля должны «сойтись», чтобы PVC стал Bound

При статическом provisioning (PV создан заранее) Kubernetes матчится по набору правил. Чаще всего «мимо» из-за:

  • несовпадения storageClassName (или один объект без класса);
  • несовпадения accessModes;
  • разного volumeMode (Filesystem/Block);
  • запрошенный размер PVC больше, чем capacity PV;
  • PVC содержит selector, а PV не подходит по label’ам;
  • PV уже связан с другим PVC или находится в состоянии, которое не позволяет привязку.

Если вы подозреваете статический сценарий — выгрузите YAML обоих объектов и сравните ключевые поля. Затем вернитесь к events: они почти всегда подскажут, почему матчинг не произошёл.

Типовые причины PVC Pending и быстрые действия

Причина 1: не указан StorageClass и нет default

Симптом: PVC без storageClassName, в events сообщения о том, что storage class не задан.

Действия: укажите storageClassName в PVC или назначьте default StorageClass (осторожно: это влияет на весь кластер).

Причина 2: неверный provisioner или CSI-драйвер не работает

Симптом: ошибки provisioner, rpc error, PV не создаётся при dynamic provisioning.

Действия: проверьте Pods CSI-контроллера и node-плагина, RBAC, логи компонентов драйвера.

Причина 3: WaitForFirstConsumer, но Pod ещё не создан

Симптом: PVC выглядит «зависшим» без явных ошибок.

Действия: создайте Pod/StatefulSet, который использует PVC, и анализируйте события у Pod и PVC вместе.

Причина 4: topology конфликтует с размещением Pod

Симптом: Pod не планируется или PV создан в зоне/на ноде, где Pod оказаться не может.

Действия: проверяйте метки нод, affinity/anti-affinity, taints/tolerations, allowedTopologies в StorageClass, nodeAffinity в PV.

Причина 5: access modes не поддерживаются вашим типом хранилища

Симптом: запросили RWX, а класс даёт только RWO.

Действия: меняйте accessModes под возможности драйвера или выбирайте другой StorageClass/бэкенд.

Полезные команды: собрать максимум фактов за 2–3 минуты

kubectl get pvc -A -o wide
kubectl describe pvc -n NAMESPACE PVC_NAME
kubectl get storageclass -o wide
kubectl get storageclass STORAGECLASS_NAME -o yaml
kubectl get pv -o wide
kubectl get events -A --sort-by=.metadata.creationTimestamp
kubectl describe pod -n NAMESPACE POD_NAME

Если цель — быстро локализовать проблему, начинайте с kubectl describe pvc (events), затем проверьте StorageClass (в первую очередь provisioner и volumeBindingMode), дальше — Pod (scheduling) и PV (nodeAffinity/topology).

Команды kubectl и события Kubernetes для диагностики PVC Pending

Практика: как проектировать StorageClass и PVC, чтобы Pending случался реже

  • Явно указывайте storageClassName в продакшн-манифестах, чтобы поведение не менялось при появлении/смене default StorageClass.
  • Выбирайте WaitForFirstConsumer для зональных/локальных хранилищ: меньше шанс создать том «не в той зоне».
  • Документируйте поддерживаемые access modes для каждого StorageClass: это экономит часы отладки при масштабировании StatefulSet.
  • Следите за topology-метками нод: любые перекосы в метках или ограничениях планировщика быстро вылезают в PVC/POD Pending.
  • Делайте отдельные StorageClass под разные профили: быстрые диски, дешёвые диски, «только RWO», «RWX», локальные тома и т.д.

Если вы отлаживаете Kubernetes-хранилище на одиночном сервере

В небольших инсталляциях (одна-две ноды) особенно важно, чтобы StorageClass и драйвер не «ожидали» несуществующих зон/сегментов. Если вы строите кластер на виртуальных машинах, проверьте, что:

  • CSI-драйвер рассчитан на ваш тип хранения и корректно установлен;
  • в кластере есть корректные node labels для topology (или StorageClass не требует их);
  • volumeBindingMode выбран осознанно под сценарий;
  • parameters StorageClass соответствуют возможностям бэкенда.

Если параллельно приходится разбираться с моделью изоляции и ограничениями рантайма, держите под рукой материал про изоляцию контейнеров через gVisor и Firecracker: это иногда влияет на дизайн stateful-нагрузок и выбор инфраструктуры.

Короткое резюме

PVC Pending — это не «магия Kubernetes», а конкретный сигнал: подходящий PV не найден или не создан. В большинстве случаев ответ находится внизу kubectl describe pvc в разделе Events.

Дальше всё сводится к трём группам проверок: provisioner/CSI (создаём ли том вообще), volume binding mode (когда и где создаём том) и topology/access modes (можно ли подключить том в нужном месте и нужным способом).

Поделиться статьей

Вам будет интересно

OpenSSH hardening 2026: KEX, hostkey, CA подписи и FIDO2-ключи без боли для легаси OpenAI Статья написана AI (GPT 5)

OpenSSH hardening 2026: KEX, hostkey, CA подписи и FIDO2-ключи без боли для легаси

Пошагово поджимаем OpenSSH в 2026: инвентаризация через sshd -T, выбор современного KEX и hostkey, запрет ssh-rsa без поломки RSA ...
systemd-networkd: policy routing и таблицы маршрутизации (ip rule, multiple gateways, source routing) OpenAI Статья написана AI (GPT 5)

systemd-networkd: policy routing и таблицы маршрутизации (ip rule, multiple gateways, source routing)

Разберём, как настроить policy routing через systemd-networkd: отдельные таблицы маршрутов, правила ip rule по исходному адресу и ...
Kubernetes: ImagePullBackOff из‑за Docker Hub rate limit — mirror и registry cache на практике OpenAI Статья написана AI (GPT 5)

Kubernetes: ImagePullBackOff из‑за Docker Hub rate limit — mirror и registry cache на практике

ImagePullBackOff нередко вызван Docker Hub pull rate limit: кластер внезапно перестаёт скачивать образы, особенно при автоскейле и ...