PostgreSQLXVIII · Platforms, Corruption and Production ArchitecturePlatforms
PostgreSQL on Kubernetes: operators, StatefulSets, storage, fencing
What you'll learn
- Map Kubernetes primitives onto the HA responsibilities from Part XV
- Identify where Kubernetes conflicts with database requirements
- Evaluate an operator against the six responsibilities
- Decide whether Kubernetes is the right place for this database
Prerequisites
Verified against PostgreSQL 18.x · PostgreSQL (comparison targets) 17.11, 16.15 · PostgreSQL (support calendar) 18, 17, 16, 15, 14 supported · pgBackRest 2.59.1 · PgBouncer 1.25.2 · Patroni 4.1.5 · Ubuntu (host baseline) 26.04 LTS · 2026-08-27
What Kubernetes supplies
StatefulSets give stable network identity and stable per-pod
storage, which is the minimum a database needs and is why
Deployment is wrong for one.
PersistentVolumeClaims bind storage to a pod identity rather than to a node.
Services give a stable name in front of changing pods, which is lesson XV-06’s routing problem with an implementation.
Scheduling places pods on nodes and moves them when nodes fail.
Where it conflicts
Kubernetes was built for stateless workloads, and its instincts are wrong for a database in specific ways.
It restarts things. A pod that exits is restarted. Lesson XVII-02
measured a cluster whose pg_wal filled: it PANICs, recovery fails for
the same reason, and it shuts down. Kubernetes restarts it into the same
condition, in a loop, and the log line that explains it scrolls past
between attempts.
It reschedules things. Moving a database pod to another node means detaching and attaching storage, which takes time and can fail — and if it partially succeeds you have the fencing problem from lesson XV-03.
It treats pods as fungible. They are not. One of them is the primary, and which one matters more than anything else about the system.
Liveness probes assume a shallow question. pg_isready returns
success for a cluster in recovery, a cluster refusing writes, and a
cluster serving from the corrupted page in lesson XVIII-06. A failing
liveness probe restarts the pod, which for a database is rarely the
right response and is sometimes the worst one.
What an operator must do
Exactly lesson XV-04’s six responsibilities, plus the Kubernetes-specific ones:
| Responsibility | On Kubernetes |
|---|---|
| Detect | Deep health checks, not pg_isready |
| Decide | Consensus — often the Kubernetes API itself |
| Fence | Ensure a demoted pod cannot come back as primary |
| Promote | pg_promote() |
| Reroute | Update the Service’s endpoints |
| Rejoin | pg_rewind or rebuild |
| Storage | Correct PVC handling across rescheduling |
| Backups | Part XIII, which Kubernetes supplies nothing for |
Evaluating an operator means asking the lesson XV-04 questions, plus:
- What happens when the Kubernetes API is unavailable? If it is the consensus store, the operator cannot decide — and the right behaviour is to keep serving and stop deciding.
- What happens when a node is partitioned rather than dead? The pod may still be running and serving.
- How is the primary’s identity expressed, and does the Service follow a promotion atomically?
- What does it do about the kubelet’s restart policy during a deliberate demotion?
Storage
The database’s durability rests entirely on the storage layer, and this
is where lesson VI-01’s measurement matters most: an 854 µs fdatasync
predicted a ~1,170 tps commit ceiling, and pgbench measured 842.
Questions worth answering before running a production database on a storage class:
- Does it honour
fsync? If not, nothing above it is durable, and lesson VI-01’s whole chain is broken. - What is its fsync latency? That is your commit ceiling.
- Is it node-local or network-attached? Local is faster and does not move with the pod.
- What happens during a node failure? Detach and reattach takes time, and that time is part of your RTO.
- Can it be resized? Lesson XVII-02’s remedy for a full filesystem is “extend it”.
What to take from this
- StatefulSets, PVCs and Services supply identity, storage binding and routing. That is the useful part.
- Kubernetes restarts, reschedules and treats pods as fungible — all wrong for a database.
pg_isreadyis not a health check. A failing liveness probe restarts the pod, which is rarely right.- The kubelet is a service manager, and a restart during a deliberate demotion produces two primaries.
- An operator must supply all six Part XV responsibilities plus storage handling; backups are still yours.
- Storage decides durability and your commit ceiling. Ask whether it
honours
fsync. - Kubernetes adds a distributed system between you and the database. Worth it for many clusters, poor for one important one.
Cross-course references
- Kubernetes for Production Sysadmins — Part XVII (StatefulSets), Part L (PersistentVolumes and claims) and Part LIV (Stateful workloads) cover the primitives an operator builds on; Part LIII (Storage failure modes) covers what happens when the volume does not detach; and Part XXXIV (PodDisruptionBudgets) covers keeping a drain from taking the primary.
- Ceph & Distributed Storage — Part LXXXV (Kubernetes integration) and Part LXXXVIII (Kubernetes storage failure scenarios) cover the storage layer underneath.
Quiz
Knowledge check · 6 questions
Q1. An operator deliberately demotes a PostgreSQL pod as part of fencing. The container exits. What does Kubernetes do, and why does it matter?
Q2. Why is pg_isready inadequate as a Kubernetes liveness probe for PostgreSQL?
Q3. During a network partition, the Kubernetes control plane marks a node NotReady and evicts its pods. What is the state of the PostgreSQL pod on that node?
Q4. Which questions should be asked of a storage class before running a production database on it? Select all that apply.
Q5. Running PostgreSQL on Kubernetes removes the split-brain problem, because the control plane guarantees only one pod is the primary.
Q6. Trace how a network partition on Kubernetes leads to two primaries, and name the defence.
Passing score: 75%. Answers are checked in this browser.