Kubernetes containers are ephemeral by design; any data written to the container's filesystem disappears when the container terminates. While Docker introduced volumes for basic persistence, Kubernetes provides a more sophisticated storage architecture with diverse plugins and explicit lifecycle management tied to Pods rather than individual containers.
A key innovation is the separation between PersistentVolume (PV) and PersistentVolumeClaim (PVC). This abstraction mirrors the Pod-Node relationship: administrators provision PVs representing actual storage assets, while developers create PVCs to request storage resources without concerning themselves with backend implementation details.
PV and PVC Fundamentals
Lifecycle Stages
- Provisioning: Cluster administrators create PVs with predefined capacity and access characteristics.
- Binding: When a PVC is created, the control plane matches it to an appropriate PV. The PVC remains unbound until a suitable PV becomes available.
- Utilization: Pods reference PVCs in their specifications, mounting them as standard volumes.
- Release: Deleting a PVC triggers the release phase, marking the PV as "Released" while retaining existing data.
- Reclamation: PVs support three reclamation policies:
- Retain: Manual intervention required to manage leftover data
- Delete: Automatically removes PV and associated storage asset (supported by cloud providers)
- Recycle: Performs basic scrubbing to make storage reusable (deprecated in modern Kubernetes)
Key Attributes
PersistentVolume:
- Capacity: Currently storage size only; future versions may include IOPS and throughput
- Acces Modes:
- ReadWriteOnce (RWO) - single node read/write
- ReadOnlyMany (ROX) - multiple nodes read-only
- ReadWriteMany (RWX) - multiple nodes read/write
- Phase States: Available, Bound, Released, Failed
PersistentVolumeClaim:
- Access Modes: Must match supported PV modes
- Resource Rqeuests: Desired storage quantity
Practical Volume Implementations
emptyDir: Pod-Scoped Temporary Storage
An emptyDir volume exists only for the Pod's lifetime. It's created when a Pod is scheduled to a node and persists through container restarts, but disappears permanently when the Pod is deleted or rescheduled.
Use Case: Sharing transient data between containers in the same Pod.
</div>Deploy and verify:
kubectl apply -f shared-cache-pod.yaml kubectl get pod shared-cache-pod -o wide
Access the service
curl /content.txt
### hostPath: Node-Anchored Storage
`hostPath` mounts a file or directory from the host node's filesystem into the Pod. This creates a dependency on specific node filesystems, making it unsuitable for multi-node clusters but useful for single-node development or daemonset scenarios.
<div class="code-block">```
apiVersion: v1
kind: Pod
metadata:
name: node-data-pod
namespace: default
spec:
containers:
- name: file-viewer
image: nginx:alpine
volumeMounts:
- name: node-storage
mountPath: /usr/share/nginx/html
volumes:
- name: node-storage
hostPath:
path: /var/local/pod-data
type: DirectoryOrCreate
kubectl apply -f node-data-pod.yaml
# On the host node:
sudo mkdir -p /var/local/pod-data
echo "Node-specific content" | sudo tee /var/local/pod-data/index.html
# Access from any client:
kubectl get pod node-data-pod -o wide
curl <pod-ip>
NFS: Network-Attached Persistent Storage
NFS volumes provide true persistence independent of Pod lifecycle. Data survives Pod deletion and remains accessible across cluster nodes, enabling stateful applications.
Server Setup (Ubuntu/Debian):
sudo apt-get update
sudo apt-get install -y nfs-kernel-server
sudo mkdir -p /exports/webdata
sudo chown nobody:nogroup /exports/webdata
# Configure exports
echo "/exports/webdata 10.0.0.0/24(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
sudo exportfs -ra
sudo systemctl restart nfs-kernel-server
Client Pod Configuration:
</div>Deploy and validate persistence:
kubectl apply -f nfs-web-pod.yaml
Write content on NFS server:
echo "Persistent Data" | sudo tee /exports/webdata/index.html
Access the Pod:
kubectl get pod nfs-web-pod -o wide curl
Delete and recreate to verify persistence:
kubectl delete -f nfs-web-pod.yaml kubectl apply -f nfs-web-pod.yaml
Data remains accessible regardless of node placement
curl