apiVersion:v1kind:ConfigMapmetadata:name:postgresql-master-configdata:master.conf:|
# Configuration Master PostgreSQL
listen_addresses = '*'
max_connections = 100
shared_buffers = 256MB
# ===== Configuration WAL pour Réplication =====wal_level=replica# Active la réplicationmax_wal_senders=10# Nombre max de connexions de réplicationmax_replication_slots=10# Nombre max de slotswal_keep_size=1GB# Rétention des WAL (ajuster selon le besoin)hot_standby=on# Permet les lectures sur le slave# ===== Archivage WAL (optionnel mais recommandé) =====archive_mode=onarchive_command='test ! -f /var/lib/postgresql/archive/%f && cp %p /var/lib/postgresql/archive/%f'# ===== Logging =====log_destination='stderr'logging_collector=onlog_directory='log'log_filename='postgresql-%Y-%m-%d_%H%M%S.log'log_statement='mod'log_replication_commands=onlog_connections=onlog_disconnections=onpg_hba.conf:|
# TYPE DATABASE USER ADDRESS METHOD
local all all trust
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
# Connexions depuis les pods OpenShift (ajuster le CIDR selon votre cluster)hostallall10.128.0.0/14md5# ===== Configuration Réplication =====hostreplicationreplicator10.128.0.0/14md5hostreplicationreplicator127.0.0.1/32md5
Points d'attention :
CIDR réseau : 10.128.0.0/14 est le réseau par défaut OpenShift. À ajuster selon votre configuration réseau.
wal_keep_size : Détermine combien de WAL sont conservés. Augmenter si le slave peut être déconnecté longtemps.
shared_buffers : À ajuster selon les ressources disponibles (généralement 25% de la RAM).
apiVersion:v1kind:ConfigMapmetadata:name:postgresql-master-initdata:init-master.sh:|
#!/bin/bash
set -e
echo"Initialisation du master pour la réplication..."# Vérifier si déjà initialiséifpsql-Upostgres-dpostgres-tAc"SELECT 1 FROM pg_roles WHERE rolname='replicator'"|grep-q1;thenecho"Utilisateur de réplication déjà existant"else# Créer l'utilisateur de réplicationpsql-Upostgres<<-EOSQLCREATEUSERreplicatorWITHREPLICATIONENCRYPTEDPASSWORD'${REPLICATION_PASSWORD}';SELECTpg_create_physical_replication_slot('replication_slot_slave');EOSQLecho"Utilisateur de réplication créé avec succès"fi
Ce script :
Crée l'utilisateur replicator avec le privilège REPLICATION
Crée un slot de réplication physique nommé replication_slot_slave
Est idempotent (peut être exécuté plusieurs fois)
Appliquer :
oc apply -f postgresql-master-init.yaml
Étape 1.5 : Modification du DeploymentConfig Master
⚠️ ATTENTION : Redémarrage du pod master requis (interruption de service ~2-5 minutes)
Récupérer le DeploymentConfig actuel :
oc get dc/postgresql -o yaml > postgresql-master-updated.yaml
Modifications à appliquer dans spec.template.spec :
env:# ... env existantes ...-name:REPLICATION_PASSWORDvalueFrom:secretKeyRef:name:postgresql-replicationkey:replication-password-name:POSTGRESQL_ADMIN_PASSWORDvalueFrom:secretKeyRef:name:postgresql# Adapter au nom du secret existantkey:database-password
Résultat attendu : replication_slot_slave | physical | f
Paramètres WAL :
oc exec$POD_NAME -- psql -U postgres -c "SHOW wal_level; SHOW max_wal_senders; SHOW wal_keep_size;"
Résultat attendu : replica, 10, 1GB
Phase 2 : Déploiement du Slave
Étape 2.1 : PersistentVolumeClaim Slave
Resource : postgresql-slave-pvc.yaml
apiVersion:v1kind:PersistentVolumeClaimmetadata:name:postgresql-slavespec:accessModes:-ReadWriteOnceresources:requests:storage:20Gi# Ajuster à la taille du master ou plusstorageClassName:standard# Ajuster selon votre storage class
Points d'attention :
Taille >= taille du PVC master
Storage class avec performance similaire ou meilleure que le master
Appliquer :
oc apply -f postgresql-slave-pvc.yaml
Étape 2.2 : ConfigMap Slave
Resource : postgresql-slave-config.yaml
apiVersion:v1kind:ConfigMapmetadata:name:postgresql-slave-configdata:slave.conf:|
# Configuration Slave PostgreSQL
listen_addresses = '*'
max_connections = 100
shared_buffers = 256MB
# ===== Configuration Réplication =====wal_level=replicahot_standby=on# CRITIQUE : permet les lecturesmax_wal_senders=10max_replication_slots=10# ===== Logging =====log_destination='stderr'logging_collector=onlog_directory='log'log_filename='postgresql-%Y-%m-%d_%H%M%S.log'log_statement='mod'log_connections=onlog_disconnections=onsetup-slave.sh:|
#!/bin/bash
set -e
echo"Configuration du slave PostgreSQL..."# Attendre que le master soit disponibleecho"Attente du master sur ${MASTER_SERVICE}..."untilPGPASSWORD=${POSTGRESQL_ADMIN_PASSWORD}psql-h${MASTER_SERVICE}-Upostgres-c'\q'2>/dev/null;doecho"Master non disponible, nouvelle tentative dans 5s..."sleep5doneecho"Master disponible, démarrage de la configuration du slave..."# Vérifier si déjà initialiséif [ -f"${PGDATA}/PG_VERSION" ];thenecho"Data directory déjà initialisé, démarrage en mode standby..."exit0fi# Créer la copie depuis le master avec pg_basebackupecho"Création du backup depuis le master..."PGPASSWORD=${REPLICATION_PASSWORD}pg_basebackup\-h${MASTER_SERVICE}\-D${PGDATA}\-Ureplicator\-v-P-W-R\-Xstream\-Sreplication_slot_slave# Créer standby.signal (mode hot standby)touch"${PGDATA}/standby.signal"# Fixer les permissionschmod700${PGDATA}echo"Configuration du slave terminée avec succès"
Détails pg_basebackup :
-h : hôte du master
-D : répertoire de destination
-U : utilisateur de réplication
-v -P : verbose et progression
-W : demander le mot de passe
-R : créer automatiquement la configuration de réplication
-X stream : inclure les WAL nécessaires
-S : utiliser le slot de réplication
Appliquer :
oc apply -f postgresql-slave-config.yaml
Étape 2.3 : Deployment Slave
Resource : postgresql-slave-deployment.yaml
apiVersion:apps/v1kind:Deploymentmetadata:name:postgresql-slavelabels:app:postgresqlrole:slavespec:replicas:1selector:matchLabels:app:postgresqlrole:slavetemplate:metadata:labels:app:postgresqlrole:slavespec:# ===== Init Container : Configuration initiale du slave =====initContainers:-name:setup-slaveimage:postgres:15# ⚠️ MÊME VERSION QUE LE MASTERcommand: ["/bin/bash", "/scripts/setup-slave.sh"]
env:-name:PGDATAvalue:/var/lib/postgresql/data-name:MASTER_SERVICEvalue:postgresql# Nom du service du master-name:POSTGRESQL_ADMIN_PASSWORDvalueFrom:secretKeyRef:name:postgresql# Adapterkey:database-password-name:REPLICATION_PASSWORDvalueFrom:secretKeyRef:name:postgresql-replicationkey:replication-passwordvolumeMounts:-name:postgresql-datamountPath:/var/lib/postgresql/data-name:slave-configmountPath:/scripts# ===== Conteneur principal =====containers:-name:postgresqlimage:postgres:15# ⚠️ MÊME VERSION QUE LE MASTERargs:-"-c"-"config_file=/etc/postgresql/slave.conf"ports:-containerPort:5432protocol:TCPenv:-name:PGDATAvalue:/var/lib/postgresql/data-name:POSTGRES_USERvalue:postgres-name:POSTGRES_PASSWORDvalueFrom:secretKeyRef:name:postgresqlkey:database-passwordvolumeMounts:-name:postgresql-datamountPath:/var/lib/postgresql/data-name:slave-configmountPath:/etc/postgresql/slave.confsubPath:slave.conf# ===== Probes =====livenessProbe:exec:command:-/bin/sh--c-pg_isready-UpostgresinitialDelaySeconds:30timeoutSeconds:5periodSeconds:10readinessProbe:exec:command:-/bin/sh--c-pg_isready-UpostgresinitialDelaySeconds:10timeoutSeconds:5periodSeconds:5# ===== Ressources =====resources:requests:memory:"512Mi"cpu:"250m"limits:memory:"2Gi"cpu:"1000m"volumes:-name:postgresql-datapersistentVolumeClaim:claimName:postgresql-slave-name:slave-configconfigMap:name:postgresql-slave-configdefaultMode:0755
Points d'attention :
Image : Utiliser EXACTEMENT la même version que le master
MASTER_SERVICE : Doit correspondre au nom du service du master
apiVersion:v1kind:ConfigMapmetadata:name:postgresql-monitoring-queriesdata:replication-status.sql:|
SELECT
client_addr,
state,
sync_state,
(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) / 1024 / 1024)::INT AS lag_mb,
(EXTRACT(EPOCH FROM (now() - replay_time)))::INT AS lag_seconds
FROM pg_stat_replication;
database-size.sql:|
SELECT
pg_database.datname,
pg_size_pretty(pg_database_size(pg_database.datname)) AS size
FROM pg_database
ORDER BY pg_database_size(pg_database.datname) DESC;
connection-count.sql:|
SELECT
count(*) as total_connections,
sum(case when state = 'active' then 1 else 0 end) as active_connections,
sum(case when state = 'idle' then 1 else 0 end) as idle_connections
FROM pg_stat_activity;
replication-slots.sql:|
SELECT
slot_name,
slot_type,
active,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal
FROM pg_replication_slots;
apiVersion:monitoring.coreos.com/v1kind:PrometheusRulemetadata:name:postgresql-replication-alertsspec:groups:-name:postgresql-replicationinterval:30srules:-alert:PostgreSQLReplicationLagHighexpr:pg_replication_lag_seconds>30for:5mlabels:severity:warningannotations:summary:"PostgreSQL replication lag is high"description:"Replication lag is {{ $value }} seconds on {{ $labels.instance }}"-alert:PostgreSQLReplicationBrokenexpr:pg_replication_connected==0for:1mlabels:severity:criticalannotations:summary:"PostgreSQL replication is broken"description:"No replica is connected to the master"-alert:PostgreSQLReplicationSlotInactiveexpr:pg_replication_slot_active==0for:5mlabels:severity:warningannotations:summary:"PostgreSQL replication slot is inactive"description:"Replication slot {{ $labels.slot_name }} is not active"
CronJob de monitoring
Resource : postgresql-monitoring-cronjob.yaml
apiVersion:batch/v1kind:CronJobmetadata:name:postgresql-replication-checkspec:schedule:"*/15 * * * *"# Toutes les 15 minutesjobTemplate:spec:template:spec:serviceAccountName:postgresql-monitorcontainers:-name:checkimage:postgres:15command:-/bin/bash--c-|
MASTER_POD=$(kubectl get pods -l name=postgresql -o jsonpath='{.items[0].metadata.name}')
echo"Checking replication status..."kubectlexec$MASTER_POD--psql-Upostgres-t-c"
SELECT
CASE
WHEN count(*) = 0 THEN 'ERROR: No replication connection'
WHEN max((pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) / 1024 / 1024)::INT) > 100 THEN 'WARNING: Lag > 100MB'
WHEN max(EXTRACT(EPOCH FROM (now() - replay_time))::INT) > 60 THEN 'WARNING: Lag > 60 seconds'
ELSE 'OK: Replication healthy'
END as status
FROM pg_stat_replication;
"restartPolicy:OnFailure
Pré-requis : Créer le ServiceAccount avec les permissions nécessaires.
Procédure de rollback
Rollback du Slave
Si le slave pose problème, il peut être supprimé sans impact sur le master :
# Supprimer les ressources
oc delete deployment postgresql-slave
oc delete service postgresql-slave
oc delete pvc postgresql-slave
# Nettoyer le slot de réplication sur le master
MASTER_POD=$(oc get pods -l name=postgresql -o jsonpath='{.items[0].metadata.name}')
oc exec$MASTER_POD -- psql -U postgres -c "
SELECT pg_drop_replication_slot('replication_slot_slave');
"
Rollback du Master
En cas de problème après modification du master :
# Restaurer la configuration d'origine
oc apply -f backup-postgresql-dc.yaml
# Surveiller le rollout
oc rollout status dc/postgresql
# Vérifier l'état
oc get pods -l name=postgresql
⚠️ Attention : Les ConfigMaps créées resteront présentes mais ne seront plus utilisées.