ZIM-НИЙ SAAALEЗимние скидки: до −50% на старт и −20% на продление
до 31.01.2026 Подробнее
Выберите продукт

Kubernetes PV/PVC: Pending, FailedMount, ReadOnly и застрявшие finalizers — практический разбор

Если PVC завис в Pending, поды получают FailedMount, том внезапно становится ReadOnly или удаление PV/PVC висит на finalizers — причина часто в StorageClass, CSI и привязках. Ниже — практичная диагностика и безопасные шаги восстановления.
Kubernetes PV/PVC: Pending, FailedMount, ReadOnly и застрявшие finalizers — практический разбор

Проблемы со storage в Kubernetes часто выглядят одинаково: Pending у PVC, FailedMount у пода, внезапный ReadOnly у файловой системы или «вечное удаление» PV/PVC из-за finalizers. На практике это разные стадии одного lifecycle: provision → bind → attach → mount → cleanup. Если понять, на каком этапе «застряло», решение обычно находится быстро.

Ниже — рабочий чеклист: что смотреть в объектах и событиях, какие проверки безопасны, и где начинаются действия с риском для данных (detach/force-delete/finalizers).

Карта симптомов: где именно застряло

Сначала классифицируйте проблему по стадиям — это экономит время и убирает лишние гипотезы.

  • PVC Pending — том ещё не создан или не связан с PV (provision/binding).
  • Pod FailedMount — PV/PVC уже существуют, но под не может смонтировать том (attach/mount).
  • ReadOnly — том смонтирован, но запись невозможна (политика доступа или ошибки ФС/устройства).
  • PV/PVC Terminating + finalizers — Kubernetes ждёт cleanup (detach/delete) и блокирует удаление.
  • VolumeAttachment завис/ошибка — типично для CSI attach/detach после падений нод или проблем контроллеров.

Базовая диагностика за 10 минут (без предположений)

Наша цель — собрать факты: состояние PVC/PV, события, StorageClass и наличие CSI-attach через VolumeAttachment. Начинайте именно так даже в «очевидных» случаях: по событиям часто видно первопричину.

1) Проверяем PVC/PV и события

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

В describe важны блоки Events и поля:

  • storageClassName у PVC
  • volumeName (если уже забинден)
  • accessModes и volumeMode
  • persistentVolumeReclaimPolicy у PV

2) Проверяем StorageClass и provisioner

kubectl get storageclass
kubectl describe storageclass SC_NAME

Смотрите provisioner, volumeBindingMode и параметры драйвера. Критичные моменты:

  • volumeBindingMode: WaitForFirstConsumer — PVC может быть Pending до появления пода и выбора ноды/зоны (это не всегда ошибка).
  • allowVolumeExpansion и корректность параметров (тип диска, зона/пул, fsType и т.д.).

3) Если проблема на уровне пода: describe pod

kubectl describe pod -n NAMESPACE POD_NAME

Ищите события и ошибки: FailedMount, AttachVolume.Attach failed, MountVolume.MountDevice failed, rpc error. Это уже зона ответственности CSI и конкретной ноды.

4) Проверяем CSI-объекты: VolumeAttachment

kubectl get volumeattachment
kubectl describe volumeattachment VA_NAME

Если VolumeAttachment в ошибке или «висит» при удалении, это прямой индикатор проблем attach/detach (часто после аварий нод).

5) Проверяем компоненты CSI (поды и логи)

kubectl get pods -n kube-system
kubectl get pods -A | grep -i csi

Дальше — точечные логи у controller/node-плагинов (названия зависят от драйвера):

kubectl logs -n kube-system POD_NAME -c CONTAINER_NAME --tail=200

Чаще всего в логах всплывает одно из: проблемы авторизации к API облака/СХД, нехватка прав у ServiceAccount, topology/zone mismatch, таймауты, несовпадение volumeHandle, сбои node-plugin.

Если кластер крутится на собственных серверах, под Kubernetes обычно удобнее держать отдельные воркеры на VDS: проще контролировать ядро, модули, iSCSI/NFS-клиенты и версию container runtime — а значит, меньше сюрпризов на этапе mount.

Пример диагностики: события PVC Pending и ошибки provisioner в kubectl describe

PVC Pending: почему том не создаётся или не биндится

Pending PVC означает: Kubernetes не смог подобрать подходящий PV или динамически создать новый. Ниже — типовые причины и короткие проверки.

