Skip to main content
mastering ckad certified kubernetes application developer

PVC and Volume Mount Solutions

6 min read Chapter 44 of 87
Summary

Step-by-step solutions for Exercises 1 and 2: creating...

Step-by-step solutions for Exercises 1 and 2: creating a 1Gi ReadWriteOnce PVC with dynamic provisioning and mounting it in a busybox Pod to verify persistence across Pod deletion, and creating a multi-container Pod with two busybox containers sharing an emptyDir volume for inter-container data exchange.

PVC and Volume Mount Solutions

Solution: Exercise 1 — Create a PVC and Mount It in a Pod

This exercise requires creating a PersistentVolumeClaim with dynamic provisioning, mounting it in a Pod, writing data, deleting and recreating the Pod, and confirming the data persists.

Step 1: Create the PVC

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

Save this as exercise-pvc.yaml and apply:

kubectl apply -f exercise-pvc.yaml

Check the PVC status:

kubectl get pvc exercise-pvc

Expected output:

NAME           STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
exercise-pvc   Pending                                      standard       5s

The PVC shows Pending because the standard StorageClass in Kind uses WaitForFirstConsumer volume binding mode. The PV will not be created until a Pod actually mounts this PVC. This is expected behavior, not an error.

Step 2: Create the Pod

apiVersion: v1
kind: Pod
metadata:
  name: storage-pod
spec:
  containers:
    - name: busybox
      image: busybox:1.36
      command: ["sleep", "3600"]
      volumeMounts:
        - name: data-volume
          mountPath: /data
  volumes:
    - name: data-volume
      persistentVolumeClaim:
        claimName: exercise-pvc

Save as storage-pod.yaml and apply:

kubectl apply -f storage-pod.yaml

Wait for the Pod to reach Running status:

kubectl get pod storage-pod -w

Expected output (the Pod may take 10-30 seconds to start as the PV is provisioned):

NAME          READY   STATUS    RESTARTS   AGE
storage-pod   1/1     Running   0          15s

Now check the PVC again:

kubectl get pvc exercise-pvc

Expected output:

NAME           STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
exercise-pvc   Bound    pvc-a1b2c3d4-e5f6-7890-abcd-ef1234567890   1Gi        RWO            standard       30s

The PVC transitions from Pending to Bound once the Pod triggers dynamic provisioning. The VOLUME column shows the auto-generated PV name.

Step 3: Write Data to the Volume

kubectl exec storage-pod -- sh -c "echo 'persistent storage works' > /data/hello.txt"

Verify the file was written:

kubectl exec storage-pod -- cat /data/hello.txt

Output:

persistent storage works

Step 4: Delete and Recreate the Pod

kubectl delete pod storage-pod

Wait for the Pod to be fully deleted, then recreate it:

kubectl apply -f storage-pod.yaml

Wait for the new Pod to be running:

kubectl get pod storage-pod -w

Step 5: Verify Data Persistence

kubectl exec storage-pod -- cat /data/hello.txt

Output:

persistent storage works

The file survives Pod deletion because the PVC (and its underlying PV) was not deleted. The new Pod mounts the same PVC, which points to the same storage directory on the node.

Common Mistakes

PVC stays Pending after Pod creation: Verify the StorageClass name is correct. Run kubectl get sc to list available StorageClasses. A typo in storageClassName causes the PVC to wait for a non-existent provisioner.

Pod stays Pending with event “persistentvolumeclaim not found”: The PVC name in volumes[].persistentVolumeClaim.claimName does not match the PVC name in its metadata. Check for typos.

Pod stays Pending with event “unbound PersistentVolumeClaims”: The PVC exists but is not bound. Check PVC events with kubectl describe pvc exercise-pvc for provisioning errors.

Volume name mismatch: The name field in volumes[] must match the name field in volumeMounts[]. A mismatch causes the Pod to fail validation.

Cleanup

kubectl delete pod storage-pod
kubectl delete pvc exercise-pvc

Solution: Exercise 2 — Two Containers Sharing an emptyDir Volume

This exercise requires creating a Pod with two containers that exchange data through a shared emptyDir volume.

Step 1: Create the Multi-Container Pod

apiVersion: v1
kind: Pod
metadata:
  name: sidecar-pod
spec:
  containers:
    - name: writer
      image: busybox:1.36
      command: ["sh", "-c", "while true; do date >> /shared/timestamps.txt; sleep 5; done"]
      volumeMounts:
        - name: shared-vol
          mountPath: /shared
    - name: reader
      image: busybox:1.36
      command: ["sh", "-c", "tail -f /shared/timestamps.txt"]
      volumeMounts:
        - name: shared-vol
          mountPath: /shared
  volumes:
    - name: shared-vol
      emptyDir: {}

Save as sidecar-pod.yaml and apply:

kubectl apply -f sidecar-pod.yaml

Wait for the Pod to reach Running status:

kubectl get pod sidecar-pod -w

Expected output:

NAME          READY   STATUS    RESTARTS   AGE
sidecar-pod   2/2     Running   0          10s

The 2/2 in the READY column confirms both containers are running. If it shows 1/2, one container failed to start — check events with kubectl describe pod sidecar-pod.

Step 2: Verify the Writer Container

Check that the writer is producing timestamps:

kubectl exec sidecar-pod -c writer -- cat /shared/timestamps.txt

Output (you should see multiple timestamps, growing every 5 seconds):

Mon Jan 12 14:30:00 UTC 2026
Mon Jan 12 14:30:05 UTC 2026
Mon Jan 12 14:30:10 UTC 2026

Step 3: Verify the Reader Container

The reader container runs tail -f, so its output appears in the container’s logs:

kubectl logs sidecar-pod -c reader

Output:

Mon Jan 12 14:30:00 UTC 2026
Mon Jan 12 14:30:05 UTC 2026
Mon Jan 12 14:30:10 UTC 2026

The reader sees the same timestamps the writer produces. Both containers mount /shared backed by the same emptyDir volume — the name: shared-vol in volumes[] connects both volumeMounts[] entries.

Step 4: Confirm emptyDir Behavior

Follow the reader logs in real-time to see new entries appear:

kubectl logs sidecar-pod -c reader -f

Press Ctrl+C to stop following after observing a few new entries.

How It Works

The emptyDir volume is created when the Pod is scheduled to a node. It is an empty directory on the node’s filesystem (by default at a path managed by the kubelet). Both containers in the Pod get their own mount point (/shared) pointing to the same underlying directory. Writes from one container are immediately visible to the other.

This pattern — a primary container and a sidecar that processes its output — is a fundamental Kubernetes design pattern. Production use cases include log forwarding, metrics collection, and data transformation pipelines.

Common Mistakes

Reader container crash (CrashLoopBackOff): The reader container might crash if tail -f /shared/timestamps.txt starts before the writer has created the file. The tail -f command on a nonexistent file will error. To fix, use a startup delay: command: ["sh", "-c", "sleep 2 && tail -f /shared/timestamps.txt"]. In most cases on a real cluster, the writer creates the file fast enough that this is not an issue.

Wrong container name in logs command: kubectl logs sidecar-pod without -c reader will fail because there are multiple containers. Always specify the container name with -c for multi-container Pods.

Volume name mismatch: If the writer mounts name: shared-vol but the reader mounts name: shared-volume, they get different (or no) volumes. The name field must be identical across all mounts that should share data.

Cleanup

kubectl delete pod sidecar-pod