Kubernetes Course
The Problem: Containers Are Ephemeral

By default, any data written inside a container's filesystem is lost when the container restarts — and a container restarts far more often than you might expect (crashes, image updates, node maintenance). Kubernetes Volumes solve this by attaching storage to a Pod that outlives individual container restarts, and, with the right volume type, outlives the Pod itself.
Volumes (Pod-scoped)
The simplest volume types are tied to the Pod's lifetime — they survive container restarts within the Pod, but are deleted when the Pod itself is deleted.
emptyDir — a blank directory created when the Pod starts, useful for scratch space or sharing files between containers in the same Pod:
spec: containers: - name: app image: myapp:1.0 volumeMounts: - name: cache-volume mountPath: /cache volumes: - name: cache-volume emptyDir: {}
hostPath — mounts a file or directory from the node's own filesystem into the Pod:
volumes: - name: host-logs hostPath: path: /var/log type: Directory
hostPath ties a Pod to whatever happens to be on that specific node, and is generally discouraged for application data — it's mainly used by infrastructure-level Pods (like log collectors or monitoring agents) that need direct node access, and it carries real security risk (covered later) if misused.
PersistentVolumes and PersistentVolumeClaims

For data that must outlive the Pod entirely — a database's data directory, user uploads — Kubernetes separates storage into two objects, so application developers don't need to know the underlying storage details:
- PersistentVolume (PV): A piece of actual storage in the cluster (an AWS EBS volume, an NFS share, a local disk), provisioned either manually by a cluster admin or automatically via a StorageClass. This is a cluster-level resource, not tied to any namespace.
- PersistentVolumeClaim (PVC): A request for storage made by a developer/application — "I need 10Gi of storage, ReadWriteOnce." Kubernetes binds the PVC to a PV that satisfies the request.
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: db-data-claim spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: standard
apiVersion: v1 kind: Pod metadata: name: postgres-pod spec: containers: - name: postgres image: postgres:16 volumeMounts: - name: db-storage mountPath: /var/lib/postgresql/data volumes: - name: db-storage persistentVolumeClaim: claimName: db-data-claim
Access Modes
| Mode | Meaning |
|---|---|
| ReadWriteOnce (RWO) | Mounted as read-write by a single node at a time |
| ReadOnlyMany (ROX) | Mounted as read-only by many nodes simultaneously |
| ReadWriteMany (RWX) | Mounted as read-write by many nodes simultaneously |
| ReadWriteOncePod | Mounted as read-write by a single Pod in the whole cluster (newer, stricter than RWO) |
Most cloud block storage (AWS EBS, Azure Disk, GCP PD) only supports ReadWriteOnce. ReadWriteMany typically requires network file storage like NFS, EFS, or Azure Files.
StorageClasses and Dynamic Provisioning
Manually pre-creating PersistentVolumes doesn't scale. A StorageClass lets PVs be provisioned automatically the moment a PVC requests one:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast-ssd provisioner: ebs.csi.aws.com parameters: type: gp3 reclaimPolicy: Delete volumeBindingMode: WaitForFirstConsumer
provisioneridentifies the plugin (a CSI — Container Storage Interface driver) responsible for actually creating the underlying disk with the cloud provider.reclaimPolicy: Deletemeans the underlying storage is deleted when the PVC is deleted;Retainkeeps the data around for manual recovery — an important choice for production databases.volumeBindingMode: WaitForFirstConsumerdelays provisioning until a Pod using the PVC is actually scheduled, so the storage is created in the same availability zone as the Pod.- Most managed Kubernetes clusters (EKS, GKE, AKS) ship with a sensible default StorageClass already installed.
kubectl get storageclass kubectl get pv kubectl get pvc
Why This Matters for StatefulSets
Databases and other stateful applications rely heavily on PersistentVolumeClaims — each replica of a database needs its own persistent, stable storage that survives Pod rescheduling. We'll see this pattern in detail in the StatefulSets lesson, where each replica automatically gets its own dedicated PVC.