Learn Kubernetes in 10 DaysDay 6: Storage and Data Persistence

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 storageClassName uses 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

  1. PV + PVC is the Kubernetes equivalent of Docker Volumes. PV is storage, PVC is the request
  2. StorageClass enables dynamic PV creation β€” no manual PV provisioning needed
  3. 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.