PVC and Volume Mount Solutions
SummaryStep-by-step solutions for Exercises 1 and 2: creating...
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