Persistent Volume Claims (PVC)

A PersistentVolumeClaim (PVC) is how a Pod requests storage from the cluster. The developer specifies how much storage they need and what access mode is required; Kubernetes finds a matching PersistentVolume and binds the PVC to it. The developer does not need to know whether the storage is backed by NFS, a cloud disk, or a local directory — they just request storage and mount it. This separation of concerns is the design intent: administrators manage PVs, developers consume PVCs.

What is a PVC?

PVC binding process:

  Developer creates PVC:
    "I need 5Gi of ReadWriteOnce storage, storageClass=standard"
                    |
                    v
  Kubernetes control plane searches for matching PV:
    - capacity >= 5Gi
    - accessMode = ReadWriteOnce
    - storageClass = standard
                    |
         match found? yes
                    |
                    v
  PVC STATUS: Bound  ←→  PV STATUS: Bound
  (they are now exclusively linked)
                    |
                    v
  Pod mounts PVC as a volume

Creating a PVC

nano mysql-pvc.yaml

mysql-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: local-path    # Use k3s default, or "standard" on cloud
kubectl apply -f mysql-pvc.yaml

# Check PVC status:
kubectl get pvc

kubectl get pvc output

NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mysql-pvc   Bound    pvc-4a2b8c1d-e3f4-5678-abcd-ef1234567890   10Gi       RWO            local-path     15s
# STATUS = Bound means a PV was found and allocated
# If STATUS = Pending, either:
# - No matching PV exists (and no StorageClass for dynamic provisioning)
# - No StorageClass matches the requested storageClassName
# Debug:
kubectl describe pvc mysql-pvc    # Shows events explaining why it is Pending

Using a PVC in a Pod

nano mysql-deployment.yaml

mysql-deployment.yaml — using the PVC

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1    # Only 1 replica for RWO volumes (one node can mount at a time)
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: password
          volumeMounts:
            - name: mysql-storage
              mountPath: /var/lib/mysql    # MySQL data directory
      volumes:
        - name: mysql-storage
          persistentVolumeClaim:
            claimName: mysql-pvc           # Reference the PVC by name

StatefulSets and PVCs

# StatefulSets automatically create PVCs per replica using volumeClaimTemplates:
# (Used for databases, Kafka, Elasticsearch — anything that needs unique storage per replica)
nano mysql-statefulset.yaml

mysql-statefulset.yaml — automatic PVC per replica

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql-cluster
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 10Gi
# Creates: data-mysql-cluster-0, data-mysql-cluster-1, data-mysql-cluster-2
# Each replica gets its own dedicated PVC

Conclusion

For stateless applications, use regular Deployments with a single PVC. For stateful applications that need unique storage per replica (databases, message queues), use StatefulSets with volumeClaimTemplates — they automatically create and manage one PVC per Pod. Never run a database with replicas: 3 on an RWO PVC; all three replicas would fight over the same volume (only one can mount it). Either use RWX storage or use a StatefulSet with separate PVCs per replica.

Need help with Ubuntu administration?

Work directly with Muhammad Irfan Aslam for Ubuntu Server, Linux, cloud, Docker, DevOps, CI/CD, or infrastructure troubleshooting support.

Work with Muhammad Irfan Aslam