⌂ Home

PV-PVC-Pod Binding Lifecycle

Repository YAML Files:
  • k8s/labs/storage/hostpath-pv-pvc.yaml — Static PersistentVolume, PersistentVolumeClaim, and Pod wiring for hostPath-backed storage.
  • k8s/labs/storage/nfs-pv-pvc.yaml — PV/PVC manifests using NFS for shared persistent storage.

PV Lifecycle States

1. Available

PV created and ready for binding. Not yet claimed by any PVC.

2. Bound

PV successfully bound to a PVC. Storage in use by Pod.

3. Released

PVC deleted, but PV retains data. Awaiting reclaim action.

4. Reclaim

Reclaim policy executed: Retain, Delete, or Recycle (Deprecated).

Reclaim Policies

Retain

Data preserved after PVC deletion. Manual cleanup required to reuse PV. Best for production data.

Delete

Automatically deletes PV and underlying storage resource. Default for dynamic provisioning.

Recycle (Deprecated)

Clears data (rm -rf) and makes PV available. Use Delete with dynamic provisioning instead.

Binding Process

1
PVC Created: User creates PVC specifying storage size, access mode, and StorageClass
2
PV Matching: Kubernetes searches for PV matching: size ≥ requested, access mode compatible, StorageClass matches
3
Binding: PVC bound to PV with 1:1 relationship. PV status: Available → Bound
4
Pod Uses Volume: Pod references PVC in volumes section. Volume mounted to container at specified mountPath
5
Release & Reclaim: When PVC deleted, PV enters Released state. Reclaim policy determines next action
Key Concept: PV-PVC binding is 1:1. One PV can only bind to one PVC at a time. Multiple Pods can use the same PVC if access mode allows (ReadWriteMany).

Static vs Dynamic Provisioning

Static Provisioning

  • Admin manually creates PV before PVC
  • PV pre-configured with storage backend details
  • PVC claims existing PV based on requirements
  • StorageClass optional or set to "manual"
  • Best for: On-premises, NFS, specific storage allocation

Dynamic Provisioning

  • PV automatically created when PVC submitted
  • Requires StorageClass with provisioner
  • No manual PV creation needed
  • Scales with demand automatically
  • Best for: Cloud providers (AWS, GCP, Azure)

Access Modes

ReadWriteOnce (RWO)

Volume mounted read-write by single node. Multiple Pods on same node can use. Use: Databases, single-node apps.

ReadOnlyMany (ROX)

Volume mounted read-only by multiple nodes. Use: Configuration files, static data sharing.

ReadWriteMany (RWX)

Volume mounted read-write by multiple nodes. Requires: NFS, CephFS, cloud file storage. Use: Shared logs, distributed apps.

Volume Binding Modes: Immediate - PV provisioned immediately when PVC created. WaitForFirstConsumer - PV provisioned only when Pod using PVC is scheduled (ensures correct zone/node).

Static Provisioning Example (HostPath)

1. Create PersistentVolume

apiVersion: v1
kind: PersistentVolume
metadata:
  name: hostpath-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  hostPath:
    path: /mnt/data
    type: Directory

2. Create PersistentVolumeClaim

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: hostpath-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: manual

3. Create Pod Using PVC

apiVersion: v1
kind: Pod
metadata:
  name: hostpath-pod
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: hostpath-volume
      mountPath: /usr/share/nginx/html
  volumes:
  - name: hostpath-volume
    persistentVolumeClaim:
      claimName: hostpath-pvc

Dynamic Provisioning Example

1. StorageClass (Pre-existing)

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  fsType: ext4
volumeBindingMode: WaitForFirstConsumer

2. Create PVC (PV Auto-Created)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: dynamic-pvc
spec:
  storageClassName: standard
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

3. Pod Uses Auto-Created PV

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: busybox
    command: ['sh', '-c', 'sleep 3600']
    volumeMounts:
    - name: storage
      mountPath: /data
  volumes:
  - name: storage
    persistentVolumeClaim:
      claimName: dynamic-pvc
Verification: Check PVC binding: kubectl get pvc (Status: Bound). Check PV: kubectl get pv. Verify Pod volume mount: kubectl exec -it <pod> -- ls /data