๐Ÿท๏ธ Manage persistent volumes and persistent volume claims

๐Ÿท๏ธ Manage persistent volumes and persistent volume claims#

PersistentVolume and PersistentVolumeClaim

A PersistentVolume (PV) is a cluster-wide resource that represents a piece of pre-provisioned storage, which can be used across different user environments and has a lifecycle independent of any individual pod that uses it. PVs can be created statically by an administrator or dynamically through a StorageClass, and they correspond to physical storage such as a disk or file system, either on-premise or provided by a cloud vendor. They are defined as Kubernetes objects and can be managed as separate resources from the pods that consume them.

A PersistentVolumeClaim (PVC) is a request made by a user or application for storage resources within the cluster. It acts as a โ€œvoucherโ€ or a request for a specific amount of storage, specifying requirements like capacity, access mode (e.g., ReadWriteOnce, ReadOnlyMany, ReadWriteMany), and optionally a storage class. PVCs are namespaced and are used by pods to claim storage from a PV. The Kubernetes control plane binds a PVC to a suitable PV based on the requested capacity and properties, establishing a one-to-one relationship between the two. Once bound, the PVC can be mounted into a pod as a volume, allowing the application to access persistent data even after pod restarts or rescheduling.

This separation of concernsโ€”where PVs are provisioned by administrators and PVCs are consumed by usersโ€”decouples storage provisioning from application deployment, enabling more flexible and efficient resource utilization. If a PVC is deleted, the PV can be reclaimed based on its reclaim policy (Retain, Delete, or Recycle), with Retain being the default, meaning the PV and its data remain intact until manually reclaimed

Create PersistentVolume#

แ… cat <<EOF >> pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-guisam
  labels:
    storage: pv-guisam
spec:
  capacity:
    storage: 5Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /opt/guisam-nfs
    server: 192.168.94.61
    readOnly: false
EOF
แ… kb apply -f pv.yaml
แ… kb get pv
NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pv-guisam   5Gi        RWX            Retain           Available                          <unset>                          7s

Tip

To reserve a volume use claimRef in spec volume manifest. Do not forget to specify the namespace.

  claimRef:
    name: pvc-guisam
    namespace: default

Create PersistentVolumeClaim#

แ… cat <<EOF > pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-guisam
  labels:
    storage: nfs-guisam
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
EOF
แ… kb get pv,pvc
NAME                         CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
persistentvolume/pv-guisam   5Gi        RWX            Retain           Bound    default/pvc-guisam                  <unset>                          2m5s

NAME                               STATUS   VOLUME      CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/pvc-guisam   Bound    pv-guisam   5Gi        RWX                           <unset>                 8s

Create Deployment#

แ… kb create deploy guisamweb \
--dry-run=client --image=nginx:alpine \
--replicas=2 --port=80 \
-o yaml > guisamweb.yaml
แ… diff -u guisamweb.yaml{.before,}
--- guisamweb.yaml.before       2025-10-11 15:52:32.421221200 +0200
+++ guisamweb.yaml      2025-10-12 16:39:54.353769872 +0200
@@ -21,4 +21,11 @@
         ports:
         - containerPort: 80
         resources: {}
+        volumeMounts:
+          - name: nfs-guisam
+            mountPath: /usr/share/nginx/html
+      volumes:
+        - name: nfs-guisam
+          persistentVolumeClaim:
+            claimName: pvc-guisam
 status: {}
แ… kb exec -ti guisamweb-6954d47787-7kzvw -- df -hT /usr/share/nginx/html
Filesystem           Type            Size      Used Available Use% Mounted on
forge:/opt/guisam-nfs
                     nfs4           37.7G      3.7G     34.0G  10% /usr/share/nginx/html
แ… kb delete deploy guisamweb
แ… kb delete pvc pvc-guisam
แ… kb delete pv pv-guisam

ResourceQuota to limit PVC count and usage#

แ… kb create quota nfs-guisam \
--dry-run=client -o yaml \
--hard="persistentvolumeclaims=10,requests.storage=1Gi" \
--namespace nfs-guisam \
> nfs-quota.yaml
แ… kb apply -f pv.yaml
แ… kb apply -f pvc.yaml
แ… kb apply -f guisamweb.yaml
แ… kb get resourcequotas -n nfs-guisam
NAME         REQUEST                                                    LIMIT   AGE
nfs-guisam   persistentvolumeclaims: 1/10, requests.storage: 5Gi/10Gi           58m
แ… sed 's/5/15/;s/pv/pv2/' pv.yaml > pv2.yam
แ… sed 's/5/15/;s/pvc/pvc2/' pvc.yaml > pvc2.yaml
แ… kb apply -f pv2.yaml -n nfs-guisam
แ… kb apply -f pvc2.yaml -n nfs-guisam
Error from server (Forbidden): error when creating "pvc2.yaml": persistentvolumeclaims "pvc2-guisam" is forbidden: exceeded quota: nfs-guisam, requested: requests.storage=15Gi, used: requests.storage=5Gi, limited: requests.storage=10Gi