Kubernetes Handbook

    Kubernetes Persistent Volume Claims (PVC)

    Introduction#

    Alright, let’s talk Persistent Volume Claims (PVC) in Kubernetes! If you’ve ever wondered how apps get storage without a hassle, you’re about to become a pro.

    Picture yourself at a library, needing a diary to jot down your thoughts. You don’t want to hunt through shelves—you just tell the librarian, “I need a diary with enough pages!” In Kubernetes, Persistent Volume Claims (PVC) are like that librarian, fetching the right Persistent Volume (PV) for your app. Let’s be real, when I first heard “PVC,” I thought it was about plumbing pipes! 😅 Turns out, it’s way cooler, and I’m here to make it super simple with examples that’ll stick like a Post-it note.

    In this blog, we’ll cover what PVCs are, how they work, their lifecycle, and how to use them with Pods and Deployments. By the end, you’ll be giving your apps storage like a Kubernetes ninja. Let’s dive in!

    What Are Persistent Volume Claims?#

    Persistent Volumes (PV) are like diaries stored in your Kubernetes cluster, ready to hold your app’s data. But your app (or Pod) can’t just grab a PV—it’s like trying to borrow a diary without asking. Persistent Volume Claims (PVC) are requests your app makes, saying, “I need a diary with this much space!” The cluster finds a matching PV, and your app gets to write in it.

    Here’s the thing: PVCs make storage easy by hiding the complicated stuff. You might think you need to be a PV expert to use PVCs, but nope—PVCs do the hard work for you. They’re like ordering a pizza without picking the toppings!

    Kubernetes PV and PVC

    Why PVCs Rock#

    • Dead Simple: Request storage without knowing where it comes from, like asking for a coffee and getting it handed to you.
    • Perfect Matches: PVCs find PVs that fit your needs (size, access type), so your app gets the right diary.
    • Safe and Sound: If a Pod crashes, the PVC keeps the PV ready for a new Pod, like passing a diary to a friend.

    When to Use PVCs#

    Use Persistent Volume Claims whenever your app needs permanent storage, like saving user profiles or game scores, customer orders, whole app data. They’re the easiest way to connect apps to PVs.

    How Do PVCs Work?#

    1. Request Storage: You create a PVC, saying how much space and what kind of access you need (e.g., one Pod writing at a time).
    2. Cluster Matches It: Kubernetes finds a PV that fits your PVC, like a librarian picking a diary with enough pages.
    3. App Uses It: Your Pod or Deployment links to the PVC and writes in the PV, keeping data safe even if it crashes.

    When I first tried PVCs, I requested a huge PV by mistake and got nothing—oops! 😬 The cluster only matches what’s available, so let’s see how to do it right with some examples.

    Example 1: Saving a Journal Entry with a PVC and Pod#

    Let’s make a Pod save a journal entry, like “Saw a sunset,” using a Persistent Volume Claim. We’ll use a hostPath PV for testing (use nfs or csi for real apps).

    Step 1: Create a Persistent Volume#

    First, we need a PV as our diary:

    apiVersion: v1 kind: PersistentVolume metadata: name: journal-pv spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain hostPath: path: /mnt/journal

    Step-by-Step Breakdown of the YAML:

    1. Make a diary: capacity: storage: 1GiThis PV gives your app a diary with 1GiB to write in.
    2. Set access: accessModes: - ReadWriteOnceOnly one Pod on one computer can write in the diary at a time.
    3. Keep it safe: persistentVolumeReclaimPolicy: RetainThe diary’s notes stay even if the Pod is gone, like locking it in a drawer.
    4. Point to files: hostPath: path: /mnt/journalThis uses a folder on the computer for testing (not for real apps).

    Apply it:

    kubectl apply -f journal-pv.yaml

    Output:

    persistentvolume/journal-pv created

    Check the PV:

    kubectl get pv

    Output:

    NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE journal-pv 1Gi RWO Retain Available 10s

    Step 2: Create a Persistent Volume Claim#

    Now, let’s create a PVC to request this PV.

    apiVersion: v1 kind: PersistentVolumeClaim metadata: name: journal-claim namespace: simple-namespace spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi

    Step-by-Step Breakdown of the YAML:

    1. Ask for a diary: resources: requests: storage: 1GiThis asks for a diary with 1GiB of space.
    2. Set access: accessModes: - ReadWriteOnceOnly one Pod on one computer can use the diary at a time.
    3. Name the request: metadata: name: journal-claimThis names your request, like a library slip.

    Apply it:

    kubectl apply -f journal-claim.yaml

    Output:

    persistentvolumeclaim/journal-claim created

    Check the PVC:

    kubectl get pvc -n simple-namespace

    Output:

    NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE journal-claim Bound journal-pv 1Gi RWO 10s

    The PVC is Bound, so the cluster found our diary!

    Step 3: Use the PVC in a Pod#

    Let’s make a Pod use this PVC to save “Saw a sunset.”

    apiVersion: v1 kind: Pod metadata: name: journal-pod namespace: simple-namespace spec: containers: - name: note-writer image: busybox command: ["/bin/sh", "-c", "echo 'Saw a sunset' > /notes/journal.txt; sleep 3600"] volumeMounts: - name: note-storage mountPath: /notes volumes: - name: note-storage persistentVolumeClaim: claimName: journal-claim

    Step-by-Step Breakdown of the YAML:

    1. Link the diary: volumeMounts: - name: note-storage, mountPath: /notesThis connects the diary to the Pod’s /notes folder for writing.
    2. Use the diary: volumes: - name: note-storage, persistentVolumeClaim: claimName: journal-claimThis links the Pod to the diary (PV) via the PVC.
    3. Write the entry: command: ["/bin/sh", "-c", "echo 'Saw a sunset' > /notes/journal.txt; sleep 3600"]This saves “Saw a sunset” in the diary.

    Apply it:

    kubectl apply -f journal-pod.yaml

    Output:

    pod/journal-pod created

    Check the note:

    kubectl exec -it journal-pod -n simple-namespace -- cat /notes/journal.txt

    Output:

    Saw a sunset

    If the Pod crashes, “Saw a sunset” stays safe in /mnt/journal. You’ll probably trip up here the first time—no biggie, just try again!

    Example 2: Saving a To-Do List with a PVC and Deployment#

    Since most folks use Deployments for apps, let’s save a to-do list, like “Call mom,” using a Persistent Volume Claim with a Deployment. Deployments manage multiple Pods, making them perfect for real apps.

    Step 1: Create a Persistent Volume#

    Here’s a PV for our to-do list:

    apiVersion: v1 kind: PersistentVolume metadata: name: todo-pv spec: capacity: storage: 2Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain hostPath: path: /mnt/todo

    Step-by-Step Breakdown of the YAML:

    1. Make a diary: capacity: storage: 2GiThis PV gives your app a diary with 2GiB to write in.
    2. Set access: accessModes: - ReadWriteOnceOnly one Pod on one computer can write in the diary.
    3. Keep it safe: persistentVolumeReclaimPolicy: RetainThe diary’s notes stay safe, like locking it away.
    4. Point to files: hostPath: path: /mnt/todoThis uses a folder on the computer for testing (not for real apps).

    Apply it:

    kubectl apply -f todo-pv.yaml

    Output:

    persistentvolume/todo-pv created

    Check the PV:

    kubectl get pv

    Output:

    NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE todo-pv 2Gi RWO Retain Available 10s

    Step 2: Create a Persistent Volume Claim#

    Let’s create a PVC to request this 2GiB PV.

    apiVersion: v1 kind: PersistentVolumeClaim metadata: name: todo-claim namespace: simple-namespace spec: accessModes: - ReadWriteOnce resources: requests: storage: 2Gi

    Step-by-Step Breakdown of the YAML:

    1. Ask for a diary: resources: requests: storage: 2GiThis asks for a diary with 2GiB of space.
    2. Set access: accessModes: - ReadWriteOnceOnly one Pod on one computer can use the diary.
    3. Name the request: metadata: name: todo-claimThis names your request, like a library slip.

    Apply it:

    kubectl apply -f todo-claim.yaml

    Output:

    persistentvolumeclaim/todo-claim created

    Check the PVC:

    kubectl get pvc -n simple-namespace

    Output:

    NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE todo-claim Bound todo-pv 2Gi RWO 10s

    Step 3: Use the PVC in a Deployment#

    Now, let’s create a Deployment to use this PVC and save “Call mom.”

    apiVersion: apps/v1 kind: Deployment metadata: name: todo-deployment namespace: simple-namespace spec: replicas: 1 selector: matchLabels: app: todo template: metadata: labels: app: todo spec: containers: - name: note-writer image: busybox command: ["/bin/sh", "-c", "echo 'Call mom' > /notes/todo.txt; sleep 3600"] volumeMounts: - name: note-storage mountPath: /notes volumes: - name: note-storage persistentVolumeClaim: claimName: todo-claim

    Step-by-Step Breakdown of the YAML:

    1. Set up the app: replicas: 1, selector: matchLabels: app: todoThis runs one Pod, labeled “todo,” managed by the Deployment.
    2. Link the diary: volumeMounts: - name: note-storage, mountPath: /notesThis connects the diary to the Pod’s /notes folder.
    3. Use the diary: volumes: - name: note-storage, persistentVolumeClaim: claimName: todo-claimThis links the Pod to the diary via the PVC.
    4. Write the entry: command: ["/bin/sh", "-c", "echo 'Call mom' > /notes/todo.txt; sleep 3600"]This saves “Call mom” in the diary.

    Apply it:

    kubectl apply -f todo-deployment.yaml

    Output:

    deployment.apps/todo-deployment created

    Check the Pod (get the Pod name first):

    kubectl get pods -n simple-namespace

    Output:

    NAME READY STATUS RESTARTS AGE todo-deployment-abc123-xyz789 1/1 Running 0 10s

    Check the note:

    kubectl exec -it todo-deployment-abc123-xyz789 -n simple-namespace -- cat /notes/todo.txt

    Output:

    Call mom

    The Deployment ensures the Pod keeps running, and if it crashes, a new Pod uses the same PVC to access “Call mom” in /mnt/todo.

    Lifecycle of Persistent Volumes and PVCs#

    PVs and PVCs have a lifecycle, like a diary’s journey from the library shelf to your hands. Understanding this helps you use Persistent Volume Claims like a pro.

    Stages of the Lifecycle#

    1. Provisioning: A PV is created, either by you (like making a diary) or automatically. It’s like a diary waiting on the library shelf.
    2. Binding: A PVC requests storage, and Kubernetes matches it to a PV, like a librarian handing you a diary. The PVC becomes Bound, and the PV is reserved.
    3. Using: A Pod or Deployment uses the PVC to write in the PV, like jotting notes in the diary. If the Pod crashes, the PVC keeps the PV ready for a new Pod.
    4. Reclaiming: When the PVC is deleted, the PV’s fate depends on its persistentVolumeReclaimPolicy:
      • Retain: The diary stays with its notes, ready for a new PVC (manual cleanup needed).
      • Delete: The diary is erased, and the PV is gone.
      • Recycle: The diary’s notes are cleared, and the PV is reused (rarely used).

    Why This Matters#

    The lifecycle ensures your app’s data stays safe and available. For example, with Retain, “Saw a sunset” stays in /mnt/journal even if the PVC is deleted, but you’ll need to clean it up later. I once forgot to check the reclaim policy and ended up with a pile of unused PVs—don’t be like me! 😬

    Persistent Volume Configurations for Cloud Providers#

    In our examples, we used hostPath for Persistent Volumes, like a diary stored on a single computer. But hostPath is a no-go for real apps because:

    • ❌ If the Pod moves to another computer, the data’s gone.
    • ❌ No backups or high availability.
    • ❌ Useless for clusters with multiple computers.

    For production, use cloud-based Persistent Volumes like Google Cloud Persistent Disk (GCP PD) or AWS Elastic Block Store (EBS). They keep your diary safe, even if Pods move or crash.

    Example 1: Persistent Volume on Google Cloud (GKE)#

    Here’s a PV for Google Kubernetes Engine (GKE):

    apiVersion: v1 kind: PersistentVolume metadata: name: gcp-pd-pv spec: capacity: storage: 50Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Delete gcePersistentDisk: pdName: my-gcp-disk fsType: ext4

    Step-by-Step Breakdown of the YAML:

    1. Make a big diary: capacity: storage: 50GiThis PV gives your app a diary with 50GiB to write in.
    2. Set access: accessModes: - ReadWriteOnceOnly one Pod on one computer can write in the diary.
    3. Clean it up: persistentVolumeReclaimPolicy: DeleteThe diary is erased when the PVC is deleted, like shredding it.
    4. Point to cloud: gcePersistentDisk: pdName: my-gcp-diskThis uses a pre-created disk in Google Cloud, keeping data safe.

    Notes:

    • pdName must match a disk you’ve already created in GCP.
    • Data stays safe if the Pod moves to another computer.
    • ReadWriteOnce means only one Pod can write at a time.

    Example 2: Persistent Volume on AWS (EKS)#

    For Amazon Elastic Kubernetes Service (EKS), we use the CSI driver for AWS EBS:

    apiVersion: v1 kind: PersistentVolume metadata: name: csi-pv spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Delete csi: driver: ebs.csi.aws.com volumeHandle: vol-0123456789abcdef fsType: ext4

    Step-by-Step Breakdown of the YAML:

    1. Make a diary: capacity: storage: 5GiThis PV gives your app a diary with 5GiB to write in.
    2. Set access: accessModes: - ReadWriteOnceOnly one Pod on one computer can write in the diary.
    3. Clean it up: persistentVolumeReclaimPolicy: DeleteThe diary is erased when the PVC is deleted.
    4. Point to cloud: csi: driver: ebs.csi.aws.com, volumeHandle: vol-0123456789abcdefThis uses a pre-created EBS volume in AWS, keeping data safe.

    Notes:

    • driver must be ebs.csi.aws.com for EBS.
    • volumeHandle is the EBS Volume ID, created beforehand.
    • ReadWriteOnce limits access to one Pod at a time.

    Common PVC Questions (FAQ)#

    Here are some questions I had as a beginner, answered simply:

    • What if my Pod crashes? The PVC keeps the PV’s diary safe, so a new Pod can use it. It’s like handing the diary to someone else.
    • What happens when a PVC is deleted? The PV follows its persistentVolumeReclaimPolicyRetain keeps the diary, Delete erases it.
    • Can multiple Pods use one PVC? With ReadWriteOnce, only one Pod can write, but ReadWriteMany allows sharing if the PV supports it.

    Best Practices for Persistent Volume Claims#

    While working with Persistent Volume Claims, try these tips:

    • Size It Right: Request only the storage you need in the PVC, like picking a diary with enough pages.
    • Use Namespaces: Organize PVCs in namespaces.
    • Check Binding: Run kubectl get pvc to confirm your PVC is Bound.
    • Test with hostPath: Use hostPath for learning, but switch to nfs or csi for production.
    • Clean Up: Delete unused PVCs to free PVs, like returning a diary.

    Conclusion#

    In this blog, you learned how Persistent Volume Claims (PVC) make Kubernetes storage a snap, letting your apps grab diaries (PVs) effortlessly. We explored PVC basics, their lifecycle, cloud provider setups, and tried examples with a Pod and a Deployment, saving journal entries and to-do lists. Now, you’re ready to manage Kubernetes storage like a champ, keeping your apps’ data safe with container orchestration.

    Next in our Kubernetes Handbook, we’ll tackle Dynamic Provisioning, where the cluster creates PVs for your PVCs automatically, like a librarian crafting a diary on the spot. It’s storage magic! Until then, try these examples in a test cluster and watch your apps save data like pros. You’ve got this! 😎

    Last updated on May 06, 2025