Déploiement d'un cluster postgresql hautement disponible avec Patroni
Patroni est un outil open source qui permet de créer et gérer un cluster PostgreSQL hautement disponible. Il peut être utilisé pour gérer des tâches telles que la réplication, les sauvegardes et les restaurations. En utilisant une configuration HAProxy, Patroni offre un point d'accès unique pour se connecter au serveur primaire du cluster, indépendamment de l'emplacement de la base de données primaire.
Si vous avez besoin de déployer rapidement un cluster PostgreSQL hautement disponible dans votre data centre, n'hésitez pas à nous contacter pour obtenir de l'aide.
Pré-requis
Il est recommandé d'utiliser une machine virtuelle équipée d'Ubuntu avec au moins 8 GB de mémoire RAM, avec Docker et Docker Compose préalablement installés.
Dans cet article, nous allons configurer un cluster de haute disponibilité pour PostgreSQL en utilisant les binaires de PostgreSQL 12, PATRONI, HAProxy et un client PostgreSQL.
Pour docker, nous allons utiliser le sous-réseau 172.18.56.0/24. les adresses IP suivantes seront utilisées:
- postgres1: 172.18.56.41 => Services: PostgreSQL, patroni, etcd, pgbouncer
- postgres2: 172.18.56.42 => Services: PostgreSQL, patroni, etcd, pgbouncer
- postgres3: 172.18.56.43 => Services: PostgreSQL, patroni, etcd, pgbouncer
- haproxy1: 172.18.56.50 => Services: HAProxy
Création et configuration des conteneurs docker
1. Créer un répertoire de travail /app/postgres
mkdir -p /app/postgres
cd /app/postgres/
2. Créer un Dockerfile avec le contenu suivant
FROM ubuntu:20.04
LABEL maintainer="data-resilience"
LABEL version="1"
LABEL description="Image docker pour postgresql 12"
ARG DEBIAN_FRONTEND=noninteractive
RUN apt update
RUN apt install -y vim wget ca-certificates curl gnupg lsb-release dnsutils systemd systemctl
RUN apt clean
3. Construire l'image docker postgres12-img
docker build -t postgres12-img .
4. Vérifier que l'image a bien été créée
docker images
5. Lancer un conteneur à partir de notre image Docker
docker run -tid --name postgres12-server postgres12-img
6. Se connecter au conteneur postgres12-server
docker exec -ti postgres12-server sh
7. Ajouter le dépôt de PostgreSQL
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg
sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" >> /etc/apt/sources.list.d/pgdg.list'
apt update
8. Installer postgreSQL 12
apt -y install postgresql-12
ln -s /usr/lib/postgresql/12/bin/* /usr/sbin/
rm -rf /var/lib/postgresql/12/main/*
9. Installer etcd
apt install -y etcd
10. Installer patroni
apt -y install python3 python3-pip python3-dev libpq-dev python3-etcd
ln -s /usr/bin/python3 /usr/bin/python
pip3 install launchpadlib --upgrade setuptools psycopg2
apt install -y patroni
11. Installer pgbouncer
apt install -y pgbouncer
12. Ajouter les variables d'environnement de Patroni
echo 'PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
export PGDATA="/var/lib/postgresql/12/main"
export ETCDCTL_API="3"
export PATRONI_ETCD_URL="http://127.0.0.1:2379"
export PATRONI_SCOPE="pg_cluster"
postgres1=172.18.56.41
postgres2=172.18.56.42
postgres3=172.18.56.43
ENDPOINTS=$postgres1:2379,$postgres2:2379,$postgres3:2379
' > /etc/environment
13. Configurer la résolution des noms des machines
cat >> /etc/hosts << 'EOF'
172.18.56.41 postgres1
172.18.56.42 postgres2
172.18.56.43 postgres3
EOF
14. Créer une nouvelle image Docker
docker commit postgres12-server postgres12-img
15. Supprimer le conteneur postgres12-server
docker rm -f postgres12-server
16. Créer un fichier docker-compose.yml
version: '3.5'
services:
postgres1:
tty: true
hostname: postgres1
container_name: postgres1
image: postgres12-img
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
- type: volume
source: pg_data1
target: /var/lib/postgresql/data
networks:
dbNetwork:
ipv4_address: 172.18.56.41
ports:
- '5432:5432'
postgres2:
tty: true
hostname: postgres2
container_name: postgres2
image: postgres12-img
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
- type: volume
source: pg_data2
target: /var/lib/postgresql/data
networks:
dbNetwork:
ipv4_address: 172.18.56.42
ports:
- '5433:5432'
postgres3:
tty: true
hostname: postgres3
container_name: postgres3
image: postgres12-img
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
- type: volume
source: pg_data3
target: /var/lib/postgresql/data
networks:
dbNetwork:
ipv4_address: 172.18.56.43
ports:
- '5434:5432'
networks:
dbNetwork:
name: dbNetwork
driver: bridge
ipam:
config:
- subnet: 172.18.56.0/24
volumes:
pg_data1:
pg_data2:
pg_data3:
17. Lancer docker-compose
docker-compose up -d
18. Vérifier que les 3 nœuds sont en cours d'exécution
docker-compose ps
Configuration du service etcd
Etcd est un magasin de clés-valeurs distribué qui fournit un moyen fiable de stocker les données qui doivent être accessibles par un système distribué ou un groupe de machines. Dans notre cas, il va servir à stocker les données de configuration du cluster patroni. La configuration d'etcd est gérée dans le fichier /etc/default/etcd.
19. Configuration etcd pour postgres1
docker exec -ti postgres1 sh -c "cat > /etc/default/etcd << 'EOF'
ETCD_NAME=postgres1
ETCD_DATA_DIR=\"/var/lib/etcd/postgres1\"
ETCD_LISTEN_CLIENT_URLS=\"http://0.0.0.0:2379\"
ETCD_INITIAL_ADVERTISE_PEER_URLS=\"http://172.18.56.41:2380\"
ETCD_INITIAL_CLUSTER=\"postgres1=http://172.18.56.41:2380,postgres2=http://172.18.56.42:2380,postgres3=http://172.18.56.43:2380\"
ETCD_INITIAL_CLUSTER_STATE=\"new\"
ETCD_INITIAL_CLUSTER_TOKEN=\"etcd-cluster\"
ETCD_ADVERTISE_CLIENT_URLS=\"http://0.0.0.0:2379\"
ETCD_ENABLE_V2=\"true\"
ETCD_LISTEN_PEER_URLS=\"http://0.0.0.0:2380\"
EOF"
20. Configuration etcd pour postgres2
docker exec -ti postgres2 sh -c "cat > /etc/default/etcd << 'EOF'
ETCD_NAME=postgres2
ETCD_DATA_DIR=\"/var/lib/etcd/postgres2\"
ETCD_LISTEN_CLIENT_URLS=\"http://0.0.0.0:2379\"
ETCD_INITIAL_ADVERTISE_PEER_URLS=\"http://172.18.56.42:2380\"
ETCD_INITIAL_CLUSTER=\"postgres1=http://172.18.56.41:2380,postgres2=http://172.18.56.42:2380,postgres3=http://172.18.56.43:2380\"
ETCD_INITIAL_CLUSTER_STATE=\"new\"
ETCD_INITIAL_CLUSTER_TOKEN=\"etcd-cluster\"
ETCD_ADVERTISE_CLIENT_URLS=\"http://0.0.0.0:2379\"
ETCD_ENABLE_V2=\"true\"
ETCD_LISTEN_PEER_URLS=\"http://0.0.0.0:2380\"
EOF"
21. Configuration etcd pour postgres3
docker exec -ti postgres3 sh -c "cat > /etc/default/etcd << 'EOF'
ETCD_NAME=postgres3
ETCD_DATA_DIR=\"/var/lib/etcd/postgres3\"
ETCD_LISTEN_CLIENT_URLS=\"http://0.0.0.0:2379\"
ETCD_INITIAL_ADVERTISE_PEER_URLS=\"http://172.18.56.43:2380\"
ETCD_INITIAL_CLUSTER=\"postgres1=http://172.18.56.41:2380,postgres2=http://172.18.56.42:2380,postgres3=http://172.18.56.43:2380\"
ETCD_INITIAL_CLUSTER_STATE=\"new\"
ETCD_INITIAL_CLUSTER_TOKEN=\"etcd-cluster\"
ETCD_ADVERTISE_CLIENT_URLS=\"http://0.0.0.0:2379\"
ETCD_ENABLE_V2=\"true\"
ETCD_LISTEN_PEER_URLS=\"http://0.0.0.0:2380\"
EOF"
22. Démarrer le service etcd sur les 3 serveurs
docker exec -ti postgres1 sh -c "service etcd start"
docker exec -ti postgres2 sh -c "service etcd start"
docker exec -ti postgres3 sh -c "service etcd start"
23. Vérifier l'état du cluster
docker exec -ti postgres1 etcdctl cluster-health
24. Lister les membres du cluster
docker exec -ti postgres1 etcdctl member list
docker exec -it postgres1 bash -c 'source /etc/environment ; etcdctl endpoint status --write-out=table --endpoints=$ENDPOINTS'
Configuration du service patroni
25. Configuration patroni pour postgres1
docker exec -ti postgres1 sh -c "cat > /etc/patroni/postgres.yml << 'EOF'
scope: pg_cluster
namespace: /service/
name: postgres1
restapi:
listen: postgres1:8008
connect_address: postgres1:8008
etcd:
hosts: postgres1:2379,postgres2:2379,postgres3:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
initdb:
- encoding: UTF8
- data-checksums
pg_hba:
- host replication replicator 127.0.0.1/32 md5
- host replication replicator 0.0.0.0/0 md5
- host all all 0.0.0.0/0 md5
users:
admin:
password: admin
options:
- createrole
- createdb
postgresql:
listen: postgres1:5432
connect_address: postgres1:5432
proxy_address: postgres1:6432
data_dir: /var/lib/postgresql/12/main
bin_dir: /usr/lib/postgresql/12/bin
pgpass: /tmp/pgpass
authentication:
replication:
username: replicator
password: replicator
superuser:
username: postgres
password: postgres
rewind:
username: rewind
password: rewind
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
EOF"
26. Configuration patroni pour postgres2
docker exec -ti postgres2 sh -c "cat > /etc/patroni/postgres.yml << 'EOF'
scope: pg_cluster
namespace: /service/
name: postgres2
restapi:
listen: postgres2:8008
connect_address: postgres2:8008
etcd:
hosts: postgres1:2379,postgres2:2379,postgres3:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
initdb:
- encoding: UTF8
- data-checksums
pg_hba:
- host replication replicator 127.0.0.1/32 md5
- host replication replicator 0.0.0.0/0 md5
- host all all 0.0.0.0/0 md5
users:
admin:
password: admin
options:
- createrole
- createdb
postgresql:
listen: postgres2:5432
connect_address: postgres2:5432
proxy_address: postgres2:6432
data_dir: /var/lib/postgresql/12/main
bin_dir: /usr/lib/postgresql/12/bin
pgpass: /tmp/pgpass
authentication:
replication:
username: replicator
password: replicator
superuser:
username: postgres
password: postgres
rewind:
username: rewind
password: rewind
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
EOF"
27. Configuration patroni pour postgres3
docker exec -ti postgres3 sh -c "cat > /etc/patroni/postgres.yml << 'EOF'
scope: pg_cluster
namespace: /service/
name: postgres3
restapi:
listen: postgres3:8008
connect_address: postgres3:8008
etcd:
hosts: postgres1:2379,postgres2:2379,postgres3:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
initdb:
- encoding: UTF8
- data-checksums
pg_hba:
- host replication replicator 127.0.0.1/32 md5
- host replication replicator 0.0.0.0/0 md5
- host all all 0.0.0.0/0 md5
users:
admin:
password: admin
options:
- createrole
- createdb
postgresql:
listen: postgres3:5432
connect_address: postgres3:5432
proxy_address: postgres3:6432
data_dir: /var/lib/postgresql/12/main
bin_dir: /usr/lib/postgresql/12/bin
pgpass: /tmp/pgpass
authentication:
replication:
username: replicator
password: replicator
superuser:
username: postgres
password: postgres
rewind:
username: rewind
password: rewind
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
EOF"
28. Démarrer le service patroni sur postgres1
docker exec -ti postgres1 sh -c "service patroni start"
29. Vérifier l'état du service patroni
docker exec -ti postgres1 sh -c "service patroni status"
30. Consulter les logs patroni pour postgres1
docker exec -ti postgres1 sh -c "tail -f /var/log/patroni.log"
31. Démarrer patroni sur postgres2 et postgres3
docker exec -ti postgres2 sh -c "service patroni start"
docker exec -ti postgres3 sh -c "service patroni start"
32. Consulter les logs patroni pour postgres2
docker exec -ti postgres2 sh -c "tail -f /var/log/patroni.log"
33. Consulter les logs patroni pour postgres3
docker exec -ti postgres3 sh -c "tail -f /var/log/patroni.log"
34. Lister les membres du cluster patroni
docker exec -it postgres1 bash -c 'source /etc/environment ; patronictl list'
Configuration pgbouncer
Pgbouncer est un logiciel open-source qui agit comme un proxy de base de données pour PostgreSQL. Il permet de réduire le nombre de connexions physiques à la base de données en utilisant un pool de connexions. Cela permet d'améliorer les performances et de réduire la charge sur la base de données en utilisant moins de ressources système. Il est également utilisé pour la sécurité et aussi il agit comme répartiteur de charge (load balancer).
35. Configuration pgbouncer pour postgres1
docker exec -ti postgres1 sh -c "echo '* = host=postgres1 port=5432 dbname=postgres' >> /etc/pgbouncer/pgbouncer.ini"
36. Configuration pgbouncer pour postgres2
docker exec -ti postgres2 sh -c "echo '* = host=postgres2 port=5432 dbname=postgres' >> /etc/pgbouncer/pgbouncer.ini"
37. Configuration pgbouncer pour postgres3
docker exec -ti postgres3 sh -c "echo '* = host=postgres3 port=5432 dbname=postgres' >> /etc/pgbouncer/pgbouncer.ini"
38. Modifier listen_addr sur les 3 serveurs
# Sur les 3 serveurs, modifier listen_addr = localhost par listen_addr = *
docker exec -ti postgres1 sh -c "sed -i 's/#listen_addr = localhost/listen_addr = */' /etc/pgbouncer/pgbouncer.ini"
docker exec -ti postgres2 sh -c "sed -i 's/#listen_addr = localhost/listen_addr = */' /etc/pgbouncer/pgbouncer.ini"
docker exec -ti postgres3 sh -c "sed -i 's/#listen_addr = localhost/listen_addr = */' /etc/pgbouncer/pgbouncer.ini"
39. Ajouter les paramètres d'authentification sur les 3 serveurs
docker exec -ti postgres1 sh -c "sed -i '/auth_file = \/etc\/pgbouncer\/userlist.txt/a auth_user = pgbouncer\nauth_query = SELECT p_user, p_password FROM public.lookup(\$1)' /etc/pgbouncer/pgbouncer.ini"
docker exec -ti postgres2 sh -c "sed -i '/auth_file = \/etc\/pgbouncer\/userlist.txt/a auth_user = pgbouncer\nauth_query = SELECT p_user, p_password FROM public.lookup(\$1)' /etc/pgbouncer/pgbouncer.ini"
docker exec -ti postgres3 sh -c "sed -i '/auth_file = \/etc\/pgbouncer\/userlist.txt/a auth_user = pgbouncer\nauth_query = SELECT p_user, p_password FROM public.lookup(\$1)' /etc/pgbouncer/pgbouncer.ini"
40. Se connecter au serveur PostgreSQL primaire (postgres1)
docker exec -ti postgres1 bash -c "psql -h postgres1 -p 5432 -U postgres"
41. Créer le rôle pgbouncer
CREATE ROLE pgbouncer with LOGIN encrypted password 'pgbouncer';
42. Créer la fonction lookup
CREATE FUNCTION public.lookup (
INOUT p_user name,
OUT p_password text
) RETURNS record
LANGUAGE sql SECURITY DEFINER SET search_path = pg_catalog AS
$$SELECT usename, passwd FROM pg_shadow WHERE usename = p_user$$;
43. Récupérer le mot de passe crypté du rôle pgbouncer
select * from pg_shadow;
44. Configurer userlist.txt
docker exec -ti postgres1 bash -c "echo '\"pgbouncer\" \"md5be5544d3807b54dd0637f2439ecb03b9\"' > /etc/pgbouncer/userlist.txt"
docker exec -ti postgres2 bash -c "echo '\"pgbouncer\" \"md5be5544d3807b54dd0637f2439ecb03b9\"' > /etc/pgbouncer/userlist.txt"
docker exec -ti postgres3 bash -c "echo '\"pgbouncer\" \"md5be5544d3807b54dd0637f2439ecb03b9\"' > /etc/pgbouncer/userlist.txt"
45. Démarrer pgbouncer sur les 3 serveurs
docker exec -it postgres1 bash -c "service pgbouncer start"
docker exec -it postgres2 bash -c "service pgbouncer start"
docker exec -it postgres3 bash -c "service pgbouncer start"
46. Tester l'authentification avec pgbouncer
docker exec -ti postgres1 bash -c "psql -h postgres1 -p 6432 -U postgres"
Installation HAProxy
47. Ajouter haproxy dans docker-compose.yml
haproxy1:
tty: true
hostname: haproxy1
container_name: haproxy1
image: ubuntu:20.04
networks:
dbNetwork:
ipv4_address: 172.18.56.50
ports:
- '5000:5000'
- '5001:5001'
- '7000:7000'
48. Lancer le conteneur haproxy1
docker-compose up -d haproxy1
49. Installer HAProxy
docker exec -ti haproxy1 bash -c "apt update && apt install -y haproxy vim"
50. Configuration HAProxy
docker exec -ti haproxy1 sh -c "cat > /etc/haproxy/haproxy.cfg << 'EOF'
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
maxconn 100
daemon
defaults
mode tcp
log global
option tcplog
retries 3
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout check 10s
maxconn 100
listen stats
mode http
bind *:7000
stats enable
stats uri /
listen primary
bind *:5000
option httpchk OPTIONS /master
http-check expect status 200
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
server postgres1 172.18.56.41:6432 maxconn 100 check port 8008
server postgres2 172.18.56.42:6432 maxconn 100 check port 8008
server postgres3 172.18.56.43:6432 maxconn 100 check port 8008
listen replicas
bind *:5001
balance roundrobin
option httpchk OPTIONS /replica
http-check expect status 200
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
server postgres1 172.18.56.41:6432 maxconn 100 check port 8008
server postgres2 172.18.56.42:6432 maxconn 100 check port 8008
server postgres3 172.18.56.43:6432 maxconn 100 check port 8008
EOF"
51. Démarrer HAProxy
docker exec -ti haproxy1 sh -c "service haproxy start"
52. Vérifier le statut de HAProxy
docker exec -ti haproxy1 sh -c "service haproxy status"
53. Interface web HAProxy
Vous pouvez vérifier que le HAProxy est bien configuré en accédant à l'URL http://172.18.56.50:7000/
Installation du client PostgreSQL
54. Installer le client PostgreSQL sur l'hôte
apt install -y postgresql-client python3-psycopg2
55. Configurer les mots de passe
echo "localhost:5000:*:postgres:postgres" >> ~/.pgpass
echo "localhost:5001:*:postgres:postgres" >> ~/.pgpass
chmod 0600 ~/.pgpass
56. Tester les requêtes de lecture
psql -h localhost -p 5001 -U postgres -t -c "select inet_server_addr()"
57. Tester les requêtes d'écriture
psql -h localhost -p 5000 -U postgres -t -c "select inet_server_addr()"
Test PostgreSQL High Availability (HA) Cluster Replication
58. Créer les répertoires de données
docker exec -it postgres1 bash -c "mkdir -p /opt/data && chown -R postgres:postgres /opt/data"
docker exec -it postgres2 bash -c "mkdir -p /opt/data && chown -R postgres:postgres /opt/data"
docker exec -it postgres3 bash -c "mkdir -p /opt/data && chown -R postgres:postgres /opt/data"
59. Créer le tablespace
psql -h localhost -p 5000 -U postgres -c "CREATE TABLESPACE tbs_data OWNER postgres LOCATION '/opt/data'"
60. Créer la base de données
psql -h localhost -p 5000 -U postgres -c "create database dataresilience TABLESPACE tbs_data"
61. Créer le schéma test
psql -h localhost -p 5000 -U postgres -d dataresilience -c "create schema test"
62. Créer la table log
psql -h localhost -p 5000 -U postgres -d dataresilience -c "create table test.log(date timestamp, host_addr character varying(15), message character varying(30))"
63. Créer un utilisateur
psql -h localhost -p 5000 -U postgres -d dataresilience -c "create user rachid login password 'rachid'"
psql -h localhost -p 5000 -U postgres -d dataresilience -c "grant usage on schema test to rachid;"
psql -h localhost -p 5000 -U postgres -d dataresilience -c "grant insert, update, delete, select on test.log to rachid;"
64. Ajouter le compte dans .pgpass
echo "localhost:5000:*:rachid:rachid" >> ~/.pgpass
echo "localhost:5001:*:rachid:rachid" >> ~/.pgpass
65. Premier test - tous les serveurs up
psql -h localhost -p 5000 -U rachid -d dataresilience -c "INSERT INTO test.log (date, host_addr, message) VALUES (current_date, inet_server_addr(), 'tous les serveurs sont up')"
psql -h localhost -p 5001 -U rachid -d dataresilience -c "select date, host_addr as insert_from_host, message, inet_server_addr() as select_from_host from test.log, inet_server_addr();"
66. Deuxième test
psql -h localhost -p 5000 -U rachid -d dataresilience -c "INSERT INTO test.log (date, host_addr, message) VALUES (current_date, inet_server_addr(), 'tous les serveurs sont up')"
psql -h localhost -p 5001 -U rachid -d dataresilience -c "select date, host_addr as insert_from_host, message, inet_server_addr() as select_from_host from test.log, inet_server_addr();"
67. Test de failover - arrêt du nœud primaire
docker exec -ti postgres1 sh -c "service etcd stop"
docker exec -ti postgres1 sh -c "service etcd status"
docker exec -it postgres2 bash -c 'source /etc/environment ; patronictl list'
68. Test après failover
psql -h localhost -p 5000 -U rachid -d dataresilience -c "INSERT INTO test.log (date, host_addr, message) VALUES (current_date, inet_server_addr(), 'test après failover')"
psql -h localhost -p 5001 -U rachid -d dataresilience -c "select date, host_addr as insert_from_host, message, inet_server_addr() as select_from_host from test.log, inet_server_addr();"
Surveillance et maintenance
Commandes utiles pour le monitoring
État du cluster Patroni
docker exec -it postgres1 bash -c 'source /etc/environment ; patronictl list'
État d'etcd
docker exec -it postgres1 bash -c 'source /etc/environment ; etcdctl endpoint status --write-out=table --endpoints=$ENDPOINTS'
Logs des services
# Logs Patroni
docker exec -ti postgres1 tail -f /var/log/patroni.log
# Logs PostgreSQL
docker exec -ti postgres1 tail -f /var/log/postgresql/postgresql-12-main.log
Interface HAProxy
Accédez à http://localhost:7000/ pour monitorer l'état des serveurs backend.
Opérations de maintenance
Basculement manuel
# Basculer vers un nœud spécifique
docker exec -it postgres1 bash -c 'source /etc/environment ; patronictl switchover pg_cluster --master postgres1 --candidate postgres2'
Redémarrage d'un nœud
# Redémarrer un service sur un nœud
docker exec -ti postgres2 sh -c "service patroni restart"
Vérification de la réplication
# Vérifier le lag de réplication
docker exec -it postgres1 bash -c 'source /etc/environment ; patronictl list'
Gestion des services
# Arrêter tous les services
docker-compose down
# Redémarrer un conteneur spécifique
docker-compose restart postgres1
# Voir les logs d'un conteneur
docker-compose logs -f postgres1
Résolution de problèmes
Problèmes courants
Le cluster ne démarre pas
- Vérifier que etcd est démarré sur tous les nœuds
- Vérifier la connectivité réseau entre les nœuds
- Consulter les logs de patroni
docker exec -ti postgres1 tail -100 /var/log/patroni.log
Problème de réplication
# Vérifier le statut de la réplication
docker exec -ti postgres1 psql -U postgres -c "SELECT * FROM pg_stat_replication;"
Problème avec pgbouncer
# Vérifier la configuration pgbouncer
docker exec -ti postgres1 cat /etc/pgbouncer/pgbouncer.ini
# Redémarrer pgbouncer
docker exec -ti postgres1 service pgbouncer restart
Problème avec HAProxy
# Vérifier la configuration HAProxy
docker exec -ti haproxy1 cat /etc/haproxy/haproxy.cfg
# Tester la connectivité vers les backends
docker exec -ti haproxy1 curl -I http://172.18.56.41:8008/master
Sauvegarde et restauration
Sauvegarde avec pg_dump
# Sauvegarde complète de la base dataresilience
docker exec -ti postgres1 pg_dump -h postgres1 -U postgres -d dataresilience > backup_dataresilience.sql
Sauvegarde continue avec WAL-E (optionnel)
Pour une solution de sauvegarde plus robuste, vous pouvez intégrer WAL-E ou pgBackRest.
Optimisations et bonnes pratiques
Configuration PostgreSQL
Paramètres recommandés pour la réplication
-- Augmenter le nombre de connexions WAL sender
ALTER SYSTEM SET max_wal_senders = 10;
-- Configurer les archives WAL
ALTER SYSTEM SET archive_mode = 'on';
ALTER SYSTEM SET archive_command = 'cp %p /var/lib/postgresql/archives/%f';
-- Optimiser la réplication synchrone si nécessaire
ALTER SYSTEM SET synchronous_standby_names = 'postgres2,postgres3';
Monitoring des performances
-- Vérifier les statistiques de réplication
SELECT * FROM pg_stat_replication;
-- Monitorer les conflits de réplication
SELECT * FROM pg_stat_database_conflicts;
Configuration Patroni avancée
Configuration des callbacks
Vous pouvez ajouter des scripts de callback dans la configuration Patroni :
postgresql:
callbacks:
on_start: /scripts/on_start.sh
on_stop: /scripts/on_stop.sh
on_role_change: /scripts/on_role_change.sh
Configuration des tags avancés
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
priority: 100 # Priorité pour l'élection du leader
Sécurité
Chiffrement des communications
Pour un environnement de production, activez SSL :
postgresql:
parameters:
ssl: 'on'
ssl_cert_file: '/etc/ssl/certs/server.crt'
ssl_key_file: '/etc/ssl/private/server.key'
Authentification renforcée
postgresql:
pg_hba:
- hostssl replication replicator 0.0.0.0/0 md5
- hostssl all all 0.0.0.0/0 md5
Conclusion
Ce guide vous a permis de déployer un cluster PostgreSQL hautement disponible avec les composants suivants :
- 3 nœuds PostgreSQL avec réplication automatique
- Patroni pour la gestion automatique du failover
- etcd pour la coordination du cluster
- pgbouncer pour l'optimisation des connexions
- HAProxy pour la répartition de charge et la haute disponibilité
Avantages de cette architecture
- Haute disponibilité : Failover automatique en cas de panne
- Répartition de charge : Les lectures sont distribuées sur les répliques
- Monitoring intégré : Interface web HAProxy et outils de monitoring
- Scalabilité : Possibilité d'ajouter facilement de nouveaux nœuds
- Maintenance sans interruption : Basculement manuel pour les mises à jour
Points de vigilance
- Réseau : Assurez-vous d'une connectivité stable entre les nœuds
- Stockage : Utilisez un stockage performant et fiable
- Monitoring : Surveillez régulièrement les métriques de performance
- Sauvegardes : Implémentez une stratégie de sauvegarde robuste
- Sécurité : Chiffrez les communications et sécurisez les accès
Cette architecture est prête pour un environnement de production et peut être adaptée selon vos besoins spécifiques en termes de performance, sécurité et disponibilité.
Ressources supplémentaires
- Documentation officielle Patroni
- Documentation PostgreSQL High Availability
- Guide HAProxy
- Documentation etcd
Cet article fait partie d'une série sur la gestion des bases de données haute disponibilité. N'hésitez pas à nous contacter pour des conseils personnalisés sur votre architecture.