1) Не найден или не работает provisioner (StorageClass указывает на несуществующий CSI)

Симптомы в describe pvc: события про failed to provision volume, no volume plugin matched, timed out waiting for external-provisioner.

  • Проверьте, что CSI-драйвер установлен и его controller-поды в Running.
  • Сверьте provisioner в StorageClass — он должен совпадать с реальным драйвером.
  • Посмотрите логи external-provisioner (часто контейнер называется csi-provisioner).

2) WaitForFirstConsumer: Pending — это «норма», пока нет планирования

Если volumeBindingMode = WaitForFirstConsumer, PVC будет Pending до тех пор, пока под не будет создан и не выберется нода/зона. Ошибка начинается, когда под создан, но планировщик не может выбрать ноду из-за ограничений.

kubectl describe storageclass SC_NAME
kubectl describe pod -n NAMESPACE POD_NAME

Смотрите события планировщика: часто корень в nodeSelector, taints/tolerations, нехватке ресурсов или topology-ограничениях CSI.

3) Несовместимость accessModes/volumeMode/size

  • PVC просит ReadWriteMany, а драйвер умеет только ReadWriteOnce.
  • Указан volumeMode: Block, но приложение ожидает filesystem.
  • Запрошен размер, который драйвер или пул не может выделить (квоты, лимиты, free space).

Сверяйте спецификацию PVC и возможности StorageClass/CSI (документация драйвера плюс события provisioner).

4) Static PV не подходит (mismatch storageClassName/labels/claimRef)

Для заранее созданного PV частая ошибка — PV и PVC не совпадают по storageClassName, accessModes, volumeMode или capacity. Ещё один «тихий убийца» — старый claimRef на PV.

kubectl get pv PV_NAME -o yaml
kubectl get pvc -n NAMESPACE PVC_NAME -o yaml

FailedMount: PVC Bound, но под не может смонтировать том

FailedMount — это этап после binding. Причины обычно делятся на «attach не случился» и «attach есть, но mount не прошёл».

1) Attach/Detach не проходит: смотрим VolumeAttachment

kubectl get volumeattachment
kubectl describe volumeattachment VA_NAME
  • attached: false и текст ошибки в status
  • какая нода указана в nodeName (важно при «том держит другая нода»)

2) Том «занят» другой нодой (multi-attach error)

Классика для ReadWriteOnce: под переехал на другую ноду, а хранилище всё ещё считает том подключенным к старой. В событиях пода обычно есть Multi-Attach error.

  • Убедитесь, что старый под действительно удалён и больше не держит PVC.
  • Проверьте, жива ли старая нода: если нода умерла, detach может зависнуть.
  • Удалять проблемный VolumeAttachment имеет смысл только когда вы уверены, что том не используется на старой ноде (иначе можно получить повреждение ФС).

3) MountDevice/MountVolume: fsType, утилиты на ноде, доступ к секретам

Если attach успешен, но mount падает, в событиях часто фигурируют:

  • ошибки формата/ФС, неверный fsType
  • отсутствие нужных утилит на ноде (зависит от драйвера)
  • ошибки прав доступа/секретов (часто для сетевых хранилищ)

Ключевой шаг — логи node-plugin CSI на конкретной ноде (обычно DaemonSet). Найдите pod node-plugin, запущенный на нужной ноде, и посмотрите kubectl logs.

4) Topology/zone mismatch (особенно при WaitForFirstConsumer)

Если том создан в определённой зоне/топологии, а под планируется на ноду в другой зоне, получите бесконечные попытки attach/mount. Проверяйте:

  • аннотации/топологию PV
  • ограничения StorageClass
  • labels нод (topology keys) и правила планирования пода
Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

ReadOnly: почему том внезапно стал только для чтения

Ситуация «вчера писали, сегодня read-only» пугает сильнее всего. Но Kubernetes редко является первопричиной: чаще это защита данных на уровне ядра, файловой системы или backend-хранилища.

1) Файловая система переведена в read-only из-за I/O ошибок

При ошибках ввода-вывода ext4/xfs могут переключиться в ro. Kubernetes лишь видит, что записи не проходят.

  1. Определите масштаб: один под/том или массово на ноде (второе чаще про проблемы диска/СХД/сетевого пути).
  2. Посмотрите события пода и логи приложения (ошибки записи).
  3. Планируйте обслуживание: проверка и восстановление ФС (например, fsck/xfs_repair) обычно делаются вне прод-окна и зависят от типа тома и способа подключения.

