Skip to content

docs: rework StatefulSet chapter with hardened lab and deeper explanations#5

Merged
r97221004 merged 13 commits into
masterfrom
docs/update-statefulset-chapter
Jul 2, 2026
Merged

docs: rework StatefulSet chapter with hardened lab and deeper explanations#5
r97221004 merged 13 commits into
masterfrom
docs/update-statefulset-chapter

Conversation

@r97221004

Copy link
Copy Markdown
Owner

Summary

  • Add readiness/liveness/startup probes, a non-root securityContext, and resource requests/limits to the PostgreSQL StatefulSet lab, fixing a gap where kubectl wait --for=condition=Ready reported Ready before Postgres could accept connections.
  • Restructure the chapter into progressive-disclosure sections: a minimal core YAML (identity/PVC/ordering only), a separate "Hardening this lab" section explaining each production field, dedicated "What a headless Service is" and "What a volumeClaimTemplate is" subsections with comparison tables, and a namespace/DNS-name breakdown.
  • Add k9s watch points (:sts/:pods/:pvc) at Pod startup and the scale-to-2 exercise so readers can observe ordered creation and per-replica PVC binding live.
  • Fix doc/manifest drift and a broken cross-reference (link pointed at deployment.md, which has no PVC content; corrected to volumes.md).
  • Ground the ordered-lifecycle and PVC-persistence claims in concrete, verifiable exercises (real data written/read across Pod deletes and scale down/up) instead of just Pod-status checks.

Test plan

  • Read through docs/config-and-data/statefulset.md for flow and correctness
  • kubectl apply -f manifests/config-and-data/postgres-statefulset.yaml on a test cluster and walk through the exercises (apply → wait → DNS lookup → write/read data → delete/reattach → scale to 2 → scale to 1)

🤖 Generated with Claude Code

r97221004 added 13 commits July 1, 2026 17:48
AS IS: the scale-to-2 exercise showed the ordinal pattern appearing but never showed what happens to the PVC when scaling back down

TO BE: adds a kubectl get pvc check and an explanation that pgdata-postgres-1 survives scale-down and gets reattached on scale-up, reinforcing the "PVCs outlive the Pod" lesson from the earlier delete/reattach test

TASK # N/A
AS IS: the doc asserts ordered Pod creation "matters for clustered databases" without showing why

TO BE: adds the pg_basebackup primary/replica pattern to show what breaks without OrderedReady — a replica bootstrapping before the primary's DNS is resolvable

TASK # N/A
AS IS: the delete/reattach exercise only checked that postgres-0 came back and pvc stayed Bound, which doesn't actually prove data survived

TO BE: adds readiness/pg_isready waits, a DNS lookup check, and a real insert-then-verify test so the exercise proves data persistence instead of just Pod identity

TASK # N/A
…t lab

AS IS: the postgres StatefulSet had no probes or resource requests/limits,
so kubectl wait reported Ready before postgres could accept connections,
requiring a manual pg_isready polling loop as a workaround

TO BE: add pg_isready-based readinessProbe/livenessProbe and cpu/memory
requests/limits so the Pod's Ready condition reflects real DB availability,
plus comments noting production should pin the image version and choose
an explicit StorageClass

TASK # N/A
AS IS: the postgres container ran as root with no startup grace period,
and probe commands hardcoded "appuser" instead of reading POSTGRES_USER

TO BE: run as the image's non-root user via securityContext/fsGroup, add
a startupProbe so initialization isn't cut short by liveness checks, and
have probes read $POSTGRES_USER so they stay in sync with the Secret

TASK # N/A
AS IS: exercises used kubectl wait --timeout=120s, shorter than the
startupProbe's worst-case 150s window (failureThreshold 30 * periodSeconds 5),
so a slow first-time initdb could time out the wait before the probe itself gave up

TO BE: bump the wait timeout to 180s so it comfortably covers the
startupProbe's worst case

TASK # N/A
AS IS: the doc used "headless Service" and referenced per-Pod DNS names
without ever defining what makes a headless Service different, leaving
readers to infer it from the manifest alone

TO BE: add a dedicated section defining clusterIP: None, a comparison
table against a normal Service, and why StatefulSets need per-Pod DNS
instead of load-balanced traffic

TASK # N/A
AS IS: the DNS example postgres-0.postgres.default.svc.cluster.local
was shown with no explanation, so "postgres" appearing twice and
"default" could easily be misread as parts of the Service name

TO BE: break down the <pod>.<service>.<namespace> format and note the
manifests never set metadata.namespace, so default comes from the
current kubectl context, not a hardcoded value

TASK # N/A
AS IS: the single 84-line YAML mixed core StatefulSet mechanics with
probes, securityContext, and resource limits, making it hard to see
identity/PVC/ordering without wading through production-hardening noise

TO BE: trim the walkthrough YAML to just the three core StatefulSet
concepts, and move the hardening fields into a separate section with
a field-by-field explanation table plus their own YAML snippet

TASK # N/A
AS IS: the doc mentioned volumeClaimTemplates gives each replica its
own PVC but never explained how that differs from a normal Pod's
volumes: reference, or where the pgdata-postgres-N naming comes from

TO BE: add a dedicated section contrasting shared-PVC volumes: against
per-replica volumeClaimTemplates, with the naming convention and a
comparison table, linking to the scaling exercise and reclaim-policy docs

TASK # N/A
AS IS: the link to "Deployment replicas sharing one PVC" pointed at
deployment.md, which never mentions PVCs at all — the actual content
lives in volumes.md

TO BE: point the link at volumes.md so readers land on the section
that actually explains the shared-PVC footgun

TASK # N/A
AS IS: the manifest listed Service before StatefulSet with no
explanation, so readers could reasonably assume the order was arbitrary
or even backwards (workload before its supporting Service)

TO BE: note that serviceName references the Service by name, so
listing it first mirrors creating a ConfigMap/Secret before the Pod
that reads it, and avoids a DNS race if the order were reversed

TASK # N/A
AS IS: the lab only mentioned k9s once, for the delete/reattach test,
leaving readers to poll kubectl get/wait for everything else even
though the ordered Pod creation and PVC binding are exactly the kind
of live reconciliation k9s is meant to make visible

TO BE: add k9s tips at first pod startup and at the scale-to-2
exercise, pointing at :sts/:pods/:pvc so readers can watch ordering
and per-replica PVC binding happen instead of just reading kubectl output

TASK # N/A
@r97221004
r97221004 merged commit 40e8900 into master Jul 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant