← Back to Kubernetes Mastery
Intermediate13 min read

Storage

Manage persistent data in Kubernetes — PersistentVolumes, PersistentVolumeClaims, StorageClasses, and StatefulSets for stateful applications.

PersistentVolumes and Claims

PersistentVolume (PV) is cluster storage provisioned by an admin or dynamically via StorageClass. PersistentVolumeClaim (PVC) is a user request for storage. Kubernetes binds PVCs to matching PVs.

Pods use PVCs as volumes — storage persists beyond pod lifecycle. When a pod is deleted and recreated, it reattaches the same PVC.

  • ReadWriteOnce: one node read-write (most common)
  • ReadWriteMany: multiple nodes read-write (NFS, EFS)
  • ReadOnlyMany: multiple nodes read-only
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: db-storage
spec:
  accessModes: [ReadWriteOnce]
  storageClassName: gp3
  resources:
    requests:
      storage: 20Gi

# Reference in pod spec
volumes:
  - name: data
    persistentVolumeClaim:
      claimName: db-storage

StorageClasses

StorageClass enables dynamic provisioning — creating PVs automatically when PVCs are created. Cloud providers offer classes mapped to their storage products: gp3 (AWS EBS), pd-ssd (GCE), managed-premium (Azure).

Set a default StorageClass so PVCs without storageClassName get provisioned automatically.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp3
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  iops: "3000"
volumeBindingMode: WaitForFirstConsumer

StatefulSets

StatefulSets manage stateful applications with stable network identities and persistent storage. Each pod gets a predictable name (web-0, web-1) and its own PVC that persists across restarts.

Use StatefulSets for databases, message queues, and any application requiring stable storage and network identity. Deploy in order (0, 1, 2) and scale down in reverse.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres
  replicas: 3
  selector:
    matchLabels:
      app: postgres
  template:
    spec:
      containers:
        - name: postgres
          image: postgres:16
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: [ReadWriteOnce]
        resources:
          requests:
            storage: 50Gi

Volume Types

Beyond PVCs, pods support emptyDir (temporary, dies with pod), configMap and secret volumes (configuration injection), and projected volumes (combining multiple sources).

emptyDir is useful for scratch space and inter-container sharing within a pod. configMap volumes mount configuration files that update when the ConfigMap changes.

volumes:
  - name: cache
    emptyDir:
      sizeLimit: 1Gi
  - name: config
    configMap:
      name: app-config
  - name: secrets
    secret:
      secretName: db-credentials

Backup and Recovery

Back up PVC data with volume snapshots (StorageClass must support it) or by mounting the volume in a backup pod. Cloud providers offer automated snapshot schedules.

Test recovery regularly — a backup you cannot restore is worthless. Document RPO (Recovery Point Objective) and RTO (Recovery Time Objective) for each stateful service.

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: db-backup-20240115
spec:
  volumeSnapshotClassName: csi-aws-vsc
  source:
    persistentVolumeClaimName: db-storage

Get In Touch


Ready to discuss your next project? Drop me a message.