Day 6: Storage and Data Persistence
What You'll Learn Today
- How Kubernetes storage differs from Docker volumes
- PersistentVolume (PV) and PersistentVolumeClaim (PVC)
- Dynamic provisioning with StorageClass
- Practical database data persistence
From Docker Volumes to Kubernetes Storage
In Docker Day 6, you learned about Volumes, Bind Mounts, and tmpfs. Kubernetes also needs data persistence, but a multi-node cluster requires additional mechanisms.
| Docker | Kubernetes | Description |
|---|---|---|
| Volume | PersistentVolume | Storage resource |
docker volume create |
PV / StorageClass | Storage provisioning |
-v myvolume:/data |
PersistentVolumeClaim | Storage request |
| tmpfs | emptyDir (medium: Memory) | Temporary in-memory storage |
Volume Types
emptyDir
A temporary volume that exists as long as the Pod. Used for sharing data between containers in a Pod.
apiVersion: v1
kind: Pod
metadata:
name: shared-volume-pod
spec:
containers:
- name: writer
image: busybox:1.37
command: ["sh", "-c", "echo 'Hello' > /data/message.txt && sleep 3600"]
volumeMounts:
- name: shared-data
mountPath: /data
- name: reader
image: busybox:1.37
command: ["sh", "-c", "cat /data/message.txt && sleep 3600"]
volumeMounts:
- name: shared-data
mountPath: /data
volumes:
- name: shared-data
emptyDir: {}
Note: emptyDir data is lost when the Pod is deleted.
hostPath
Mounts the node's filesystem into the Pod. Equivalent to Docker's Bind Mount.
volumes:
- name: host-data
hostPath:
path: /var/data
type: DirectoryOrCreate
Note: hostPath is node-specific. If a Pod moves to another node, the data is inaccessible. Avoid in production.
PersistentVolume and PersistentVolumeClaim
Kubernetes manages storage through two resources: PersistentVolume (PV) and PersistentVolumeClaim (PVC).
flowchart LR
ADMIN["Administrator"] -->|"creates"| PV["PersistentVolume\n(storage resource)"]
DEV["Developer"] -->|"creates"| PVC["PersistentVolumeClaim\n(storage request)"]
PVC -->|"binds"| PV
POD["Pod"] -->|"mounts"| PVC
style PV fill:#8b5cf6,color:#fff
style PVC fill:#3b82f6,color:#fff
style POD fill:#22c55e,color:#fff
PersistentVolume (PV)
A cluster storage resource, pre-provisioned by administrators or dynamically created via StorageClass.
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /mnt/data
PersistentVolumeClaim (PVC)
A developer's request for storage. Automatically binds to a matching PV.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
Using PVC in a Pod
apiVersion: v1
kind: Pod
metadata:
name: app-with-storage
spec:
containers:
- name: app
image: nginx:1.27
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
persistentVolumeClaim:
claimName: my-pvc
Access Modes
| Mode | Abbreviation | Description |
|---|---|---|
| ReadWriteOnce | RWO | Read-write by a single node |
| ReadOnlyMany | ROX | Read-only by multiple nodes |
| ReadWriteMany | RWX | Read-write by multiple nodes |
| ReadWriteOncePod | RWOP | Read-write by a single Pod |
Reclaim Policies
| Policy | Description |
|---|---|
| Retain | Keep PV and data. Manual reuse required |
| Delete | Automatically delete PV and storage |
| Recycle | Clear data and reuse PV (deprecated) |
StorageClass (Dynamic Provisioning)
Instead of pre-creating PVs, StorageClass automatically provisions PVs when PVCs are created.
flowchart LR
PVC["PVC\n(5Gi request)"] -->|"references"| SC["StorageClass\n(standard)"]
SC -->|"auto-creates"| PV["PersistentVolume\n(5Gi)"]
PVC -->|"binds"| PV
style SC fill:#f59e0b,color:#fff
style PV fill:#8b5cf6,color:#fff
style PVC fill:#3b82f6,color:#fff
# Check available StorageClasses
kubectl get storageclasses
PVC with StorageClass
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dynamic-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard
resources:
requests:
storage: 5Gi
Omitting
storageClassNameuses the default StorageClass.
Practical Example: PostgreSQL Data Persistence
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:17
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: myapp
- name: POSTGRES_USER
value: admin
- name: POSTGRES_PASSWORD
value: secret123
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pvc
---
apiVersion: v1
kind: Service
metadata:
name: postgres-service
spec:
type: ClusterIP
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
# Deploy
kubectl apply -f postgres-storage.yaml
# Verify PVC
kubectl get pvc
# Delete Pod β Deployment recreates it, data persists
kubectl delete pod -l app=postgres
PV Lifecycle
flowchart LR
A["Available"] --> B["Bound"]
B --> C["Released"]
C -->|"Retain"| D["Manual\nReuse"]
C -->|"Delete"| E["Auto\nDeleted"]
style A fill:#22c55e,color:#fff
style B fill:#3b82f6,color:#fff
style C fill:#f59e0b,color:#fff
style E fill:#ef4444,color:#fff
Summary
| Concept | Description |
|---|---|
| emptyDir | Temporary shared volume within a Pod |
| hostPath | Mounts node filesystem (development only) |
| PersistentVolume (PV) | Cluster storage resource |
| PersistentVolumeClaim (PVC) | Storage request |
| StorageClass | Defines dynamic PV provisioning |
| Access Modes | RWO, ROX, RWX, RWOP |
Key Takeaways
- PV + PVC is the Kubernetes equivalent of Docker Volumes. PV is storage, PVC is the request
- StorageClass enables dynamic PV creation β no manual PV provisioning needed
- Use PVCs for database persistence so data survives Pod recreation
Practice Exercises
Exercise 1: Basics
Create a 5Gi PVC, mount it to an Nginx Pod, and persist HTML files.
Exercise 2: Database
Create a MySQL Deployment with PVC. Insert data, delete the Pod, and verify data persists after recreation.
Challenge
Compare emptyDir and PVC. Write data to both, delete the Pod, and observe which data survives.
References
Next up: In Day 7, you'll learn about "ConfigMaps and Secrets" β how Kubernetes manages configuration that you previously handled with environment variables and .env files in Docker.