TL;DR : Un cluster repmgr gère le basculement automatique, mais les applications doivent toujours savoir quel nœud est le primaire actuel.
Keepalived résout ce problème avec une adresse IP virtuelle (VIP) flottante qui se déplace automatiquement vers le nœud qui détient le rôle principal.
Ce guide ajoute un VIP à un cluster PostgreSQL 18 + repmgr existant sur Ubuntu 24.04 à l'aide de Keepalived 2.x.
Chaque étape a été exécutée en direct sur un cluster réel et la sortie a été vérifiée.
Votre cluster repmgr bascule en 60 secondes.
Votre application pointe toujours vers l'IP de l'ancien primaire.
Une adresse VIP flottante résout ce problème : une adresse stable qui se connecte toujours au primaire actuel, quel que soit le nœud physique concerné.
Keepalived implémente ceci en utilisant VRRP — un protocole standard conçu précisément à cet effet.
Ce guide ajoute un VIP à un cluster PostgreSQL + repmgr fonctionnel à deux nœuds.
Si vous n'avez pas encore ce cluster, suivez le Guide d'installation de repmgr d'abord, puis reviens ici.
Table des matières
Comment ça marche
Keepalived exécute un script de vérification de l'état sur chaque nœud toutes les 2 secondes.
Le script se connecte à l'instance PostgreSQL locale via une socket Unix et interroge pg_is_in_recovery().
Si le nœud est le principal (la fonction retourne f), le script se termine avec 0 — Keepalived conserve ou revendique la VIP.
Si le nœud est en mode veille ou si PostgreSQL est inaccessible (la fonction renvoie t ou la connexion échoue), le script se termine avec 1 — Keepalived libère la VIP.
Le nœud avec la priorité effective la plus élevée détient la VIP.
Server1 a une priorité de base de 100, server2 a une priorité de base de 90.
Le script de vérification de l'état de santé est configuré avec un poids de -50.
Lorsqu'un script d'un nœud échoue, sa priorité effective diminue de 50 : server1 passe de 100 à 50, server2 de 90 à 40.
Le nœud primaire gagne toujours — son script réussit et sa priorité effective reste à sa valeur de base.
L'environnement
Prérequis : Un cluster PostgreSQL 18 + repmgr fonctionnel à deux nœuds.
| Hôte | CI | Rôle |
|---|---|---|
| serveur1 (Ubuntu 24.04) | 192.168.0.181 | Nœud PostgreSQL |
| serveur2 (Ubuntu 24.04) | 192.168.0.182 | Nœud PostgreSQL |
| VIP | 192.168.0.180 | Flottant vers le principal actuel |
Étape 1 — Installer Keepalived sur les deux serveurs
Sur le serveur1 :
# On server1
sudo apt update
sudo apt install -y keepalived
keepalived --version
# Expected: Keepalived v2.x.x
Sur le serveur2 :
# On server2
sudo apt update
sudo apt install -y keepalived
keepalived --version
Étape 2 — Créer le script de vérification de l'état sur les deux serveurs
Le script se connecte à l'instance PostgreSQL locale via une socket Unix et vérifie si le nœud est le primaire.
Il retourne 0 sur le maître, 1 sur un secondaire ou si PostgreSQL est injoignable.
Un piège est à considérer ici : Keepalived exécute ce script en tant que PostgreSQL Utilisateur de l'OS, configuré via script_utilisateur postgres postgres en global_defs.
Parce que le script s'exécute déjà en tant que postgres, appelez psql directement — n'utilisez pas exécutez luser ou sudo -u postgres.
exécutez luser nécessite l'accès root et échouera silencieusement lorsqu'il sera appelé par un utilisateur non root, ce qui entraînera toujours la sortie du script avec 1 sur les deux nœuds et le comportement incorrect de la VIP.
Sur le serveur1 :
# On server1
sudo tee /usr/local/bin/check_postgres_primary.sh > /dev/null << 'EOF'
#!/bin/bash
result=$(psql -t -c "SELECT pg_is_in_recovery();" 2>/dev/null | tr -d '[:space:]')
[ "$result" = "f" ]
EOF
# The script must be executable — Keepalived will not run it otherwise
sudo chmod +x /usr/local/bin/check_postgres_primary.sh
Testez le script manuellement en tant qu'utilisateur postgres :
# On server1
sudo -u postgres /usr/local/bin/check_postgres_primary.sh
echo $?
# Expected: 0 if server1 is currently the primary, 1 if it is a standby
# Always test as postgres — running as root will give a different result
Sur le serveur2 :
# On server2
sudo tee /usr/local/bin/check_postgres_primary.sh > /dev/null << 'EOF'
#!/bin/bash
result=$(psql -t -c "SELECT pg_is_in_recovery();" 2>/dev/null | tr -d '[:space:]')
[ "$result" = "f" ]
EOF
sudo chmod +x /usr/local/bin/check_postgres_primary.sh
sudo -u postgres /usr/local/bin/check_postgres_primary.sh
echo $?
# Expected: 1 — server2 is currently a standby
Étape 3 — Configurer Keepalived sur les deux serveurs
Sauvegardez la configuration par défaut sur les deux serveurs avant d'écraser :
sudo cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.20260519 2>/dev/null || true
configuration server1 (priorité 100)
# On server1
sudo tee /etc/keepalived/keepalived.conf > /dev/null << 'EOF'
global_defs {
# Run health check scripts as the postgres OS user
# This allows the script to connect via Unix socket using peer authentication
script_user postgres postgres
enable_script_security
}
vrrp_script check_postgres {
script "/usr/local/bin/check_postgres_primary.sh"
# Run the check every 2 seconds
interval 2
# If the script fails, subtract 50 from this node's effective priority
# server1 base priority is 100 — on failure it drops to 50, losing to server2 (base 90)
weight -50
# Number of consecutive failures before declaring the script failed
fall 2
# Number of consecutive successes before declaring the script recovered
rise 2
}
vrrp_instance VI_POSTGRES {
state BACKUP
interface enp0s3
virtual_router_id 51
# Base priority — must differ between nodes; server1 is preferred primary candidate
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass pg_vip_2026
}
virtual_ipaddress {
192.168.0.180/24
}
track_script {
check_postgres
}
}
EOF
configuration du serveur2 (priorité 90)
# On server2
sudo tee /etc/keepalived/keepalived.conf > /dev/null << 'EOF'
global_defs {
script_user postgres postgres
enable_script_security
}
vrrp_script check_postgres {
script "/usr/local/bin/check_postgres_primary.sh"
interval 2
# server2 base priority is 90 — on failure it drops to 40
weight -50
fall 2
rise 2
}
vrrp_instance VI_POSTGRES {
state BACKUP
interface enp0s3
virtual_router_id 51
# Lower base priority than server1 — server1 holds the VIP when both are healthy
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass pg_vip_2026
}
virtual_ipaddress {
192.168.0.180/24
}
track_script {
check_postgres
}
}
EOF
Les deux nœuds utilisent état SAUVEGARDE.
Keepalived élit le maître dynamiquement en fonction de la priorité effective — il n'est pas nécessaire d'en définir un dans un nœud état MAÎTRE.
Étape 4 — Démarrer Keepalived et vérifier la VIP
Sur le serveur1 :
# On server1
sudo systemctl enable keepalived
sudo systemctl start keepalived
sudo systemctl status keepalived
# Expected: active (running)
# If failed: sudo journalctl -u keepalived -n 30
Sur le serveur2 :
# On server2
sudo systemctl enable keepalived
sudo systemctl start keepalived
sudo systemctl status keepalived
# Expected: active (running)
Laissez 5 à 10 secondes après le démarrage pour que les vérifications d'intégrité se stabilisent, puis vérifiez que le VIP est sur le principal actuel.
Sur le serveur1 :
# On server1
ip addr show enp0s3 | grep 192.168.0.180
# Expected: inet 192.168.0.180/24 — VIP is present if server1 is the current primary
# If not present and server1 IS the primary: wait 10 seconds and retry
Sur le serveur2 :
# On server2
ip addr show enp0s3 | grep 192.168.0.180
# Expected: no output — server2 is standby and does not hold the VIP
Ajouter le VIP à .pgpass sur les deux serveurs afin que repmgr puisse s'y connecter sans invite de mot de passe :
# On server1
sudo -u postgres bash -c 'echo "192.168.0.180:5432:repmgr:repmgr:repmgr" >> /var/lib/postgresql/.pgpass'
sudo -u postgres bash -c 'echo "192.168.0.180:5432:replication:repmgr:repmgr" >> /var/lib/postgresql/.pgpass'
# On server2
sudo -u postgres bash -c 'echo "192.168.0.180:5432:repmgr:repmgr:repmgr" >> /var/lib/postgresql/.pgpass'
sudo -u postgres bash -c 'echo "192.168.0.180:5432:replication:repmgr:repmgr" >> /var/lib/postgresql/.pgpass'
Vérifiez que le VIP est joignable et se connecte au primaire :
# On server1 or server2
ping -c 3 192.168.0.180
# Expected: replies from 192.168.0.180
# Connect to PostgreSQL via VIP — must run as postgres OS user to use .pgpass
sudo -u postgres psql -h 192.168.0.180 -U repmgr -d repmgr -c "SELECT pg_is_in_recovery(), inet_server_addr();"
# Expected: f (false) | 192.168.0.180 — connected to the primary through the VIP
Étape 5 — Tester le basculement VIP
Notez quel nœud détient actuellement le VIP :
# On server1
ip addr show enp0s3 | grep 192.168.0.180
# Record which node holds the VIP before triggering the failover
Arrêter PostgreSQL sur le primaire pour déclencher le basculement automatique :
# On server1
sudo systemctl stop postgresql
# repmgrd on server2 will detect this and promote server2 after ~60 seconds
Regardez Keepalived sur le serveur2 prendre en charge la VIP :
# On server2
sudo journalctl -u keepalived -f
# Expected sequence:
# Script check_postgres_primary.sh succeeded — server2 now primary after promotion
# VRRP_Instance(VI_POSTGRES) Entering MASTER STATE
Vérifiez que le VIP a bougé :
# On server2
ip addr show enp0s3 | grep 192.168.0.180
# Expected: inet 192.168.0.180/24 — VIP is now on server2
psql -h 192.168.0.180 -U repmgr -d repmgr -c "SELECT pg_is_in_recovery(), inet_server_addr();"
# Expected: f | 192.168.0.182 — VIP now connects to server2, which is the new primary
Étape 6 — Test de basculement VIP
Un basculement propre déplace également le VIP.
L'ancien primaire devient un secondaire — son script de vérification d'état échoue — le VIP bascule vers le nouveau primaire.
Avant d'exécuter un basculement, réintégrez le nœud défaillant du test précédent en tant que serveur de secours.
Sur la réplication (le nœud qui deviendra le nouveau primaire) :
# On server1 (assuming server1 is currently standby)
sudo -u postgres repmgr standby switchover
Lors du basculement, repmgr arrête l'ancien primaire via SSH mais ne le redémarre pas automatiquement.
Démarrez PostgreSQL manuellement sur le nœud déclassé lorsque le message de basculement indique “ en attente de la connexion du nœud X ” :
# On the demoted node (the old primary)
sudo systemctl start postgresql
Vérifiez que le VIP a bien été transféré vers le serveur 1 :
# On server1
ip addr show enp0s3 | grep 192.168.0.180
# Expected: inet 192.168.0.180/24 — VIP is back on server1
psql -h 192.168.0.180 -U repmgr -d repmgr -c "SELECT pg_is_in_recovery(), inet_server_addr();"
# Expected: f | 192.168.0.181 — VIP connects to server1, now the primary
Foire aux questions
Pourquoi le script de vérification de l'état utilise-t-il psql directement au lieu de sudo -u postgres psql ?
Keepalived exécute le script en tant qu'utilisateur postgres du système d'exploitation via script_utilisateur postgres postgres en global_defs.
Le script s'exécute déjà sous l'identité de postgres, donc appeler psql se connecte directement via un socket Unix en utilisant l'authentification par pair.
Utilisation exécutez luser ou sudo -u postgres à l'intérieur du script échouera silencieusement — les deux nécessitent les privilèges root, et le script ne s'exécute pas en tant que root.
Le résultat est que les deux nœuds se terminent toujours avec 1, et aucun ne détient correctement le VIP.
Pourquoi les deux nœuds utilisent-ils l'état BACKUP au lieu d'un utilisant l'état MASTER ?
Avec une vérification de santé basée sur le poids, le maître VRRP est déterminé dynamiquement par la priorité effective, et non par la priorité statique. état directive.
Si un nœud est configuré pour état MAÎTRE, il revendiquera le VIP au démarrage, quel que soit le résultat de la vérification de l'état, provoquant une condition de concurrence pendant les premières secondes.
Utilisation état SAUVEGARDE sur les deux nœuds permet au script de vérification de l'état de santé de déterminer dès le départ quel nœud doit héberger l'adresse VIP.
Combien de temps faut-il au VIP pour se déplacer après un basculement ?
Le VIP se déplace une fois que deux conditions sont remplies : repmgrd a promu le standby en primaire (environ 60 secondes avec les paramètres par défaut), et la vérification de santé de Keepalived a confirmé la promotion (jusqu'à l'automne 2 × intervalle 2 = 4 secondes).
Le temps total entre la défaillance primaire et le déplacement du VIP est d'environ 60 à 70 secondes avec la configuration décrite dans ce guide.
Le VIP bouge-t-il lors d'une bascule planifiée ?
Oui.
Quand Basculement vers le mode veille de repmgr dégrade l'ancien nœud principal ; le script de vérification de l'état de ce nœud commence alors à renvoyer la valeur 1 (car le nœud est désormais en mode de secours).
Keepalived détecte le changement dans l'automne 2 × intervalle 2 = 4 secondes et transfère le VIP vers le nouveau serveur principal.
VRPP est le protocole de redondance des routeurs. Il est utilisé pour assurer la redondance au niveau de la passerelle par défaut pour les hôtes d'un sous-réseau. L'objectif est d'empêcher un point de défaillance unique dans un réseau en cas de défaillance du routeur.
VRRP (Virtual Router Redundancy Protocol) est un protocole réseau standard (RFC 5798) conçu pour permettre l'attribution automatique de routeurs IP aux hôtes participants.
Keepalived met en œuvre VRRP pour gérer le VIP flottant — plusieurs nœuds participent à un groupe VRRP et élisent un maître en fonction de la priorité.
Le maître détient l'adresse VIP ; si le maître tombe en panne ou si sa priorité passe en dessous de celle d'un autre nœud, un nouveau maître est élu et l'adresse VIP est transférée.
En résumé
Keepalived permet d'ajouter un nœud VIP flottant à un cluster PostgreSQL + repmgr existant avec une configuration minimale.
Le script de vérification de l'état de santé est le composant critique : il doit s'exécuter en tant qu'utilisateur système postgres et appeler psql directement — et non par l'intermédiaire de exécutez luser ou sudo.
Avec l'automne 2 et intervalle 2, le VIP se met en place dans les 4 secondes suivant la détection du changement de rôle par Keepalived, qui se produit automatiquement après que repmgrd a promu le serveur de secours.
Si vous concevez une architecture de haute disponibilité PostgreSQL et que vous souhaitez un deuxième avis avant de passer en production, prendre contact →
