Technical Theory

Managing Persistent Volumes and Claims

Introduction

This tutorial guides you through managing persistent storage in Kubernetes using Persistent Volumes (PVs) and Persistent Volume Claims (PVCs). You will learn how to define, create, and utilize PVs and PVCs to provide persistent storage for your applications. A basic understanding of Kubernetes concepts (Pods, Deployments) is recommended.

Task 1: Understanding Persistent Volumes (PVs)

PVs are cluster-level resources representing a piece of storage in the cluster. They are provisioned by an administrator or dynamically provisioned using StorageClasses.

  1. Define a Persistent Volume: Create a file named pv.yaml with the following content:

    NODE_TYPE // yaml
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: my-pv
    spec:
      capacity:
        storage: 1Gi
      accessModes:
        - ReadWriteOnce
      persistentVolumeReclaimPolicy: Retain
      storageClassName: manual
      hostPath:
        path: "/mnt/data"
    hostPath is suitable for development/testing but is NOT recommended for production. In production, use cloud provider volumes (e.g., awsElasticBlockStore, gcePersistentDisk).
  2. Explanation of the PV definition:

    • apiVersion: API version of the Kubernetes resource.
    • kind: Specifies that this is a PersistentVolume.
    • metadata.name: Name of the PV (e.g., my-pv).
    • spec.capacity.storage: Storage capacity of the volume (e.g., 1Gi).
    • spec.accessModes: How the volume can be accessed:
      • ReadWriteOnce: Can be mounted by a single node for read and write.
      • ReadOnlyMany: Can be mounted by multiple nodes for read-only access.
      • ReadWriteMany: Can be mounted by multiple nodes for read and write.
    • spec.persistentVolumeReclaimPolicy: What happens to the volume when the PVC is deleted:
      • Retain: The volume remains and data is preserved. Requires manual cleanup.
      • Delete: The volume and data are deleted (if supported by the underlying storage).
      • Recycle: (Deprecated) The volume is scrubbed and made available for reuse.
    • spec.storageClassName: Name of the StorageClass to use for dynamic provisioning. Set to manual when provisioning PVs directly.
    • spec.hostPath.path: The path on the host node where the volume is located (for hostPath volumes).
  3. Create the Persistent Volume:

    NODE_TYPE // bash
    kubectl apply -f pv.yaml
    NODE_TYPE // output
    persistentvolume/my-pv created
  4. Verify the Persistent Volume:

    NODE_TYPE // bash
    kubectl get pv my-pv
    NODE_TYPE // output
    NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
    my-pv     1Gi        RWO            Retain           Available           manual                  10s
    The STATUS should be Available if the PV is successfully created and not yet bound to a PVC.

Task 2: Understanding Persistent Volume Claims (PVCs)

PVCs are requests for storage by users. They specify the storage size, access modes, and other requirements.

  1. Define a Persistent Volume Claim: Create a file named pvc.yaml with the following content:

    NODE_TYPE // yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: my-pvc
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 500Mi
      storageClassName: manual
      selector:
        matchLabels:
          name: my-pv
  2. Explanation of the PVC definition:

    • apiVersion: API version of the Kubernetes resource.
    • kind: Specifies that this is a PersistentVolumeClaim.
    • metadata.name: Name of the PVC (e.g., my-pvc).
    • spec.accessModes: The access modes required by the application (must be compatible with the PV).
    • spec.resources.requests.storage: The amount of storage requested (e.g., 500Mi).
    • spec.storageClassName: Must match the storageClassName of the PV to bind to it.
    • spec.selector: Allows you to select specific PVs.
  3. Create the Persistent Volume Claim:

    NODE_TYPE // bash
    kubectl apply -f pvc.yaml
    NODE_TYPE // output
    persistentvolumeclaim/my-pvc created
  4. Verify the Persistent Volume Claim:

    NODE_TYPE // bash
    kubectl get pvc my-pvc
    NODE_TYPE // output
    NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    my-pvc    Bound    my-pv    1Gi        RWO            manual         15s
    The STATUS should be Bound if the PVC has been successfully bound to a PV. The VOLUME column shows the name of the bound PV.

Task 3: Using a Persistent Volume Claim in a Pod

Now, let’s create a Pod that uses the PVC to access the persistent storage.

  1. Define a Pod that uses the PVC: Create a file named pod.yaml with the following content:

    NODE_TYPE // yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
    spec:
      volumes:
        - name: my-volume
          persistentVolumeClaim:
            claimName: my-pvc
      containers:
        - name: my-container
          image: busybox:latest
          command: ["/bin/sh", "-c", "while true; do echo $(date) >> /data/output.txt; sleep 5; done"]
          volumeMounts:
            - mountPath: /data
              name: my-volume
  2. Explanation of the Pod definition:

    • apiVersion: API version of the Kubernetes resource.
    • kind: Specifies that this is a Pod.
    • metadata.name: Name of the Pod (e.g., my-pod).
    • spec.volumes: Defines the volumes to be used by the Pod.
      • name: A name for the volume within the Pod.
      • persistentVolumeClaim.claimName: The name of the PVC to use.
    • spec.containers: Defines the containers within the Pod.
      • name: Name of the container.
      • image: The container image to use.
      • command: The command to run inside the container. In this example, it writes the current date to a file named output.txt every 5 seconds.
      • volumeMounts: Specifies where to mount the volume inside the container.
        • mountPath: The path inside the container where the volume will be mounted (e.g., /data).
        • name: The name of the volume defined in spec.volumes.
  3. Create the Pod:

    NODE_TYPE // bash
    kubectl apply -f pod.yaml
    NODE_TYPE // output
    pod/my-pod created
  4. Verify the Pod:

    NODE_TYPE // bash
    kubectl get pod my-pod
    NODE_TYPE // output
    NAME     READY   STATUS    RESTARTS   AGE
    my-pod   1/1     Running   0          20s
    The STATUS should be Running if the Pod has been successfully created and is running.
  5. Check the Data: Exec into the pod

    NODE_TYPE // bash
    kubectl exec -it my-pod -- /bin/sh
  6. Read the log file

    NODE_TYPE // bash
    cat /data/output.txt
  7. Example Log file output

    NODE_TYPE // output
    Wed Apr  7 15:00:00 UTC 2026
    Wed Apr  7 15:00:05 UTC 2026
    Wed Apr  7 15:00:10 UTC 2026
  8. Clean up (optional):

    NODE_TYPE // bash
    kubectl delete pod my-pod
    kubectl delete pvc my-pvc
    kubectl delete pv my-pv

Conclusion

In this tutorial, you learned how to create and manage persistent storage in Kubernetes using Persistent Volumes and Persistent Volume Claims. You provisioned a PV, created a PVC, and mounted it in a Pod. Remember that hostPath is only suitable for development/testing and should be replaced with appropriate cloud provider storage in production environments.

Next Topic