Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

03 — StatefulSet with PVC and headless Service

A 3-replica PostgreSQL-style StatefulSet with stable storage and stable network identity. The headless Service exposes each pod under a predictable DNS name (<release>-db-0.<release>-db.<ns>.svc).

What this shows

  • A statefulSets.db workload — replaces deployments.<n> for ordered, stateful pods.
  • volumeClaimTemplates — a list of embedded PVCs, one entry named data, so every pod gets its own PVC, retained across restarts and scale-up.
  • service.clusterIP: None — headless Service required by StatefulSet for stable per-pod DNS.
  • replicaCount: 3 with podManagementPolicy: OrderedReady (chart default).
  • envSecrets referencing an externally-managed Secret for POSTGRES_PASSWORD (no ESO here — see 07-external-secrets/ for that).
  • Per-pod volumeMounts map keyed by mount name, referencing the volumeClaimTemplates entry by its metadata.name.

Delta from 02-web-app-ingress

ChangedWhat and why
deployments → statefulSetsStatefulSet, not Deployment — needed for stable storage + stable DNS.
volumeClaimTemplatesPer-pod PVC; volumes (the per-pod ephemeral kind) wouldn’t survive pod replacement.
service.clusterIP: NoneHeadless Service so each pod gets <pod>.<service>.<ns>.svc DNS.
service.ports.postgresSingle non-http port — port ordering rule still puts it first since “http” is absent (alphabetical fallback).
No Ingress, no HPAStateful workloads aren’t horizontally autoscaled in this template (use a connection pooler or read-replicas pattern instead).
Pre-existing Secretdb-credentials Secret must exist in the namespace before install (or come from a different release). For an ESO-managed flow, see ../07-external-secrets/.

Files

FilePurpose
values.yamlChart values.
argocd/application.yamlArgo CD Application, single source.
argocd/application-multisource.yamlArgo CD Application with spec.sources[].
flux/ocirepository.yamlFlux OCIRepository.
flux/helmrelease.yamlFlux HelmRelease.
helm/install.shPlain helm upgrade --install.

Try it

# First create the password Secret (this example doesn't manage it)
kubectl create namespace stateful
kubectl create secret generic db-credentials \
  --from-literal=POSTGRES_PASSWORD='changeme' \
  --from-literal=POSTGRES_USER='app' \
  -n stateful

# Then install via any of these
bash helm/install.sh
kubectl apply -f argocd/application.yaml -n argocd
kubectl apply -f flux/

Prerequisites

  • A default StorageClass in the cluster, or set storageClassName in the data entry’s spec for your provisioner.
  • The db-credentials Secret pre-existing in the target namespace.