2) Ошибка режима доступа: пытаемся писать в RO-том

Проверьте, не примонтирован ли том как read-only на уровне манифеста:

kubectl get pod -n NAMESPACE POD_NAME -o yaml

Ищите в volumeMounts поле readOnly: true. Также проверьте, не используете ли один и тот же PVC одновременно в нескольких местах, где драйвер ограничивает запись.

3) Snapshot/clone/restore: ограничения после восстановления

Зависит от CSI и backend. Иногда после restore нужны корректные параметры в StorageClass или другой режим доступа. Здесь почти всегда помогают логи CSI-controller и точный текст ошибок в событиях.

Схема жизненного цикла тома: provision, attach/mount и cleanup с finalizers

Finalizers: почему PV/PVC/VolumeAttachment «не удаляются»

Finalizer — механизм Kubernetes, который не даёт объекту исчезнуть, пока контроллер не выполнит «последнее действие»: detach, delete, cleanup на backend.

Снятие finalizers — это принудительное завершение lifecycle. Делайте это только когда вы уверены, что контроллер не выполнит cleanup сам, и вы понимаете последствия для данных и ресурсов (например, «залипший» диск может остаться на backend и продолжать тарифицироваться).

1) Выясняем, какой finalizer мешает

kubectl get pvc -n NAMESPACE PVC_NAME -o jsonpath='{.metadata.finalizers}'
kubectl get pv PV_NAME -o jsonpath='{.metadata.finalizers}'
kubectl get volumeattachment VA_NAME -o jsonpath='{.metadata.finalizers}'

Часто встречаются finalizers защиты PV/PVC и finalizers внешнего провижионера/CSI.

2) Смотрим reclaim policy: что будет с данными

persistentVolumeReclaimPolicy определяет судьбу backend-ресурса:

  • Delete — удаление PVC/PV должно удалить реальный диск/шару (если контроллер работает).
  • Retain — диск останется, PV перейдёт в Released, дальше всё вручную.
kubectl get pv PV_NAME -o jsonpath='{.spec.persistentVolumeReclaimPolicy}'

3) Типовые причины stuck finalizer

  • CSI-controller не работает или не имеет прав удалять/отвязывать том на backend.
  • VolumeAttachment завис: backend считает том подключенным, detach не проходит.
  • Нода умерла, а контроллер не может корректно завершить detach.
  • Ресурс на backend удалён вручную, а Kubernetes ждёт подтверждение удаления.

4) Минимальная безопасная последовательность перед принудительным снятием

  1. Убедитесь, что поды, использующие PVC, удалены или остановлены.
  2. Проверьте, нет ли активного attach на другой ноде (через VolumeAttachment и события).
  3. Проверьте состояние CSI-подов и их логи. Иногда достаточно восстановить права/секреты или перезапустить контроллер.
  4. Поймите последствия persistentVolumeReclaimPolicy и нужно ли сохранить данные.

5) Как снять finalizer точечно (когда проверки уже сделаны)

Самый аккуратный вариант — JSON patch, чтобы убрать список finalizers:

kubectl patch pvc -n NAMESPACE PVC_NAME --type=json -p='[{"op":"remove","path":"/metadata/finalizers"}]'
kubectl patch pv PV_NAME --type=json -p='[{"op":"remove","path":"/metadata/finalizers"}]'
kubectl patch volumeattachment VA_NAME --type=json -p='[{"op":"remove","path":"/metadata/finalizers"}]'

Если remove не проходит из-за отсутствия поля, задайте пустой список:

kubectl patch pvc -n NAMESPACE PVC_NAME --type=merge -p='{"metadata":{"finalizers":[]}}'

VolumeAttachment: как понять, что именно «держит» том

Когда FailedMount или удаление PV/PVC упирается в attach/detach, объект VolumeAttachment часто является лучшей подсказкой. Поля, на которые стоит смотреть в describe:

  • attacher (какой драйвер)
  • nodeName (куда пытается attach)
  • сообщение об ошибке в статусе

Практика: убедитесь, что для конкретного PV/тома активен ровно один attachment и он указывает на ожидаемую ноду. Если attachments «размножились» после аварии, сначала фиксируйте реальное состояние на backend, и только потом чистите объекты в Kubernetes.

