Kubernetes
storageClass
PostgreSQL
database management
cloud storage

Kubernetes storageClass for Postgresql database

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

For PostgreSQL on Kubernetes, a StorageClass is not just a way to get "some disk." It defines how persistent volumes are provisioned, what performance profile they have, how they are bound to nodes, and what happens to the underlying storage when claims are deleted.

What Matters for PostgreSQL

A database cares about storage behavior more than stateless applications do. The key concerns are:

  • low and predictable latency
  • durable writes
  • correct access mode
  • safe reclaim behavior
  • the ability to resize or snapshot volumes

That is why the best StorageClass for PostgreSQL depends on the storage backend and workload, not on PostgreSQL alone.

A Typical StorageClass Example

Here is a reasonable AWS EBS CSI example for a single-instance PostgreSQL workload:

yaml
1apiVersion: storage.k8s.io/v1
2kind: StorageClass
3metadata:
4  name: pg-fast
5provisioner: ebs.csi.aws.com
6reclaimPolicy: Retain
7volumeBindingMode: WaitForFirstConsumer
8allowVolumeExpansion: true
9parameters:
10  type: gp3
11  fsType: xfs

The important parts are:

  • 'Retain so the disk is not automatically destroyed when the claim is removed'
  • 'WaitForFirstConsumer so scheduling and volume placement happen together'
  • 'allowVolumeExpansion so the PVC can grow later'

For PostgreSQL, Retain is usually safer than Delete because accidental data loss is expensive.

Use a StatefulSet, Not a Deployment

For PostgreSQL, you usually want a StatefulSet with a volume claim template rather than a plain Deployment.

yaml
1apiVersion: apps/v1
2kind: StatefulSet
3metadata:
4  name: postgres
5spec:
6  serviceName: postgres
7  replicas: 1
8  selector:
9    matchLabels:
10      app: postgres
11  template:
12    metadata:
13      labels:
14        app: postgres
15    spec:
16      containers:
17        - name: postgres
18          image: postgres:16
19          ports:
20            - containerPort: 5432
21          volumeMounts:
22            - name: data
23              mountPath: /var/lib/postgresql/data
24  volumeClaimTemplates:
25    - metadata:
26        name: data
27      spec:
28        accessModes:
29          - ReadWriteOnce
30        storageClassName: pg-fast
31        resources:
32          requests:
33            storage: 100Gi

That ensures PostgreSQL gets stable storage and predictable volume naming across restarts.

Choose the Access Mode Carefully

For most block-storage-backed PostgreSQL deployments, ReadWriteOnce is the correct access mode. A single PostgreSQL instance writes to one volume from one node. Trying to force a shared writable filesystem is often the wrong design for a primary database pod.

If you are running a replicated PostgreSQL setup, each replica should normally have its own volume rather than multiple pods writing to the same data directory.

Backend Choice Matters

The right parameters differ by provider:

  • AWS EBS and GCE PD are common for single-node block storage
  • Ceph or other CSI drivers may offer snapshots and advanced policies
  • network filesystems are usually less ideal for primary PostgreSQL data files unless the platform is tuned specifically for database workloads

Do not assume a default cluster StorageClass is good enough for a write-heavy database. Check latency, throughput, and failure behavior.

Reclaim Policy Is a Real Safety Decision

For disposable workloads, Delete is convenient. For PostgreSQL, it can be catastrophic if an operator removes a PVC by mistake. Retain means extra manual cleanup, but it also means the data can survive an application-level mistake.

That tradeoff is usually worth it for databases.

Common Pitfalls

  • Using a Deployment for PostgreSQL when a StatefulSet is the better fit.
  • Keeping the default StorageClass without checking its latency and reclaim behavior.
  • Using Delete reclaim policy on important database data without realizing the risk.
  • Trying to share one writable volume across multiple PostgreSQL pods.
  • Forgetting WaitForFirstConsumer, which can lead to poor volume placement in multi-zone clusters.

Summary

  • PostgreSQL needs a deliberately chosen StorageClass, not just any persistent volume.
  • Prefer a StatefulSet with a PVC template and ReadWriteOnce storage.
  • 'Retain, WaitForFirstConsumer, and volume expansion are strong defaults for many database setups.'
  • Choose storage parameters based on actual database workload and backend behavior.
  • Treat reclaim policy and backend latency as data-safety decisions, not minor YAML details.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.