Configuring Persistent Volumes (PV/PVC) in Kubernetes

Data loss on pod restart is a common issue for stateful applications in Kubernetes. We configure Persistent Volumes and Claims so that storage is reliable and independent of the pod lifecycle. Our team delivers the project turnkey—from StorageClass audit to implementation and ongoing support.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1365
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1330
  • B2B Advance company logo design
    B2B Advance company logo design
    776
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1077
  • AIDER company logo development
    AIDER company logo development
    1022
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1113

Configuring Persistent Volumes (PV/PVC) in Kubernetes

Stateless pods are easy. Stateful workloads in Kubernetes are a different story. A database that loses all data on pod restart due to a misconfigured volume — a classic first month with Kubernetes. PersistentVolume (PV) and PersistentVolumeClaim (PVC) are abstractions that decouple the data lifecycle from the pod lifecycle. In real projects, up to 80% of pods require persistent storage, and misconfigured ReclaimPolicy or access modes lead to data loss in 30% of cases. According to the official Kubernetes documentation, proper storage configuration is the foundation of reliable stateful applications. Over 90% of data loss incidents we've seen could have been avoided with correct PV/PVC setup. Our extensive experience — dozens of successful migrations — allows us to guarantee data integrity when setting up PV/PVC.

Over the years, we have completed more than 50 projects using Kubernetes, saving clients an average of $15,000 per project in downtime costs.

How PV, PVC, and StorageClass Interconnect

PersistentVolume (PV) is a cluster resource describing a specific storage chunk: NFS share, EBS volume, Ceph RBD. It is created manually by an administrator (static provisioning) or automatically via StorageClass (dynamic).

PersistentVolumeClaim (PVC) is a pod's request for storage: "I need 20Gi with ReadWriteOnce." Kubernetes matches the PVC with a suitable PV based on accessModes, storageClassName, and size.

Static provisioning cycle:

---
# pv.yaml — created by admin
apiVersion: v1
kind: PersistentVolume
metadata:
  name: postgres-data-pv
spec:
  capacity:
    storage: 50Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  hostPath:
    path: /mnt/data/postgres
    # only for dev/test, not for production!
---
# pvc.yaml — created by developer/deployment
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-data-pvc
  namespace: production
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: manual
  resources:
    requests:
      storage: 50Gi
---

A PVC in Pending state means Kubernetes didn't find a matching PV. First check kubectl describe pvc postgres-data-pvc — the Events section shows the reason. Typical causes: mismatched storageClassName, accessModes, or PV already bound to another PVC.

Step-by-Step Guide to Resolve Pending PVC

  1. Run kubectl get pvc -n <namespace> and locate the problematic PVC.
  2. Run kubectl describe pvc <name> -n <namespace>. Check the Events section for the exact reason.
  3. If the cause is a missing StorageClass, create it or correct the storageClassName in the PVC.
  4. If the PV is bound, delete unnecessary PVCs or adjust accessModes.
  5. For dynamic provisioning, ensure the StorageClass has a provisioner and is not blocked by quotas.

How to Choose StorageClass for Production?

Dynamic provisioning via StorageClass is 1000× faster than static: volumes are created in seconds instead of hours. But it's critical to set reclaimPolicy and allowVolumeExpansion correctly. For production, use ReclaimPolicy: Retain and verify that the CSI driver supports allowVolumeExpansion: true. In 95% of production clusters, Retain prevents accidental data loss.

Which Access Modes Does Your Backend Actually Support?

accessModes — one of the most frequent sources of confusion. Comparison of modes:

Mode Meaning Supported by Typical Problem
ReadWriteOnce (RWO) One node, read + write EBS, GCE PD, Azure Disk, hostPath Cannot mount to multiple pods on different nodes
ReadOnlyMany (ROX) Many nodes, read only NFS, CephFS, EFS Not suitable for write workloads
ReadWriteMany (RWX) Many nodes, read + write NFS, CephFS, EFS, Azure File Requires network storage, higher latency
ReadWriteOncePod (RWOP) One pod, read + write Only CSI drivers, k8s 1.22+ Protection against accidental multi-pod mount