Чеклист: быстрые решения по симптомам

PVC Pending

  • Проверить storageClassName и provisioner у StorageClass.
  • Учесть WaitForFirstConsumer: создать под и посмотреть scheduling events.
  • Сверить accessModes/volumeMode/размер с возможностями драйвера.
  • Проверить квоты/лимиты namespace и права CSI (по логам provisioner/controller).

FailedMount

  • Посмотреть kubectl describe pod и точный текст ошибки.
  • Проверить VolumeAttachment, статус attached и multi-attach.
  • Посмотреть логи CSI node-plugin на нужной ноде.
  • Проверить topology/zone и ограничения планирования.

ReadOnly

  • Проверить readOnly: true в volumeMounts.
  • Искать признаки I/O ошибок и деградации backend-хранилища.
  • Планировать проверку/восстановление ФС по процедуре, подходящей вашему типу тома.

Stuck finalizer / Terminating

  • Сначала выяснить persistentVolumeReclaimPolicy и требования к сохранению данных.
  • Убедиться, что поды удалены и нет активного attach.
  • Восстановить работу CSI-controller (часто достаточно починить права/секреты или перезапустить компоненты).
  • Только потом — снять finalizers патчем.
FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Нюансы, о которых часто забывают

Resize/expand и «подвисшие» операции

При включенном расширении томов (allowVolumeExpansion) PVC может зависать в промежуточных состояниях, если node-side расширение не происходит (например, под не перезапущен или драйвер требует re-mount). Если видите события про resize, проверьте требования конкретного CSI-драйвера и состояние пода.

Retain-policy и «кладбище» Released PV

Если persistentVolumeReclaimPolicy = Retain, удаление PVC не удалит данные, но PV останется в Released и не будет автоматически переиспользован, пока вы вручную не очистите claimRef и не приведёте PV в пригодное состояние. Это нормально, но часто воспринимается как утечка ресурсов.

Когда не стоит чинить «в лоб»

Если есть признаки деградации хранилища (I/O ошибки, массовые ReadOnly, нестабильный attach), сначала стабилизируйте backend. Иначе «патчи finalizers» и ручные detach будут маскировать симптомы и повышать риск потери данных.

Итог: как быстрее всего прийти к причине

В задачах с PV/PVC выигрывает дисциплина: начинайте с kubectl describe и событий, затем сопоставляйте StorageClass → CSI → VolumeAttachment → pod events. Pending обычно про provision/binding и StorageClass, FailedMount — про attach/mount и VolumeAttachment, ReadOnly — про состояние ФС/доступ, а stuck finalizer — про незавершённый cleanup.

Если параллельно усиливаете изоляцию и безопасность контейнеров на нодах (чтобы проблемные workload’ы меньше влияли на окружение), полезно разобраться в подходах к изоляции: gVisor и Firecracker для изоляции контейнеров.

Хотите адаптацию чеклиста под ваш CSI (Ceph RBD, NFS, Longhorn, OpenEBS, облачные диски): подготовьте вывод kubectl describe pvc, kubectl describe pod и один kubectl describe volumeattachment — и можно разбирать по шагам.

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

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

Nginx 444 и 403: блокируем ботов и сканеры через map, geo, deny и return OpenAI Статья написана AI (GPT 5)

Nginx 444 и 403: блокируем ботов и сканеры через map, geo, deny и return

Разбираем, когда выбирать nginx 444, а когда 403, и как собрать аккуратную схему блокировок на map и geo. Покажу deny и return 444 ...
SSH Permission denied (publickey): проверяем sshd_config и ~/.ssh без лишней боли OpenAI Статья написана AI (GPT 5)

SSH Permission denied (publickey): проверяем sshd_config и ~/.ssh без лишней боли

Permission denied (publickey) обычно сводится к трём причинам: клиент отправляет не тот ключ, сервер не принимает ключевую аутенти ...
systemd restart loop: как остановить бесконечные рестарты и настроить Restart/StartLimitBurst OpenAI Статья написана AI (GPT 5)

systemd restart loop: как остановить бесконечные рестарты и настроить Restart/StartLimitBurst

Если сервис в systemd уходит в бесконечный перезапуск, обычно виноваты неверный ExecStart, права/пользователь, неподходящий Type= ...