Deploiement#
Corosync / Pacemaker / PAF (pgsqlms) — réplication streaming native, sans DRBD.
Runbook validé sur Pacemaker 4.0 (pcs récent) et PostgreSQL 18.
Topologie de référence#
Nœud |
IP |
RĂ´le initial |
|---|---|---|
pg-01 |
192.168.14.161 |
primaire (amorçage) |
pg-02 |
192.168.14.162 |
standby |
pg-03 |
192.168.14.163 |
standby |
VIP |
192.168.14.160 |
suit le primaire |
PGDATA=/var/lib/pgsql/18/databindir=/usr/pgsql-18/binutilisateur de réplication :
replicator
Règle d’or apprise à la dure : le primary_conninfo de chaque nœud pointe la VIP (192.168.14.160), jamais l’IP d’un nœud. Un standby suit « le primaire », pas « tel serveur ».
0. Prérequis (les 3 nœuds)#
# Résolution de noms cohérente
cat >> /etc/hosts <<'EOF'
192.168.14.161 pg-01
192.168.14.162 pg-02
192.168.14.163 pg-03
EOF
# Horloge synchronisée — critique pour Corosync
systemctl enable --now chronyd
A toi de preparer la conf firewall en adequation avec ton infra.
1. Installer PostgreSQL 18 et de la stack HA (les 3 nœuds)#
dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-10-x86_64/pgdg-redhat-repo-latest.noarch.rpm
dnf -qy module disable postgresql
dnf install -y postgresql18 postgresql18-server postgresql18-contrib
# Dépôt HighAvailability
dnf install -y rocky-release-ha
dnf config-manager --set-enabled highavailability
# Stack + agents de fencing
dnf install -y pcs pacemaker corosync fence-agents-all
# PAF (resource agent pgsqlms)
dnf install -y resource-agents-paf
# vérifier :
dnf provides '*/pgsqlms'
ls /usr/lib/ocf/resource.d/heartbeat/pgsqlms
# Mot de passe hacluster (identique sur les 3)
echo "hacluster:motdepassehacluster" | chpasswd
systemctl enable --now pcsd
2. Initialiser le primaire (pg-01)#
/usr/pgsql-18/bin/postgresql-18-setup initdb
listen_addresses = '*'
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
hot_standby = on
hot_standby_feedback = on
wal_log_hints = on
host replication replicator 192.168.14.161/32 scram-sha-256
host replication replicator 192.168.14.162/32 scram-sha-256
host replication replicator 192.168.14.163/32 scram-sha-256
host all all 192.168.14.0/24 scram-sha-256
Créer le rôle de réplication :
sudo -u postgres /usr/pgsql-18/bin/pg_ctl -D /var/lib/pgsql/18/data start
sudo -u postgres psql -c "CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'motdepasse';"
Attention
PAS de `recovery_template` / fichier `pgsqlms.conf`. PAF l’interdit en PG 12+ (Recovery template file … is forbidden for PostgreSQL 12 and above). La config standby vit dans postgresql.auto.conf (standby.signal + primary_conninfo).
3. Bootstrap des standbys (pg-02 et pg-03)#
Sur chaque standby, basebackup depuis le primaire d’amorçage (pg-01, IP directe) :
# sur pg-02, puis pg-03
sudo -u postgres /usr/pgsql-18/bin/pg_basebackup \
-h 192.168.14.161 -U replicator \
-D /var/lib/pgsql/18/data \
-R -X stream -c fast -P
-R écrit standby.signal + primary_conninfo, -X stream récupère les WAL en
parallèle (évite le requested WAL segment has already been removed).
Corriger primary_conninfo → VIP + bon application_name (le -R met l’IP directe et pas d”application_name) :
# sur pg-02 (adapter application_name=pg-03 sur pg-03)
sudo -u postgres bash -c '
cd /var/lib/pgsql/18/data
sed -i "/^primary_conninfo/d" postgresql.auto.conf
cat >> postgresql.auto.conf <<EOF
primary_conninfo = '\''host=192.168.14.160 application_name=pg-02 user=replicator password=motdepasse'\''
EOF
'
Poser aussi le primary_conninfo sur pg-01 (utile Ă son futur passage en standby),
via ALTER SYSTEM — surtout PAS de standby.signal sur le primaire d’amorçage :
# sur pg-01
sudo -u postgres psql -c "ALTER SYSTEM SET primary_conninfo = 'host=192.168.14.160 application_name=pg-01 user=replicator password=motdepasse';"
4. Arret des PostgreSQL (les 3 nœuds)#
# les 3 nœuds
sudo -u postgres /usr/pgsql-18/bin/pg_ctl -D /var/lib/pgsql/18/data stop -m fast
systemctl disable --now postgresql-18
systemctl mask postgresql-18.service
5. Former le cluster (pg-01)#
pcs host auth pg-01 pg-02 pg-03 -u hacluster -p motdepassehacluster
pcs cluster setup pgcluster pg-01 pg-02 pg-03 --transport knet
pcs cluster start --all
pcs cluster enable --all
pcs status # attendu : 3 nœuds Online, Quorate: Yes
Astuce
pcs cluster start –all démarre corosync + pacemaker seulement. PostgreSQL sera lancé par Pacemaker/PAF, pas par systemd (d’où le systemctl disable de l’étape 3).
6. Configurer les ressources (pg-01)#
pcs property set maintenance-mode=true
pcs property set stonith-enabled=false
pcs property set no-quorum-policy=stop
pcs resource defaults update resource-stickiness=10
Ressource PostgreSQL via PAF — sans `recovery_template`, avec `promoted-max=1` :
pcs resource create pgsqld ocf:heartbeat:pgsqlms \
bindir=/usr/pgsql-18/bin \
pgdata=/var/lib/pgsql/18/data \
pgport=5432 \
op start timeout=60s \
op stop timeout=60s \
op promote timeout=30s \
op demote timeout=120s \
op monitor interval=15s timeout=10s role="Promoted" \
op monitor interval=16s timeout=10s role="Unpromoted" \
op notify timeout=60s \
promotable notify=true promoted-max=1 promoted-node-max=1
Attention
promoted-max=1 est obligatoire sur Pacemaker 4.0, sinon PAF renvoie You must set meta parameter promoted_max=1 for your « promotable » resource. (Les warnings de dépréciation sur la syntaxe promotable … sont sans effet ; la forme future est promotable meta notify=true promoted-max=1 ….)
VIP + contraintes — sans `symmetric=false` (attribut retiré du schéma pacemaker-4.0) :
pcs resource create pgsql-vip ocf:heartbeat:IPaddr2 \
ip=192.168.14.160 cidr_netmask=24 \
op monitor interval=10s
pcs constraint colocation add pgsql-vip with Promoted pgsqld-clone INFINITY
pcs constraint order promote pgsqld-clone then start pgsql-vip kind=Mandatory
Astuce
Recréer la ressource pgsqld supprime les contraintes qui la référencent : il faut reposer colocation + order après chaque pcs resource delete/create pgsqld.
7. Amorçage du cluster (pg-01)#
On peut tenter de demarrer le cluster la commande est plutot simple, on sort pacemaker de maintenance et on vois ce qu’il ce passe.
pcs property set maintenance-mode=false
watch -n1 pcs status
État cible :
Clone Set: pgsqld-clone [pgsqld] (promotable):
Promoted: [ pg-01 ]
Unpromoted: [ pg-02 pg-03 ]
pgsql-vip (ocf:heartbeat:IPaddr2): Started pg-01
Au tout premier démarrage, les scores de promotion PAF peuvent valoir -1 partout : aucun nœud n’a jamais été primaire connu de PAF, donc personne n’est promu spontanément. Il faut présenter à PAF un état de réplication déjà sain (1 primaire + 2 standbys raccrochés) avant de lui rendre la main.
Vérifier que le score de pg-01 est devenu positif :
crm_simulate -sL 2>/dev/null | grep -i promotion
Si c’est bien ce probleme on peut suivre la procedure suivante:
# 1) pg-01 en primaire réel : PAS de standby.signal
# sur pg-01
sudo -u postgres rm -f /var/lib/pgsql/18/data/standby.signal
sudo -u postgres /usr/pgsql-18/bin/pg_ctl -D /var/lib/pgsql/18/data start
sudo -u postgres psql -c "SELECT pg_is_in_recovery();" # attendu : f
# 2) pg-02 et pg-03 en standby raccrochés à pg-01
# sur pg-02 puis pg-03
sudo -u postgres /usr/pgsql-18/bin/pg_ctl -D /var/lib/pgsql/18/data start
sudo -u postgres psql -c "SELECT pg_is_in_recovery();" # attendu : t
# 3) vérifier la réplication depuis pg-01
# sur pg-01
sudo -u postgres psql -c "SELECT application_name, state, sync_state FROM pg_stat_replication ORDER BY application_name;"
# attendu : pg-02 et pg-03 en streaming
# 4) tout arrêter — PAF va reprendre
# les 3 nœuds
sudo -u postgres /usr/pgsql-18/bin/pg_ctl -D /var/lib/pgsql/18/data stop -m fast
# 5) rendre la main Ă Pacemaker
pcs resource cleanup pgsqld
pcs property set maintenance-mode=false
watch -n1 pcs status
Astuce
Felicitation tu a maintenant un cluster postgresql-18 qui tiendra l’extinction d’un noeud.
Ă€ FAIRE avant la production#
STONITH est resté désactivé pendant tout le montage (stonith-enabled=false). Un nœud partant en primaire-fantôme pendant que Pacemaker promeut un autre = split-brain (rencontré pendant le debug). Le fencing l’empêche.
# exemple IPMI (adapter à l'infra : Proxmox → fence_virsh / agent API)
pcs stonith create fence-pg01 fence_ipmilan \
pcmk_host_list="pg-01" ip=<bmc-ip-pg01> \
username=<user> password=<pass> lanplus=1 \
op monitor interval=60s
# idem pg-02, pg-03
pcs property set stonith-enabled=true
pcs stonith status
Astuce
Slots de réplication : vérifier pg_replication_slots (protège du recyclage WAL) ; prévoir max_slot_wal_keep_size comme garde-fou contre la saturation disque si un standby reste mort longtemps.
pg_hba homogène sur les 3 nœuds (via Ansible configuration-management) : après bascule n’importe quel nœud devient primaire.
Test de failover documenté, à rejouer STONITH actif : pcs node standby <primaire> → promotion d’un standby + VIP déplacée → pcs node unstandby → l’ancien primaire revient en standby.