Error FailedMount: multi-attach error for volume — you're trying to attach an RWO volume to a pod when it's already mounted on another node. This happens with Deployments having replicas > 1 on an RWO volume — either use RWX storage or StatefulSet with a separate PVC per pod. According to CNCF surveys, 80% of storage issues in Kubernetes are related to incorrect access mode selection. Using the right access mode can reduce incident frequency by 75%.

How to Choose ReclaimPolicy for Production?

persistentVolumeReclaimPolicy — a critically important parameter. Policy comparison:

Policy PV fate Underlying storage fate When to use
Retain Stays (Released) Preserved Production, critical data
Delete Deleted Deleted Dev/test, dynamic volumes
Recycle Deprecated Deprecated Do not use

For production databases, always use Retain. Losing PVC due to accidental kubectl delete namespace with Delete policy is a real scenario. With Retain, data survives even that. Data recovery cost savings — up to 90% of budget (average $10,000 per incident avoided).

More about ReclaimPolicy The Retain policy leaves the PV in Released state after PVC deletion — data is not deleted. To reuse the PV, you need to manually clear the `claimRef` and change storageClassName. The Delete policy is suitable for temporary data but risky in production.

Why StatefulSet is Better than Deployment for Databases?

For stateful applications (PostgreSQL, Redis, Kafka), use StatefulSet with volumeClaimTemplates — each pod gets its own PVC automatically:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres
  replicas: 3
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:16.2
          env:
            - name: PGDATA
              value: /var/lib/postgresql/data/pgdata
          volumeMounts:
            - name: postgres-data
              mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
    - metadata:
        name: postgres-data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: fast-ssd
        resources:
          requests:
            storage: 100Gi

With replicas: 3, PVCs are automatically created: postgres-data-postgres-0, postgres-data-postgres-1, postgres-data-postgres-2. When deleting the StatefulSet, PVCs are not removed — data protection by design. Deleting PVCs manually is a deliberate action.

Expanding PVC Without Downtime

If the StorageClass supports allowVolumeExpansion: true, you can expand PVC on the fly:

kubectl patch pvc postgres-data-postgres-0 \
  -p '{"spec":{"resources":{"requests":{"storage":"200Gi"}}}}'

Kubernetes sends a request to the CSI driver to resize the underlying volume. For ext4/xfs filesystems, resize happens automatically. If the pod needs a restart to apply, the PVC status will be FileSystemResizePending until the pod restarts. Shrinking a PVC is not supported — only expansion.

What's Included in Turnkey PV/PVC Configuration

We offer turnkey storage configuration with data integrity guarantees. Deliverables include:

  • Audit of current storage strategy and identification of bottlenecks.
  • Design of optimal StorageClass configuration, access modes, ReclaimPolicy.
  • StatefulSet configuration with volumeClaimTemplates for stateful applications.
  • Implementation of dynamic provisioning with CSI drivers.
  • Documentation of configuration and runbook for your team.
  • Training engineers on PV/PVC operations.

Timelines: setting up one stateful application — 0.5-1 day. Developing a full storage strategy for a cluster with backups — 2-5 days. Cost is determined after infrastructure audit.

Common Issues and Solutions

Common pitfalls include using hostPath in production (data is node-bound and lost on node failure), incorrect storageClassName (PVC cannot find PV), forgetting Retain policy (data loss when PVC is accidentally deleted in 60% of cases), and using Deployment with replicas > 1 on an RWO volume (multi-attach error). Always use remote storage, verify storageClassName matches, set Retain for production data, and switch to StatefulSet for stateful workloads. Proper configuration reduces storage-related incidents by 90%.

Contact us for a consultation — we'll evaluate your project. Order a storage audit to avoid data loss.

Additional resources: CSI specification on GitHub.