PostgreSQL
Docker
Kubernetes
Data Persistence
Database Management

How to persist data using a postgres database, Docker, and Kubernetes?

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

Persisting PostgreSQL data across container restarts requires explicit storage design in both Docker and Kubernetes. Without mounted volumes, data in /var/lib/postgresql/data disappears when containers are replaced. A production-ready setup uses durable volumes, proper initialization, and clear backup procedures.

Persistence in Docker With Named Volumes

A simple and robust local setup uses a named Docker volume.

bash
1docker volume create pgdata
2
3docker run -d \
4  --name pg \
5  -e POSTGRES_USER=app \
6  -e POSTGRES_PASSWORD=secret \
7  -e POSTGRES_DB=appdb \
8  -v pgdata:/var/lib/postgresql/data \
9  -p 5432:5432 \
10  postgres:16

With this mount, data survives container recreation:

bash
docker rm -f pg
docker run -d --name pg -e POSTGRES_USER=app -e POSTGRES_PASSWORD=secret -e POSTGRES_DB=appdb -v pgdata:/var/lib/postgresql/data -p 5432:5432 postgres:16

The database starts with previous data because the volume remains.

Docker Compose Example

Compose makes repeatable local environments easier.

yaml
1services:
2  db:
3    image: postgres:16
4    environment:
5      POSTGRES_USER: app
6      POSTGRES_PASSWORD: secret
7      POSTGRES_DB: appdb
8    ports:
9      - "5432:5432"
10    volumes:
11      - pgdata:/var/lib/postgresql/data
12
13volumes:
14  pgdata:

Add initialization SQL by mounting docker-entrypoint-initdb.d for first startup only.

Kubernetes Persistence With PVC

In Kubernetes, persistence is usually handled with a PersistentVolumeClaim and either a StatefulSet or a single Deployment for non-critical environments.

yaml
1apiVersion: v1
2kind: PersistentVolumeClaim
3metadata:
4  name: pg-pvc
5spec:
6  accessModes:
7    - ReadWriteOnce
8  resources:
9    requests:
10      storage: 20Gi
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          env:
20            - name: POSTGRES_USER
21              value: app
22            - name: POSTGRES_PASSWORD
23              valueFrom:
24                secretKeyRef:
25                  name: pg-secret
26                  key: password
27            - name: POSTGRES_DB
28              value: appdb
29          volumeMounts:
30            - name: pgdata
31              mountPath: /var/lib/postgresql/data
32  volumeClaimTemplates:
33    - metadata:
34        name: pgdata
35      spec:
36        accessModes: ["ReadWriteOnce"]
37        resources:
38          requests:
39            storage: 20Gi

StatefulSet gives stable identity and is the standard choice for databases in Kubernetes.

Data Safety Beyond Volumes

Persistent volumes protect against pod restarts, not all failures. You still need:

  • logical backups with pg_dump
  • periodic restore tests
  • monitoring for disk and replication lag

Backup example:

bash
pg_dump -h localhost -U app -d appdb -F c -f appdb.backup

For clusters, run backup jobs as scheduled workloads and copy artifacts to object storage.

Migration Path From Docker to Kubernetes

Teams often start in Docker and move to Kubernetes later. Keep configuration portable:

  • same major PostgreSQL version across environments
  • same schema migration pipeline
  • environment variables managed through secrets, not hardcoded values

Use migrations at startup only with strong locking guarantees to avoid parallel migration race conditions.

Health Checks and Startup Ordering

Persistence alone is not enough if application pods start before PostgreSQL is ready. Add readiness probes and dependency retry logic so services do not fail permanently on first boot.

yaml
1readinessProbe:
2  exec:
3    command: ["pg_isready", "-U", "app"]
4  initialDelaySeconds: 10
5  periodSeconds: 5

For application deployments, include connection retry with exponential backoff. This keeps startup stable during node rescheduling and storage attach delays.

Common Pitfalls

  • Running PostgreSQL in Kubernetes without persistent volume claims.
  • Using Deployment with random pod identity for stateful production workloads.
  • Storing credentials in plain manifests instead of secrets.
  • Assuming volume persistence replaces backups.
  • Upgrading major PostgreSQL versions without migration rehearsal.

Summary

  • Data persistence requires mounting PostgreSQL data directory to durable storage.
  • Docker named volumes are sufficient for local and small environments.
  • Kubernetes should use PVC-backed StatefulSet for stable stateful behavior.
  • Persistence and backups solve different risks and both are required.
  • Standardized versioning and migration workflows make Docker to Kubernetes transitions safer.

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.