🔝 Retour au Sommaire
Déployer PostgreSQL sur Kubernetes représente un défi particulier. Contrairement à une application web stateless (sans état) qui peut être répliquée et détruite à volonté, une base de données a besoin de persistance et d'identité stable.
C'est exactement ce que les StatefulSets apportent à Kubernetes. Dans ce chapitre, nous allons comprendre ce concept fondamental et voir comment il permet de faire fonctionner PostgreSQL de manière fiable dans un cluster Kubernetes.
Avant de plonger dans les StatefulSets, assurons-nous de comprendre les bases de Kubernetes.
Kubernetes (souvent abrégé "K8s") est une plateforme d'orchestration de conteneurs. Elle permet de :
- Déployer des applications conteneurisées
- Les faire évoluer automatiquement (scaling)
- Les maintenir en bonne santé (self-healing)
- Gérer le réseau et le stockage
┌─────────────────────────────────────────────────────────────────────┐
│ CLUSTER KUBERNETES │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Node 1 │ │ Node 2 │ │ Node 3 │ │
│ │ (Serveur) │ │ (Serveur) │ │ (Serveur) │ │
│ │ │ │ │ │ │ │
│ │ ┌───┐ ┌───┐ │ │ ┌───┐ ┌───┐ │ │ ┌───┐ ┌───┐ │ │
│ │ │Pod│ │Pod│ │ │ │Pod│ │Pod│ │ │ │Pod│ │Pod│ │ │
│ │ └───┘ └───┘ │ │ └───┘ └───┘ │ │ └───┘ └───┘ │ │
│ │ │ │ │ │ │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ Kubernetes distribue les Pods sur les Nodes disponibles │
│ │
└─────────────────────────────────────────────────────────────────────┘
| Concept | Description |
|---|---|
| Cluster | L'ensemble de l'infrastructure Kubernetes |
| Node | Une machine (physique ou virtuelle) dans le cluster |
| Pod | L'unité de base : un ou plusieurs conteneurs qui s'exécutent ensemble |
| Service | Un point d'accès réseau stable vers des Pods |
| Volume | Du stockage attaché aux Pods |
Kubernetes a d'abord été conçu pour les applications stateless (sans état) :
APPLICATION STATELESS (ex: serveur web)
───────────────────────────────────────
Caractéristiques :
• Chaque instance est identique et interchangeable
• Pas de données locales à conserver
• Peut être détruite et recréée n'importe où
• Facile à répliquer
┌─────┐ ┌─────┐ ┌─────┐
│Web 1│ │Web 2│ │Web 3│ ← Tous identiques
└─────┘ └─────┘ └─────┘ Interchangeables
│ │ │
└────────┼────────┘
│
┌────────┴────────┐
│ Load Balancer │
└─────────────────┘
│
Utilisateurs
Si Web 2 meurt → Kubernetes le recrée ailleurs
Aucune perte de données car pas d'état local
APPLICATION STATEFUL (ex: PostgreSQL)
─────────────────────────────────────
Caractéristiques :
• Chaque instance a une identité unique
• Stocke des données qui doivent persister
• Ne peut PAS être détruite sans précaution
• La réplication est complexe
┌─────────────┐ ┌───────────┐ ┌───────────┐
│ PG Primary │ │PG Replica │ │PG Replica │
│ (écriture) │ │ (lecture) │ │ (lecture) │
└─────┬───────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐
│ Disque 1 │ │ Disque 2 │ │ Disque 3 │
│ (données)│ │ (données)│ │ (données)│
└───────────┘ └───────────┘ └───────────┘
Si PG Primary meurt → Catastrophe si mal géré !
Les données doivent être préservées
L'identité (primary vs replica) compte
Un Deployment est la ressource standard pour déployer des applications sur Kubernetes :
# Exemple de Deployment (pour une app stateless)
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:latestCe Deployment crée 3 Pods identiques avec des noms aléatoires :
web-app-7d9f8b6c4d-x2k9p ← Nom généré aléatoirement
web-app-7d9f8b6c4d-m3n7q ← Nom généré aléatoirement
web-app-7d9f8b6c4d-h8j2w ← Nom généré aléatoirement
| Comportement du Deployment | Problème pour PostgreSQL |
|---|---|
| Noms de Pods aléatoires | Impossible de savoir qui est primary/replica |
| Pas d'ordre de démarrage | Le replica pourrait démarrer avant le primary |
| Stockage partagé ou éphémère | Les données seraient perdues ou corrompues |
| Remplacement arbitraire | Un nouveau Pod ne retrouverait pas ses données |
❌ SCÉNARIO CATASTROPHE AVEC DEPLOYMENT
───────────────────────────────────────
1. Deployment crée 3 Pods PostgreSQL
pod-abc123 (primary ?)
pod-def456 (replica ?)
pod-ghi789 (replica ?)
2. pod-abc123 (primary) crashe
3. Kubernetes recrée un Pod...
pod-xyz999 (nouveau, vide !)
4. Problèmes :
• Où sont les données de l'ancien primary ?
• Le nouveau Pod ne sait pas qu'il était primary
• Le disque de l'ancien Pod est peut-être perdu
→ PERTE DE DONNÉES POTENTIELLE
Un StatefulSet est une ressource Kubernetes spécialement conçue pour les applications qui ont besoin de :
- Identité stable : Chaque Pod a un nom prévisible et permanent
- Stockage persistant : Chaque Pod a son propre volume de données
- Ordre de déploiement : Les Pods sont créés et supprimés dans un ordre défini
- Réseau stable : Chaque Pod a un nom DNS prévisible
┌─────────────────────────────────────────────────────────────────────┐
│ GARANTIES DU STATEFULSET │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. IDENTITÉ STABLE │
│ ───────────────── │
│ Noms prévisibles : postgres-0, postgres-1, postgres-2 │
│ Pas de suffixes aléatoires │
│ │
│ 2. STOCKAGE PERSISTANT │
│ ───────────────────── │
│ Chaque Pod a son propre PersistentVolumeClaim │
│ Le volume survit à la destruction du Pod │
│ postgres-0 retrouve toujours ses données │
│ │
│ 3. DÉPLOIEMENT ORDONNÉ │
│ ──────────────────── │
│ Création : postgres-0, puis postgres-1, puis postgres-2 │
│ Suppression : postgres-2, puis postgres-1, puis postgres-0 │
│ │
│ 4. RÉSEAU STABLE │
│ ───────────────── │
│ DNS : postgres-0.postgres-svc.namespace.svc.cluster.local │
│ Toujours accessible à la même adresse │
│ │
└─────────────────────────────────────────────────────────────────────┘
| Aspect | Deployment | StatefulSet |
|---|---|---|
| Noms des Pods | Aléatoires (hash) | Ordonnés (0, 1, 2...) |
| Identité | Interchangeable | Unique et stable |
| Stockage | Partagé ou éphémère | Dédié et persistant |
| Ordre de création | Parallèle | Séquentiel |
| Ordre de suppression | Arbitraire | Inverse de création |
| DNS | Via Service uniquement | Hostname individuel |
| Cas d'usage | Apps stateless | Bases de données, caches |
Voici la structure d'un StatefulSet pour PostgreSQL :
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: "postgres-svc" # Service headless associé
replicas: 3 # Nombre d'instances
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates: # Template pour les volumes
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gispec:
serviceName: "postgres-svc"Ce champ lie le StatefulSet à un Service Headless qui permet la découverte DNS des Pods individuels.
spec:
replicas: 3Définit le nombre d'instances. Les Pods seront nommés :
postgres-0postgres-1postgres-2
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10GiC'est la fonctionnalité clé du StatefulSet. Pour chaque Pod, Kubernetes crée automatiquement un PersistentVolumeClaim (PVC) distinct :
StatefulSet postgres (replicas: 3)
│
├── postgres-0
│ └── PVC: data-postgres-0 ──► Volume dédié
│
├── postgres-1
│ └── PVC: data-postgres-1 ──► Volume dédié
│
└── postgres-2
└── PVC: data-postgres-2 ──► Volume dédié
Contrairement aux Deployments, les StatefulSets utilisent un nommage ordonné et prévisible :
Format : <nom-statefulset>-<index>
Exemples :
postgres-0 (premier Pod, index 0)
postgres-1 (deuxième Pod, index 1)
postgres-2 (troisième Pod, index 2)
Cette prévisibilité est cruciale pour PostgreSQL :
CONFIGURATION POSTGRESQL AVEC STATEFULSET
─────────────────────────────────────────
postgres-0 → Primary (maître)
Accepte lectures ET écritures
postgres-1 → Replica (esclave)
Réplique depuis postgres-0
Lectures uniquement
postgres-2 → Replica (esclave)
Réplique depuis postgres-0
Lectures uniquement
L'index 0 est TOUJOURS le primary
Les scripts de configuration peuvent s'y fier
Un Service Headless est un Service sans ClusterIP qui permet d'accéder directement aux Pods :
apiVersion: v1
kind: Service
metadata:
name: postgres-svc
spec:
clusterIP: None # ← Headless : pas d'IP de service
selector:
app: postgres
ports:
- port: 5432Avec ce Service, chaque Pod obtient un enregistrement DNS individuel :
ENREGISTREMENTS DNS CRÉÉS
─────────────────────────
postgres-0.postgres-svc.default.svc.cluster.local
│ │ │ │ │
│ │ │ │ └── Domaine cluster
│ │ │ └── Suffixe standard
│ │ └── Namespace
│ └── Nom du Service
└── Nom du Pod (hostname)
Autres Pods :
postgres-1.postgres-svc.default.svc.cluster.local
postgres-2.postgres-svc.default.svc.cluster.local
Utilisation pratique :
# Connexion au Primary (postgres-0)
conn = psycopg2.connect(
host="postgres-0.postgres-svc.default.svc.cluster.local",
database="mydb",
user="postgres"
)
# Connexion à un Replica spécifique
conn_replica = psycopg2.connect(
host="postgres-1.postgres-svc.default.svc.cluster.local",
database="mydb",
user="postgres"
)Chaque Pod connaît son propre hostname, ce qui permet des scripts de configuration intelligents :
# Dans le conteneur postgres-0
$ hostname
postgres-0
# Dans le conteneur postgres-1
$ hostname
postgres-1Exemple de script d'initialisation :
#!/bin/bash
# Récupérer l'index du Pod
HOSTNAME=$(hostname)
INDEX=${HOSTNAME##*-} # Extrait le numéro après le dernier "-"
if [ "$INDEX" -eq 0 ]; then
echo "Je suis le PRIMARY (postgres-0)"
# Configuration en tant que primary
pg_ctl start -D /var/lib/postgresql/data
else
echo "Je suis un REPLICA (postgres-$INDEX)"
# Configuration en tant que replica
# Attendre que le primary soit prêt
until pg_isready -h postgres-0.postgres-svc; do
echo "Attente du primary..."
sleep 2
done
# Démarrer la réplication
pg_basebackup -h postgres-0.postgres-svc -D /var/lib/postgresql/data -R
pg_ctl start -D /var/lib/postgresql/data
fiPar défaut, les données dans un conteneur sont éphémères :
SANS PERSISTANCE
────────────────
1. Pod postgres-0 créé
└── Données en mémoire/filesystem conteneur
2. Pod postgres-0 crashe ou est supprimé
3. Pod postgres-0 recréé
└── Nouveau filesystem vide !
→ TOUTES LES DONNÉES SONT PERDUES
Kubernetes utilise deux concepts pour la persistance :
| Concept | Description |
|---|---|
| PersistentVolume (PV) | Un espace de stockage réel (disque, NFS, cloud storage) |
| PersistentVolumeClaim (PVC) | Une demande de stockage par une application |
RELATION PV / PVC
─────────────────
┌─────────────────────────────────────────────────────────────────┐
│ INFRASTRUCTURE │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ PV 1 │ │ PV 2 │ │ PV 3 │ │
│ │ 100 Gi │ │ 50 Gi │ │ 200 Gi │ │
│ │ SSD Fast │ │ HDD Slow │ │ SSD Fast │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
└─────────┼────────────────┼────────────────┼─────────────────────┘
│ │ │
│ BINDING │ │
│ (liaison) │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ APPLICATIONS │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ PVC 1 │ │ PVC 2 │ │ PVC 3 │ │
│ │"Je veux │ │"Je veux │ │"Je veux │ │
│ │ 50Gi SSD" │ │ 20Gi" │ │ 100Gi SSD" │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ postgres-0 │ │ postgres-1 │ │ postgres-2 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Le StatefulSet automatise la création des PVC via volumeClaimTemplates :
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "fast-ssd" # Classe de stockage
resources:
requests:
storage: 10GiÀ la création du StatefulSet, Kubernetes génère automatiquement :
StatefulSet: postgres (replicas: 3)
│
├── Crée Pod: postgres-0
│ └── Crée PVC: data-postgres-0
│ └── Lie à un PV de 10Gi (fast-ssd)
│
├── Crée Pod: postgres-1
│ └── Crée PVC: data-postgres-1
│ └── Lie à un PV de 10Gi (fast-ssd)
│
└── Crée Pod: postgres-2
└── Crée PVC: data-postgres-2
└── Lie à un PV de 10Gi (fast-ssd)
Point crucial : Les PVC survivent à la suppression des Pods !
CYCLE DE VIE
────────────
1. StatefulSet créé avec replicas: 3
→ postgres-0, postgres-1, postgres-2 créés
→ data-postgres-0, data-postgres-1, data-postgres-2 créés
2. postgres-1 crashe
→ Pod supprimé
→ PVC data-postgres-1 CONSERVÉ (données intactes)
3. Kubernetes recrée postgres-1
→ Nouveau Pod avec le même nom
→ Se rattache à data-postgres-1
→ RETROUVE SES DONNÉES !
4. Scale down à replicas: 1
→ postgres-2 supprimé, PVC data-postgres-2 CONSERVÉ
→ postgres-1 supprimé, PVC data-postgres-1 CONSERVÉ
→ postgres-0 reste actif
5. Scale up à replicas: 3
→ postgres-1 recréé, retrouve data-postgres-1
→ postgres-2 recréé, retrouve data-postgres-2
Une StorageClass définit le type de stockage à utiliser :
# Exemple de StorageClass pour AWS EBS
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
throughput: "125"
reclaimPolicy: Retain # Garder les données après suppression
allowVolumeExpansion: true # Permettre l'agrandissement
volumeBindingMode: WaitForFirstConsumer StorageClasses courantes par cloud :
| Cloud Provider | StorageClass | Type de stockage |
|---|---|---|
| AWS | gp3, io2 | EBS SSD |
| GCP | pd-ssd, pd-balanced | Persistent Disk |
| Azure | managed-premium | Azure Disk SSD |
| On-premise | local-storage | Disques locaux |
Le StatefulSet crée les Pods un par un, dans l'ordre :
CRÉATION DES PODS
─────────────────
Temps ──────────────────────────────────────────────────────────►
┌──────────────┐
│ postgres-0 │ Créé en premier
│ Starting │
└──────┬───────┘
│ Ready ✓
▼
┌──────────────┐
│ postgres-1 │ Créé quand postgres-0 est Ready
│ Starting │
└──────┬───────┘
│ Ready ✓
▼
┌──────────────┐
│ postgres-2 │ Créé quand postgres-1 est Ready
│ Starting │
└──────────────┘
Pourquoi c'est important pour PostgreSQL :
postgres-0démarre en tant que primarypostgres-0initialise le cluster et devient disponiblepostgres-1démarre et peut se connecter àpostgres-0pour la réplicationpostgres-2démarre et se connecte également àpostgres-0
Sans cet ordre, les replicas essaieraient de se connecter à un primary qui n'existe pas encore !
La suppression suit l'ordre inverse :
SUPPRESSION DES PODS (scale down ou delete)
───────────────────────────────────────────
Temps ──────────────────────────────────────────────────────────►
┌──────────────┐
│ postgres-2 │ Supprimé en premier
│ Terminating │
└──────┬───────┘
│ Terminé ✓
▼
┌──────────────┐
│ postgres-1 │ Supprimé ensuite
│ Terminating │
└──────┬───────┘
│ Terminé ✓
▼
┌──────────────┐
│ postgres-0 │ Supprimé en dernier (le primary)
│ Terminating │
└──────────────┘
Pourquoi c'est important :
- Les replicas sont supprimés avant le primary
- Évite les erreurs de réplication vers un primary inexistant
- Permet une dégradation gracieuse du cluster
Par défaut, le StatefulSet utilise OrderedReady. Vous pouvez changer ce comportement :
spec:
podManagementPolicy: OrderedReady # Défaut : un par un, attend Ready
# ou
podManagementPolicy: Parallel # Tous en parallèle (use case avancé)| Policy | Comportement | Cas d'usage |
|---|---|---|
| OrderedReady | Séquentiel, attend que chaque Pod soit Ready | Bases de données, systèmes avec dépendances |
| Parallel | Tous les Pods en même temps | Applications stateful sans dépendance d'ordre |
Pour PostgreSQL, gardez toujours OrderedReady.
Le StatefulSet supporte deux stratégies de mise à jour :
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 0 # Mettre à jour tous les PodsLes Pods sont mis à jour un par un, en ordre inverse (du plus grand index au plus petit) :
ROLLING UPDATE
──────────────
État initial : postgres-0 (v1), postgres-1 (v1), postgres-2 (v1)
1. postgres-2 supprimé → recréé avec v2
postgres-0 (v1), postgres-1 (v1), postgres-2 (v2) ✓
2. postgres-1 supprimé → recréé avec v2
postgres-0 (v1), postgres-1 (v2), postgres-2 (v2) ✓
3. postgres-0 supprimé → recréé avec v2
postgres-0 (v2), postgres-1 (v2), postgres-2 (v2) ✓
Mise à jour terminée !
spec:
updateStrategy:
type: OnDeleteLes Pods ne sont mis à jour que lorsqu'ils sont manuellement supprimés :
# Mise à jour manuelle du Pod 0
kubectl delete pod postgres-0
# Kubernetes recrée postgres-0 avec la nouvelle configurationUtile pour : Mises à jour contrôlées, tests progressifs.
Le paramètre partition permet des mises à jour "canary" :
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 2 # Seuls les Pods avec index >= 2 seront mis à jourPARTITION UPDATE (partition: 2)
───────────────────────────────
Pods existants : postgres-0 (v1), postgres-1 (v1), postgres-2 (v1)
Après changement de l'image vers v2 :
• postgres-2 (index 2 >= partition 2) → Mis à jour vers v2
• postgres-1 (index 1 < partition 2) → Reste en v1
• postgres-0 (index 0 < partition 2) → Reste en v1
État final : postgres-0 (v1), postgres-1 (v1), postgres-2 (v2)
Vous pouvez tester v2 sur postgres-2 avant de mettre à jour les autres !
┌────────────────────────────────────────────────────────────────┐
│ CLUSTER POSTGRESQL │
├────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────┐ │
│ │ Service: postgres-svc │ │
│ │ (Headless, ClusterIP: None) │ │
│ └───────────────────┬───────────────────┘ │
│ │ │
│ ┌───────────────────┼───────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ postgres-0 │ │ postgres-1 │ │ postgres-2 │ │
│ │ (PRIMARY) │ │ (REPLICA) │ │ (REPLICA) │ │
│ │ │ │ │ │ │ │
│ │ Port: 5432 │ │ Port: 5432 │ │ Port: 5432 │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ ┌──────┴──────┐ ┌──────┴──────┐ ┌──────┴──────┐ │
│ │ PVC │ │ PVC │ │ PVC │ │
│ │data-postgres│ │data-postgres│ │data-postgres│ │
│ │ -0 │ │ -1 │ │ -2 │ │
│ │ (10Gi) │ │ (10Gi) │ │ (10Gi) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└────────────────────────────────────────────────────────────────┘
# postgres-service.yaml
apiVersion: v1
kind: Service
metadata:
name: postgres-svc
labels:
app: postgres
spec:
clusterIP: None # Headless Service
selector:
app: postgres
ports:
- name: postgresql
port: 5432
targetPort: 5432# postgres-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-config
data:
POSTGRES_DB: "myapp"
POSTGRES_USER: "appuser"
# Configuration PostgreSQL
postgresql.conf: |
listen_addresses = '*'
max_connections = 100
shared_buffers = 256MB
wal_level = replica
max_wal_senders = 3
max_replication_slots = 3
hot_standby = on# postgres-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: postgres-secret
type: Opaque
stringData:
POSTGRES_PASSWORD: "your-secure-password"
REPLICATION_PASSWORD: "replication-password"# postgres-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: "postgres-svc"
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
name: postgresql
env:
- name: POSTGRES_DB
valueFrom:
configMapKeyRef:
name: postgres-config
key: POSTGRES_DB
- name: POSTGRES_USER
valueFrom:
configMapKeyRef:
name: postgres-config
key: POSTGRES_USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: POSTGRES_PASSWORD
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
readinessProbe:
exec:
command:
- pg_isready
- -U
- $(POSTGRES_USER)
- -d
- $(POSTGRES_DB)
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
exec:
command:
- pg_isready
- -U
- $(POSTGRES_USER)
- -d
- $(POSTGRES_DB)
initialDelaySeconds: 30
periodSeconds: 10
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "standard" # Adapter selon votre cluster
resources:
requests:
storage: 10Gi# Appliquer les manifestes
kubectl apply -f postgres-secret.yaml
kubectl apply -f postgres-configmap.yaml
kubectl apply -f postgres-service.yaml
kubectl apply -f postgres-statefulset.yaml
# Vérifier le déploiement
kubectl get statefulset postgres
kubectl get pods -l app=postgres
kubectl get pvc
# Voir les logs du primary
kubectl logs postgres-0
# Se connecter au primary
kubectl exec -it postgres-0 -- psql -U appuser -d myappreadinessProbe:
exec:
command: ["pg_isready", "-U", "postgres"]
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
exec:
command: ["pg_isready", "-U", "postgres"]
initialDelaySeconds: 30
periodSeconds: 10Les probes garantissent que :
- Les Pods ne reçoivent du trafic que lorsqu'ils sont prêts
- Les Pods défaillants sont redémarrés
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"Évite les problèmes de :
- Pods évincés par manque de mémoire
- Contention CPU
| Workload | StorageClass recommandée |
|---|---|
| Production | SSD avec IOPS garantis |
| Développement | Standard/balanced |
| Haute performance | NVMe local ou io2 |
# Dans le StorageClass
reclaimPolicy: Retain # Ne jamais supprimer automatiquement les donnéesPour la réplication PostgreSQL en production, utilisez un Operator (voir chapitre 20bis.4.2) plutôt que de scripter la réplication vous-même.
| Limitation | Description |
|---|---|
| Pas de réplication automatique | Vous devez configurer la réplication PostgreSQL vous-même |
| Pas de failover automatique | Si postgres-0 meurt, pas de promotion automatique d'un replica |
| Pas de backup intégré | Les sauvegardes sont votre responsabilité |
| Pas de monitoring intégré | Vous devez ajouter vos propres outils |
Les StatefulSets fournissent les briques de base (identité, persistance, ordre), mais pas la logique métier spécifique à PostgreSQL.
C'est pourquoi des Operators PostgreSQL ont été créés :
STATEFULSET SEUL STATEFULSET + OPERATOR
──────────────── ──────────────────────
✓ Identité stable ✓ Identité stable
✓ Persistance ✓ Persistance
✓ Ordre de déploiement ✓ Ordre de déploiement
✓ Réplication automatique
✗ Pas de réplication auto ✓ Failover automatique
✗ Pas de failover ✓ Backups planifiés
✗ Pas de backup ✓ Monitoring intégré
✗ Pas de monitoring ✓ Scaling simplifié
Le chapitre suivant (20bis.4.2) couvre les Operators en détail.
| Concept | Description |
|---|---|
| StatefulSet | Ressource Kubernetes pour applications stateful |
| Identité stable | Noms prévisibles (postgres-0, postgres-1, ...) |
| Persistance | Chaque Pod a son PVC dédié qui survit aux redémarrages |
| Ordre | Création séquentielle, suppression en ordre inverse |
| DNS stable | Chaque Pod accessible via <pod>.<service>.<namespace>.svc.cluster.local |
✅ Utilisez un StatefulSet pour :
- Bases de données (PostgreSQL, MySQL, MongoDB)
- Systèmes de cache distribués (Redis Cluster)
- Systèmes de messaging (Kafka, RabbitMQ)
- Toute application nécessitant identité + persistance
❌ N'utilisez PAS un StatefulSet pour :
- Applications web stateless
- Workers de traitement sans état
- Toute application où les instances sont interchangeables
Un StatefulSet seul n'est pas suffisant pour PostgreSQL en production. Vous aurez besoin de :
- Un Operator pour la gestion automatisée (failover, backups)
- Du monitoring (Prometheus, Grafana)
- Une stratégie de backup (pg_dump, pgBackRest, WAL archiving)
- Une configuration réseau sécurisée (NetworkPolicies, TLS)
Ces sujets sont couverts dans les chapitres suivants.
Les StatefulSets sont la fondation pour exécuter PostgreSQL sur Kubernetes. Ils résolvent les problèmes fondamentaux d'identité et de persistance que les Deployments ne peuvent pas adresser.
Cependant, ils ne sont qu'une partie de la solution. Pour une configuration production-ready de PostgreSQL sur Kubernetes, vous combinerez :
- StatefulSets : Pour l'infrastructure de base
- Operators : Pour l'automatisation et la gestion du cycle de vie
- Services : Pour l'accès réseau
- ConfigMaps/Secrets : Pour la configuration
- Monitoring : Pour l'observabilité
Le chapitre suivant sur les Operators vous montrera comment automatiser tout ce que les StatefulSets ne gèrent pas nativement.
- Kubernetes : Déployer une base de données stateful
- Comprendre le stockage dans Kubernetes
- StatefulSets vs Deployments : Quand utiliser quoi
- kubectl : CLI Kubernetes
- k9s : Interface terminal pour Kubernetes
- Lens : IDE Kubernetes