diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b00b956..d8e1192 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,26 +5,26 @@ ## I N C L U D E S ## -# How To Export artefacts to the private environment include: + # Export artefacts to the private environment - project: 'dalibo/gitlab-templates' file: 'artifacts_private_env.yml' + # Export artefacts to the public environment + - project: 'dalibo/gitlab-templates' + file: 'artifacts_public_env.yml' + ## ## V A R I A B L E S ## variables: - BRANCH_TARGET: ws14 + BRANCH_TARGET: patroni MASTER_TARGET: all # $ARTIFACTS is required by artefacts_private_env.yml ARTIFACTS: '_build/*' - # - THEMES_BRANCH: stable # usually 'stable' or 'master' - ## Limitation des pull docker - ## https://gitlab.dalibo.info/formation/manuels/-/issues/482 - ## Pointer temporairement vers un registre cache externe chez Gitlab (https://gitlab.com/dalibo/pandocker/container_registry/1505688) - CI_REGISTRY: registry.gitlab.com + # THEMES_BRANCH is usually 'stable' or 'master' + THEMES_BRANCH: master before_script: @@ -85,17 +85,11 @@ pandoc: expire_in: 1 day ## -## D E P L O Y +## D E P L O Y ## -## Export the master branch in a public location -public: - stage: deploy - script: - ## Install Deploy Key - - ssh-add <(echo "$CLOUD_DEPLOY_PRIVATE_KEY") - ## Push - - rsync -avp fr $CLOUD_DEPLOY_DEST - - rsync -avp en $CLOUD_DEPLOY_DEST - only: - - master@formation/workshops +# overiding the job template because we need to force GIT_STRATEGY +# for this pipeline in order to deploy `_archives` +public_env: + variables: + GIT_STRATEGY: fetch diff --git a/AUTHORS.md b/AUTHORS.md index cb5305f..57143c6 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -6,10 +6,14 @@ order: * Alexandre Anriot * Adrien Nayrat -* damien clochard +* Damien Clochard * Guillaume Lelarge * Thibaut Madelaine * Nicolas Gollet * Nicolas Thauvin * Stefan Fercot * Thomas Reiss +* Benoit Lobréau +* Christophe Courtois +* Thibaud Walkowiak +* Franck Boudehen diff --git a/README.md b/README.md index 1095ef0..9e76d09 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,21 @@ make ws14 Previous workshops generated files are versionned under `_archives_` folder with the same logic to preserve templates made in the past. +Refresh the github mirror +------------------------------------------------------------------------------- + +``` +git clone git@github.com:dalibo/workshops.git +cd workshops +git remote add upstream git@gitlab.dalibo.info:formation/workshops.git +git fetch upstream +git rebase upstream/master +git push --force-with-lease +``` + +> DO NOT use `git push --force` on the master branch. + + Contribute ------------------------------------------------------------------------------- diff --git a/fr/patroni/Makefile b/fr/patroni/Makefile new file mode 100644 index 0000000..eaf57e1 --- /dev/null +++ b/fr/patroni/Makefile @@ -0,0 +1,168 @@ +# +# Chemin vers les thèmes Dalibo. DLB est le chemin pour la command pandoc, +# HOST_DLB est le chemin pour le Makefile. +# +DLB?=$(HOME)/.dalibo/themes/ +HOST_DLB:=$(DLB) + +# +# Pandoc +# +P=pandoc + +# if pandoc is not installed, let's use pandocker +ifeq (, $(shell which $(P))) + DOCKER?=latest +endif + +ifneq ($(DOCKER),) + DLB=/root/dalibo/themes + P:=docker run --rm -it --privileged -e TEXMFHOME --volume $(CURDIR):/pandoc --volume $(HOST_DLB):$(DLB) dalibo/pandocker:$(DOCKER) +endif + +PANDOC_ARGS=--standalone +P+=--metadata=dlb:$(DLB) $(PANDOC_ARGS) + + +# +# Pandoc Flags +# +ifeq ("$(wildcard $(HOST_DLB))","") + # Default Compilation Flags + REVEAL_FLAGS=-V revealjs-url:http://lab.hakim.se/reveal-js/css/reveal.css/css/reveal.css + TEX_FLAGS= + BEAMER_FLAGS= + PDF_FLAGS= + ODT_FLAGS= + DOCX_FLAGS= + EPUB_FLAGS= +else + # Dalibo's Compilation Flags + REVEAL_LOCAL_FLAGS=-V revealjs-url="$(HOST_DLB)/reveal.js/" --template="$(DLB)/reveal.js/pandoc/templates/dalibo.revealjs" + REVEAL_FLAGS=-V revealjs-url="$(DLB)/reveal.js/" --template="$(DLB)/reveal.js/pandoc/templates/dalibo.revealjs" --self-contained + TEX_FLAGS=-V theme=Dalibo + export TEXMFHOME=$(DLB)/beamer + BEAMER_FLAGS=-V theme=Dalibo +ifneq (,$(wildcard $(HOST_DLB)/beamer/template.latex)) + BEAMER_FLAGS:=$(BEAMER_FLAGS) --template $(DLB)/beamer/template.latex +endif +ifneq (,$(wildcard $(HOST_DLB)/highlight/dalibo-dark.theme)) + $(info Utilisation du style Dalibo pour la coloration syntaxique) + BEAMER_FLAGS:=$(BEAMER_FLAGS) --highlight-style=$(DLB)/highlight/dalibo-dark.theme + REVEAL_FLAGS:=$(REVEAL_FLAGS) --highlight-style=$(DLB)/highlight/dalibo-dark.theme + REVEAL_LOCAL_FLAGS:=$(REVEAL_LOCAL_FLAGS) --highlight-style=$(DLB)/highlight/dalibo-dark.theme +endif + PDF_FLAGS=--template=$(DLB)/tex/audit/template.tex --pdf-engine-opt=-shell-escape + ODT_FLAGS=--reference-doc=$(DLB)/odt/template_conference.dokuwiki.odt + DOCX_FLAGS=--reference-doc=$(DLB)/doc/template_conference.dokuwiki.doc + EPUB_FLAGS= +endif + +## +## DECKTAPE +## +DECKTAPE?=docker run --rm -it --privileged -v $(CURDIR):/slides astefanutti/decktape + +## +## $(SRCS) is the list of all source files +## + +# Ignore documentation +EXCLUDES:= -and -not -name 'QUICKSTART.md' -and -not -name 'README.md' +# Ignore themes directories +EXCLUDES+= -and -not -path './themes/*' -and -not -path '*/reveal.js/*' +# Ignore directories and files that starts with a '_' +EXCLUDES+= -and -not -path '*/_*' + +# Search for all .md files +SRCS=$(shell find . -type f -name '*.md' $(EXCLUDES) ) + +## +## Objects files +## +REVEAL_OBJS=$(SRCS:.md=.html) +REVEAL_LOCAL_OBJS=$(SRCS:.md=.local.html) +REVEAL_PDF_OBJS=$(SRCS:.md=.reveal.pdf) +TEX_OBJS=$(SRCS:.md=.tex) +BEAMER_OBJS=$(SRCS:.md=.beamer.pdf) +BEAMER_NOTES_OBJS=$(SRCS:.md=.beamer.speaker.pdf) +PDF_OBJS=$(SRCS:.md=.pdf) +ODT_OBJS=$(SRCS:.md=.odt) +DOCX_OBJS=$(SRCS:.md=.docx) +EPUB_OBJS=$(SRCS:.md=.epub) + + +test: + @echo Présentations: $(SRCS) + @echo Thèmes dalibo: $(DLB) + @echo Commande pandoc: $(P) + @echo Options reveal: echo $(REVEAL_FLAGS) + +install: + ln -s $(HOME)/.dalibo/themes/ + +uninstall: + rm themes + +all: reveal reveal_local pdf epub odt + +reveal: $(REVEAL_OBJS) +reveal_local: $(REVEAL_LOCAL_OBJS) +tex: $(TEX_OBJS) +beamer: $(BEAMER_OBJS) +beamer_notes: $(BEAMER_NOTES_OBJS) +pdf: $(PDF_OBJS) +odt: $(ODT_OBJS) +docx: $(DOCX_OBJS) +epub: $(EPUB_OBJS) +reveal_pdf: $(REVEAL_PDF_OBJS) + + +%.all: %.html %.pdf %.odt %.epub + +%.local.html: %.md + $P -t revealjs $(REVEAL_LOCAL_FLAGS) --resource-path=.:$(dir $^) $^ -o $@ + +%.html: %.md + $P -t revealjs $(REVEAL_FLAGS) --resource-path=.:$(dir $^) $^ -o $@ + +%.tex: %.md + $P -t beamer $(TEX_FLAGS) --resource-path=.:$(dir $^) $^ -o $@ + +%.beamer.pdf: %.md + TEXMFHOME=$(DLB)/beamer $P -t beamer -V classoption=14pt -V classoption="aspectratio=169" $(BEAMER_FLAGS) --resource-path=.:$(dir $^) $^ -o $@ + +%.beamer.notes.pdf: %.md + $P -t beamer -V classoption=14pt -V "beameroption=show notes on second screen" $(BEAMER_FLAGS) --resource-path=.:$(dir $^) $^ -o $@ + +%.pdf: %.md + $P --pdf-engine=xelatex $(PDF_FLAGS) --resource-path=.:$(dir $^) $^ -o $@ + +%.odt: %.md + $P $(ODT_FLAGS) --resource-path=.:$(dir $^) $^ -o $@ + +%.docx: %.md + $P $(DOCX_FLAGS) --resource-path=.:$(dir $^) $^ -o $@ + +%.epub: %.md + $P $(EPUB_FLAGS) --resource-path=.:$(dir $^) $^ -o $@ + +%.reveal.pdf: %.html + $(DECKTAPE) --size 1920x1080 $^ $@ + +# Utiliser make watch-reveal_local pour regénérer les reveal.html à chaque +# changement des md. +watch-%: + echo $(SRCS) | entr -c make $* + +clean: + rm -fr $(REVEAL_OBJS) + rm -fr $(REVEAL_LOCAL_OBJS) + find . -name reveal.js | xargs -r rm -fr + rm -fr $(TEX_OBJS) + rm -fr $(BEAMER_OBJS) + rm -fr $(BEAMER_NOTES_OBJS) + rm -fr $(PDF_OBJS) + rm -fr $(ODT_OBJS) + rm -fr $(DOCX_OBJS) + rm -fr $(EPUB_OBJS) diff --git a/fr/patroni/_archives/pgs14/patroni.epub b/fr/patroni/_archives/pgs14/patroni.epub new file mode 100644 index 0000000..3225f2a Binary files /dev/null and b/fr/patroni/_archives/pgs14/patroni.epub differ diff --git a/fr/patroni/_archives/pgs14/patroni.handout.html b/fr/patroni/_archives/pgs14/patroni.handout.html new file mode 100644 index 0000000..84c2e21 --- /dev/null +++ b/fr/patroni/_archives/pgs14/patroni.handout.html @@ -0,0 +1,35947 @@ + + + + + + + Haute disponibilité de service - Patroni + + + + + + + + + + + + + Haute disponibilité de service - Patroni + + + + + + + + +
+ +
+
+

Haute disponibilité de +service - Patroni

+

Dalibo +& Contributors

+
+
+ +
+ + + +
+

Haute disponibilité +de service avec Patroni

+
+PostgreSQL + +
+
+ +
+
+

Introduction

+
+
    +
  • Principes
  • +
  • Mise en place
  • +
  • Installation et configuration des services
  • +
  • Construction d’un agrégat à bascule automatique
  • +
  • Création d’incidents
  • +
+
+
+ +
+
+

Principes

+
+
    +
  • Arbitrage par un quorum : DCS Etcd
  • +
  • Service PostgreSQL : désactivé
  • +
  • Contrôle complet par Patroni
  • +
+
+
+ +
+
+

DCS : Etcd

+
+
    +
  • Arbitre en cas de bascules
  • +
  • Stockage distribué de la configuration
  • +
  • Jeton leader (Etcd)
  • +
  • Instance primaire PostgreSQL
  • +
+
+
+

Pour arbitrer les bascules automatiques, confirmer le primaire +PostgreSQL ou distribuer la configuration, Patroni utilise un +DCS (distributed configuration system).

+

Pour ce rôle, nous utiliserons Etcd.

+
+
+

Service PostgreSQL et +Patroni

+
+
    +
  • Service PostgreSQL désactivé
  • +
+
+
+

Le service PostgreSQL doit être désactivé pour ne +pas se lancer au démarrage, le contrôle total de l’instance est délégué +à Patroni :

+
 $ for node in pg-1 pg-2 pg-3; do
+  sudo systemctl disable --now postgresql
+  sudo systemctl status postgresql
+done
+
Synchronizing state of postgresql.service with SysV service script with /lib/
+systemd/systemd-sysv-install.
+Executing: /lib/systemd/systemd-sysv-install disable postgresql
+· postgresql.service - PostgreSQL RDBMS
+   Loaded: loaded (/lib/systemd/system/postgresql.service; disabled; vendor 
+   preset: enabled)
+   Active: inactive (dead)
+Synchronizing state of postgresql.service with SysV service script with /lib/
+systemd/systemd-sysv-install.
+Executing: /lib/systemd/systemd-sysv-install disable postgresql
+· postgresql.service - PostgreSQL RDBMS
+   Loaded: loaded (/lib/systemd/system/postgresql.service; disabled; vendor 
+   preset: enabled)
+   Active: inactive (dead)
+Synchronizing state of postgresql.service with SysV service script with /lib/
+systemd/systemd-sysv-install.
+Executing: /lib/systemd/systemd-sysv-install disable postgresql
+· postgresql.service - PostgreSQL RDBMS
+   Loaded: loaded (/lib/systemd/system/postgresql.service; disabled; vendor 
+   preset: enabled)
+   Active: inactive (dead)
+
+
+

Mise en place de +l’infrastructure

+
+
    +
  • Connexion à la VM
  • +
  • Récupération du playbook Ansible
  • +
+
+
+

Vous disposez d’une machine virtuelle dédiée dans laquelle nous +construirons 7 conteneurs lxc :

+
    +
  • 3 Etcd
  • +
  • 3 Patroni
  • +
  • 1 backup optionnel : (sauvegardes, archivage)
  • +
+
+
+

Connexion à votre machine +virtuelle

+
+

un seul point d’entrée : eformation.dalibo.com un port +attribué : 22XX

+
  $ ssh -p 22XX dalibo@eformation.dalibo.com
+
+
+

Exemple de configuration pour une connexion simplifiée :

+

+# .ssh/config
+
+Host vm38
+Hostname eformation.dalibo.com
+User dalibo
+port 2238
+
+
 $ ssh vm38
+
Last login: Wed Nov 10 13:23:26 2021 from 78.213.160.12
+dalibo@vm38:~$ 
+
+
+

Playbook Ansible

+
+

Récupération du playbook Ansible à cette +adresse :

+

https://github.com/dalibo/workshops/tree/workshop_patroni/fr/patroni/playbook/etcd-patroni

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FichierDescription
inventory.ymlinventaire des machines
setup.ymlplaybook principal
warmup.shscript d’amorçage
exchange_ssh_keys.ymlplaybook d’échange de clés +ssh
teardown.ymlplaybook de destruction +massive
+
+
+

Quatre fichiers Yaml, un script shell :

+

Le script warmup.sh permet de précharger une image +debian pour accélérer la création des autres conteneurs :

+
 $ sudo ./warmup.sh
+
+
+
+

L’infrastructure complète peut être créée à l’aide des +commandes :

+
 $ sudo apt install -y ansible
+ $ sudo ansible-playbook -f 7 -i inventory.yml setup.yml
+...
+

Cette opération peut durer jusqu’à une vingtaine de minutes.

+
+
+

Vous pouvez suivre l’évolution de la création des conteneurs dans un +autre terminal :

+
 $ watch -n 1 sudo lxc-ls -f
+
 $ sudo lxc-ls -f
+ NAME   STATE   AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED 
+ backup STOPPED 0         -      -    -    false        
+ e1     STOPPED 0         -      -    -    false        
+ e2     STOPPED 0         -      -    -    false        
+ e3     STOPPED 0         -      -    -    false        
+ pg-1   STOPPED 0         -      -    -    false        
+ pg-2   STOPPED 0         -      -    -    false        
+ pg-3   STOPPED 0         -      -    -    false
+

L’état final de chaque conteneur étant RUNNING avec une +adresse IPV4 attribuée :

+
 $ sudo lxc-ls -f
+ NAME   STATE   AUTOSTART GROUPS IPV4       IPV6 UNPRIVILEGED
+ backup RUNNING 0         -      10.0.3.204 -    false
+ e1     RUNNING 0         -      10.0.3.101 -    false
+ e2     RUNNING 0         -      10.0.3.102 -    false
+ e3     RUNNING 0         -      10.0.3.103 -    false
+ pg-1   RUNNING 0         -      10.0.3.201 -    false
+ pg-2   RUNNING 0         -      10.0.3.202 -    false
+ pg-3   RUNNING 0         -      10.0.3.203 -    false
+
+

Sur tous les conteneurs, le fichier /etc/hosts est +automatiquement renseigné par le playbook et devrait contenir +au moins :

+
10.0.3.101 e1
+10.0.3.102 e2
+10.0.3.103 e3
+10.0.3.201 pg-1
+10.0.3.202 pg-2
+10.0.3.203 pg-3
+10.0.3.204 backup 
+
+
+

Installation d’Etcd

+
+
    +
  • Installation des paquets
  • +
  • Configuration
  • +
  • Démarrage du service
  • +
  • Vérification
  • +
+
+
+ +
+
+

Installation des paquets

+
+
    +
  • Paquets essentiels : +
      +
    • etcd
    • +
    • curl
    • +
    • jq
    • +
    • iputils-ping
    • +
  • +
+
+
+
 $ for node in e1 e2 e3; do 
+ sudo ssh $node sudo apt install etcd curl iputils-ping jq
+ done
+

Le démarrage du service est automatique sous Debian.

+
 $ for node in e1 e2 e3; do
+ sudo ssh $node  "systemctl status etcd | grep -i active"
+ done
+ 
+
   Active: active (running) since Wed 2021-11-10 17:48:26 UTC; 3min 28s ago
+   Active: active (running) since Wed 2021-11-10 17:48:36 UTC; 3min 18s ago
+   Active: active (running) since Wed 2021-11-10 17:48:46 UTC; 3min 8s ago
+
Vérification
+
$ for node in e1 e2 e3; do  
+sudo ssh $node etcdctl member list
+done
+
8e9e05c52164694d: name=e1 peerURLs=http://localhost:2380 
+clientURLs=http://localhost:2379 isLeader=true
+8e9e05c52164694d: name=e2 peerURLs=http://localhost:2380 
+clientURLs=http://localhost:2379 isLeader=true
+8e9e05c52164694d: name=e3 peerURLs=http://localhost:2380 
+clientURLs=http://localhost:2379 isLeader=true
+

Les nœuds sont tous des leaders indépendants, ce qui ne nous +intéresse pas. Il faut donc les configurer pour qu’ils fonctionnent en +agrégat.

+

Nous arrêtons donc les services :

+
 $ for node in e1 e2 e3; do
+sudo ssh $node "systemctl stop etcd && systemctl status etcd | grep -i active"
+done
+
 Active: inactive (dead) since Wed 2021-11-10 17:59:35 UTC; 2min 46s ago
+ Active: inactive (dead) since Wed 2021-11-10 17:59:35 UTC; 2min 46s ago
+ Active: inactive (dead) since Wed 2021-11-10 17:59:35 UTC; 2min 46s ago
+
+
+

Configuration du service +Etcd

+
+
    +
  • Fichier : /etc/default/etcd
  • +
+
+
+

La configuration du service Etcd se trouve dans le fichier +/etc/default/etcd, elle doit décrire notre agrégat sur +chaque nœud :

+ +
+

Attention aux caractères invisibles ou aux sauts de ligne

+
+

Sur le nœud e1 :

+
ETCD_NAME='e1'
+
+ETCD_DATA_DIR='/var/lib/etcd/default'
+
+ETCD_LISTEN_PEER_URLS='http://127.0.0.1:2380,http://10.0.3.101:2380'
+ETCD_LISTEN_CLIENT_URLS='http://127.0.0.1:2379,http://10.0.3.101:2379'
+ETCD_INITIAL_ADVERTISE_PEER_URLS='http://10.0.3.101:2380'
+
+ETCD_INITIAL_CLUSTER_STATE='new'
+ETCD_INITIAL_CLUSTER_TOKEN='etcd-cluster'
+
+ETCD_INITIAL_CLUSTER+='e1=http://10.0.3.101:2380'
+ETCD_INITIAL_CLUSTER+='e2=http://10.0.3.102:2380'
+ETCD_INITIAL_CLUSTER+='e3=http://10.0.3.103:2380'
+
+ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.101:2379'
+ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.102:2379'
+ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.103:2379'
+

Sur le nœud e2 :

+
ETCD_NAME='e2'
+
+ETCD_DATA_DIR='/var/lib/etcd/default'
+
+ETCD_LISTEN_PEER_URLS='http://127.0.0.1:2380,http://10.0.3.102:2380'
+ETCD_LISTEN_CLIENT_URLS='http://127.0.0.1:2379,http://10.0.3.102:2379'
+ETCD_INITIAL_ADVERTISE_PEER_URLS='http://10.0.3.102:2380'
+
+ETCD_INITIAL_CLUSTER_STATE='new'
+ETCD_INITIAL_CLUSTER_TOKEN='etcd-cluster'
+
+ETCD_INITIAL_CLUSTER+='e1=http://10.0.3.101:2380'
+ETCD_INITIAL_CLUSTER+='e2=http://10.0.3.102:2380'
+ETCD_INITIAL_CLUSTER+='e3=http://10.0.3.103:2380'
+
+ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.101:2379'
+ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.102:2379'
+ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.103:2379'
+

Sur le nœud e3 :

+
ETCD_NAME='e3'
+
+ETCD_DATA_DIR='/var/lib/etcd/default'
+
+ETCD_LISTEN_PEER_URLS='http://127.0.0.1:2380,http://10.0.3.103:2380'
+ETCD_LISTEN_CLIENT_URLS='http://127.0.0.1:2379,http://10.0.3.103:2379'
+ETCD_INITIAL_ADVERTISE_PEER_URLS='http://10.0.3.103:2380'
+
+ETCD_INITIAL_CLUSTER_STATE='new'
+ETCD_INITIAL_CLUSTER_TOKEN='etcd-cluster'
+
+ETCD_INITIAL_CLUSTER+='e1=http://10.0.3.101:2380'
+ETCD_INITIAL_CLUSTER+='e2=http://10.0.3.102:2380'
+ETCD_INITIAL_CLUSTER+='e3=http://10.0.3.103:2380'
+
+ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.101:2379'
+ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.102:2379'
+ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.103:2379'
+
+
+

Démarrage du service

+
+
    +
  • Réinitialisation des bases Etcd
  • +
  • Démarrage du service etcd +
      +
    • systemctl start etcd
    • +
  • +
+
+
+

Avant de démarrer le service sur chaque nœud, il faut réinitialiser +les répertoires de données des nœuds, afin qu’ils reparte sur un +répertoire neuf.

+

Le nœud e1, que nous considérons comme premier +leader sera démarré en premier :

+
 $ for node in e1 e2 e3; do 
+ echo "$node :" ; sudo ssh $node "rm -rf ~etcd/default/member"
+ done
+
 $ for node in e1 e2 e3; do 
+ sudo ssh -o StrictHostKeyChecking=no $node "systemctl start etcd" &
+ sleep 1
+ done
+

En cas d’échec de démarrage, utilisez la commande Systemd +pour en diagnostiquer la cause :

+
 e1:~$ sudo journalctl -xfu etcd
+

Vérification que le nœud e1 ayant démarré en +premier, est bien le leader :

+
 $ for node in e1 e2 e3; do 
+ echo "sur $node :" 
+ sudo ssh $node "etcdctl member list"
+done
+
sur e1 :
+736293150f1cffb7: name=e1 peerURLs=http://10.0.3.101:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379
+isLeader=true
+7ef9d5bb55cefbcc: name=e3 peerURLs=http://10.0.3.103:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379
+isLeader=false
+97463691c7858a7b: name=e2 peerURLs=http://10.0.3.102:2380
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 
+isLeader=false
+sur e2 :
+736293150f1cffb7: name=e1 peerURLs=http://10.0.3.101:2380
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 
+isLeader=true
+7ef9d5bb55cefbcc: name=e3 peerURLs=http://10.0.3.103:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 
+isLeader=false
+97463691c7858a7b: name=e2 peerURLs=http://10.0.3.102:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 
+isLeader=false
+sur e3 :
+736293150f1cffb7: name=e1 peerURLs=http://10.0.3.101:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 
+isLeader=true
+7ef9d5bb55cefbcc: name=e3 peerURLs=http://10.0.3.103:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 
+isLeader=false
+97463691c7858a7b: name=e2 peerURLs=http://10.0.3.102:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 
+isLeader=false
+
+
+

Installation de PostgreSQL / +Patroni

+
+
    +
  • Installation +
      +
    • PostgreSQL
    • +
    • Patroni
    • +
    • pgBackrest
    • +
  • +
+
+
+

Le dépôt pgdg est déjà préconfiguré dans les conteneurs +pg-1, pg-2 et pg-3, l’installation est donc triviale :

+
 $ for node in pg-1 pg-2 pg-3; do
+sudo ssh $node "apt-get update && apt-get install -y postgresql patroni pgbackrest"
+done
+

Vérification :

+
 $ for node in pg-1 pg-2 pg-3; do sudo ssh $node "dpkg -l postgresql patroni 
+pgbackrest | grep ^ii | cut -d ' ' -f 1,3"; done
+ii patroni
+ii pgbackrest
+ii postgresql
+ii patroni
+ii pgbackrest
+ii postgresql
+ii patroni
+ii pgbackrest
+ii postgresql
+

Le service PostgreSQL doit êtrre désactivé car la gestion totale de +l’instance sera déléguée à Patroni :

+
$ for node in pg-1 pg-2 pg-3; do 
+sudo ssh $node "systemctl disable --now postgresql@14-main"
+done
+
+
+

Configuration de Patroni

+
+

Sur tous les nœuds

+
    +
  • Configuration du DCS +
      +
    • /etc/patroni/dcs.yml
    • +
  • +
  • Génération de la configuration +
      +
    • pg_createconfig_patroni 14 main
    • +
  • +
+
+
+

La configuration sous Debian se fait d’abord en renseignant comment +contacter le DCS, puis en lançant le script de génération automatique de +la configuration de Patroni.

+
# /etc/patroni/dcs.yml
+etcd:
+  hosts: e1:2379, e2:2379, e3:2379
+
 $ sudo ssh pg-1 "pg_createconfig_patroni 14 main"
+

La configuration /etc/patroni/14-main.yml est +générée.

+
+
+

Création de l’agrégat

+
+
    +
  • Démarrage du primaire
  • +
  • Création de l’utilisateur de réplication
  • +
  • Suppression des instances secondaires
  • +
  • Démarrage des instances secondaires
  • +
+
+
+
Démarrage du primaire
+

La création de l’agrégat commence par la mise en route du primaire +sur le nœud pg-1, c’est lui qui sera la référence pour les +secondaires.

+

L’utilisateur permettant la mise en réplication doit être créé sur ce +nœud, avec le mot de passe renseigné dans la configuration de +Patroni :

+
 $ sudo ssh pg-1 "sudo systemctl enable --now patroni@14-main"
+
Création de +l’utilisateur de réplication
+
 $ sudo ssh pg-1 "sudo -iu postgres psql -c \"create user replicator replication 
+ password 'rep-pass'\" "
+
Suppression des instances +secondaires
+

Les instances secondaires ont été initialisées lors de l’installation +du paquet Debian, il faut donc vider leur répertoire de données :.

+

pg-1 étant notre primaire :

+
 $ for node in pg-2 pg-3; do
+  sudo ssh  $node "rm -rf /var/lib/postgresql/14/main/*"
+done
+

Les secondaires seront recréés automatiquement depuis le primaire par +Patroni.

+
Démarrage des instances +secondaires
+

Nous pouvons raccrocher nos secondaires en démarrant les deux +instances :

+
 $ for node in pg-2 pg-3; do
+  sudo ssh $node "systemctl start patroni@14-main"
+  done
+
+
+
Vérifications
+
+
    +
  • Liste des nœuds Patroni
  • +
  • Test de bascule manuelle vers chaque nœud
  • +
+
+
+
Liste des nœuds Patroni
+

Sur chaque nœud Patroni, modifier le .profile de +l’utilisateur postgres en ajoutant :

+
export PATRONICTL_CONFIG_FILE=/etc/patroni/14-main.yml
+
 $ sudo ssh pg-1 sudo -iu postgres patronictl list
+
 + Cluster: 14-main (7029596050496494965) -+----+-----------+
+ | Member | Host       | Role    | State   | TL | Lag in MB |
+ +--------+------------+---------+---------+----+-----------+
+ | pg-1   | 10.0.3.201 | Leader  | running |  3 |           |
+ | pg-2   | 10.0.3.202 | Replica | running |  3 |         0 |
+ | pg-3   | 10.0.3.203 | Replica | running |  3 |         0 |
+
Test de bascule +manuelle vers chaque nœud
+
 $ sudo ssh pg-1 sudo -iu postgres patronictl switchover
+
Master [pg-1]:
+Candidate ['pg-2', 'pg-3'] []: pg-2
+When should the switchover take place (e.g. 2021-11-12T12:21 )  [now]:                          
+Current cluster topology
++ Cluster: 14-main (7029596050496494965) -+----+-----------+                                    
+| Member | Host       | Role    | State   | TL | Lag in MB |                                    
++--------+------------+---------+---------+----+-----------+                                    
+| pg-1   | 10.0.3.201 | Leader  | running |  3 |           |                                    
+| pg-2   | 10.0.3.202 | Replica | running |  3 |         0 |                                    
+| pg-3   | 10.0.3.203 | Replica | running |  3 |         0 |                                    
++--------+------------+---------+---------+----+-----------+                                    
+Are you sure you want to switchover cluster 14-main, demoting current master 
+pg-1? [y/N]: y     
+2021-11-12 11:21:20.08091 Successfully switched over to "pg-2"                                  
++ Cluster: 14-main (7029596050496494965) -+----+-----------+                                    
+| Member | Host       | Role    | State   | TL | Lag in MB |                                    
++--------+------------+---------+---------+----+-----------+                                    
+| pg-1   | 10.0.3.201 | Replica | stopped |    |   unknown |                                    
+| pg-2   | 10.0.3.202 | Leader  | running |  3 |           |                                    
+| pg-3   | 10.0.3.203 | Replica | running |  3 |         0 |                                    
++--------+------------+---------+---------+----+-----------+
+
+
+

Création d’incidents

+
+
    +
  • Perte totale du DCS
  • +
  • Freeze du nœud primaire Patroni
  • +
  • Bascule manuelle
  • +
+
+
+ +
+
+

Perte totale du DCS

+
+
    +
  • Perte de tous les nœuds Etcd
  • +
+
+
+

Nous simulons un incident majeur au niveau du DCS :

+
 $ for node in e1 e2 e3; do
+  sudo lxc-freeze $node
+done
+

La commande classique patronictl list échoue faute de +DCS pour la renseigner.

+

Nous interrogeons directement sur les instances :

+
 $ for node in pg-1 pg-2 pg-3; do 
+echo "$node :"
+sudo ssh $node "sudo -iu postgres psql -c 'select pg_is_in_recovery()'"
+done
+
pg-1 :
+ pg_is_in_recovery 
+-------------------
+ t
+(1 ligne)
+
+pg-2 :
+ pg_is_in_recovery 
+-------------------
+ t
+(1 ligne)
+
+pg-3 :
+ pg_is_in_recovery 
+-------------------
+ t
+(1 ligne)
+

Nous constatons que l’intégralité des nœuds est passée en lecture +seule (stand-by).

+

Nous débloquons la situation :

+
 $ for node in e1 e2 e3; do 
+echo "$node :"
+sudo lxc-unfreeze $node
+done
+

Nous pouvons observer le retour à la normale :

+
 postgres@pg-1:~$ patronictl list -ew 1
+
+
+

Perte du nœud primaire +Patroni

+
+
    +
  • Perte du primaire courant
  • +
+
+
+

Dans un autre terminal, nous observons l’état de l’agrégat sur le +nœud pg-2 :

+
 postgres@pg-2:~$ patronictl list -ew 1
+

Nous simulons une perte du primaire pg-1 :

+
 $ sudo lxc-freeze pg-1
+

Nous observons la disparition de pg-1 de la liste des +nœuds et une bascule automatique se déclenche vers un des nœuds +secondaires disponibles :

+
+ Cluster: 14-main (7029596050496494965) -+----+-----------+
+| Member | Host       | Role    | State   | TL | Lag in MB |
++--------+------------+---------+---------+----+-----------+
+| pg-2   | 10.0.3.202 | Replica | running |  7 |         0 |
+| pg-3   | 10.0.3.203 | Leader  | running |  7 |           |
++--------+------------+---------+---------+----+-----------+
+

Nous rétablissons la situation :

+
$ sudo lxc-unfreeze pg-1
+
+ Cluster: 14-main (7029596050496494965) -+----+-----------+
+| Member | Host       | Role    | State   | TL | Lag in MB |
++--------+------------+---------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Replica | running |  6 |         0 |
+| pg-2   | 10.0.3.202 | Replica | running |  7 |         0 |
+| pg-3   | 10.0.3.203 | Leader  | running |  7 |           |
++--------+------------+---------+---------+----+-----------+
+

Pour un retour à l’état nominal, il suffit de procéder à une bascule +manuelle (adapter la commande si votre primaire n’est pas +pg-3) :

+
postgres@pg-1:~$ patronictl switchover --master pg-3 --candidate pg-1 --force
+
Current cluster topology
++ Cluster: 14-main (7029596050496494965) -+----+-----------+
+| Member | Host       | Role    | State   | TL | Lag in MB |
++--------+------------+---------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Replica | running |  7 |         0 |
+| pg-2   | 10.0.3.202 | Replica | running |  7 |         0 |
+| pg-3   | 10.0.3.203 | Leader  | running |  7 |           |
++--------+------------+---------+---------+----+-----------+
+2021-11-12 13:18:36.05884 Successfully switched over to "pg-1"
++ Cluster: 14-main (7029596050496494965) -+----+-----------+
+| Member | Host       | Role    | State   | TL | Lag in MB |
++--------+------------+---------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader  | running |  7 |           |
+| pg-2   | 10.0.3.202 | Replica | running |  7 |         0 |
+| pg-3   | 10.0.3.203 | Replica | stopped |    |   unknown |
++--------+------------+---------+---------+----+-----------+
+
+
+

Modification de la +configuration

+
+
    +
  • patronictl edit-config
  • +
+
+
+

L’un des avantages de bénéficier d’une configuration distribuée est +qu’il est possible de modifier cette configuration pour tous les nœuds +en une seule opération.

+

Si le paramètre nécessite un rechargement de la configuration, elle +sera lancée sur chaque nœud.

+

Si la modification nécessite un redémarrage, l’ drapeau pending +restart sera positionné sur toutes les instances et attendrons une +action de votre part pour l’effectuer.

+

L’installation de la commande less est un +pré-requis :

+
 $ for i in pg-1 pg-2 pg-3; do apt install less done
+ ...
+

La modification peut se faire sur n’importe quel nœud :

+
postgres@pg-2:~$ patronictl edit-config
+

Nous ajoutons une ligne fille de la ligne + parameters:

+
loop_wait: 10
+maximum_lag_on_failover: 1048576
+postgresql:
+  parameters: 
+    max_connections: 123
+ ...
+

Une confirmation est demandée après la sortie de l’éditeur :

+
patronictl edit-config
+--- 
++++ 
+@@ -1,7 +1,8 @@
+ loop_wait: 10
+ maximum_lag_on_failover: 1048576
+ postgresql:
+-  parameters: null
++  parameters: 
++    max_connections: 123
+   pg_hba:
+   - local   all             all                                     peer
+   - host    all             all             127.0.0.1/32            md5
+
+Apply these changes? [y/N]: y
+Configuration changed
+

Après modification, il convient de regarder si notre modification ne +nécessite pas de redémarrage :

+
postgres@pg-2:~$ patronictl list -e
+
+ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+
+| Member | Host       | Role    | State   | TL | Lag in MB | Pending restart |
++--------+------------+---------+---------+----+-----------+-----------------+
+| pg-1   | 10.0.3.201 | Leader  | running |  8 |           | *               |
+| pg-2   | 10.0.3.202 | Replica | running |  8 |         0 | *               | 
+| pg-3   | 10.0.3.203 | Replica | running |  8 |         0 | *               |
++--------+------------+---------+---------+----+-----------+-----------------+
+

Dans notre cas, un redémarrage de toutes les instances est +nécessaire :

+
postgres@pg-2:~$ patronictl restart 14-main
+
+ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+
+| Member | Host       | Role    | State   | TL | Lag in MB | Pending restart |
++--------+------------+---------+---------+----+-----------+-----------------+
+| pg-1   | 10.0.3.201 | Leader  | running |  8 |           | *               |
+| pg-2   | 10.0.3.202 | Replica | running |  8 |         0 | *               |
+| pg-3   | 10.0.3.203 | Replica | running |  8 |         0 | *               |
++--------+------------+---------+---------+----+-----------+-----------------+
+When should the restart take place (e.g. 2021-11-12T14:37)  [now]: 
+Are you sure you want to restart members pg-3, pg-2, pg-1? [y/N]: y
+Restart if the PostgreSQL version is less than provided (e.g. 9.5.2)  []: 
+Success: restart on member pg-3
+Success: restart on member pg-2
+Success: restart on member pg-1
+
postgres@pg-2:~$ patronictl list -e
+
+ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+
+| Member | Host       | Role    | State   | TL | Lag in MB | Pending restart |
++--------+------------+---------+---------+----+-----------+-----------------+
+| pg-1   | 10.0.3.201 | Leader  | running |  8 |           |                 |
+| pg-2   | 10.0.3.202 | Replica | running |  8 |         0 |                 |
+| pg-3   | 10.0.3.203 | Replica | running |  8 |         0 |                 |
++--------+------------+---------+---------+----+-----------+-----------------+
+
 $ for node in pg-1 pg-2 pg-3; do
+  echo "$node :"
+  sudo ssh $node "sudo -iu postgres psql -c 'show max_connections'"
+  done
+
pg-1 :
+ max_connections 
+-----------------
+ 123
+(1 ligne)
+
+pg-2 :
+ max_connections 
+-----------------
+ 123
+(1 ligne)
+
+pg-3 :
+ max_connections 
+-----------------
+ 123
+(1 ligne)
+

L’application d’un paramètre qui ne nécessite pas de redémarrage est +transparente, le rechargement de la configuration sur tous les nœuds est +automatiquement déclenchée par Patroni.

+
+
+

Sauvegardes

+
+
    +
  • Installation pgBackrest
  • +
  • Configuration
  • +
  • Détermination du primaire
  • +
  • Archivage
  • +
  • Sauvegarde
  • +
+
+
+

Détermination du primaire

+

Nous proposons de déclencher la sauvegarde sur le primaire courant, +il faut donc d’abord l’identifier.

+

Le script suivant est une solution permettant de récupérer le +primaire de notre agrégat à partir d’un nœud Etcd ezt de l’API mise à +disposition :

+
#! /bin/bash
+SCOPE=$(grep -i scope: /etc/patroni/14-main.yml | cut -d '"' -f 2)
+curl -s http://e1:2379/v2/keys/postgresql-common/"$SCOPE"/leader | jq -r .node.value
+

Configuration de pgBackrest

+

Sur chacun des nœuds, il faut configurer le stanza et +l’initialiser :

+
# /etc/pgbackrest.conf
+[main]
+pg1-path=/var/lib/postgresql/14/main
+pg1-socket-path=/var/run/postgresql
+pg1-port=5432
+
+[global]
+log-level-file=detail
+log-level-console=detail
+repo1-host=backup
+repo1-host-user=postgres
+

Tous les nœuds doivent permettre la connexion ssh sans mot +de passe, le playbook Ansible nommé +exchange_ssh_keys permet de faire ce travail +rapidement :

+
 $ sudo ansible-playbook -i inventory.yml exchange_ssh_keys.yml  -f 7
+

Nous pouvons alors tenter de créer le stanza sur le +primaire :

+
postgres@pg-1:~$ pgbackrest --stanza main stanza-create
+postgres@pg-1:/var/lib/pgbackrest$ pgbackrest --stanza  main check
+ERROR: [087]: archive_mode must be enabled
+

Configuration de l’archivage

+

Toutes les instances doivent être en mesure d’archiver leurs journaux +de transactions au moyen de pgBackrest :

+
postgres@pg-1:~$ patronictl edit-config
+
postgresql:
+  parameters:
+    max_connections: 123
+    archive_mode: 'on'
+    archive_command: pgbackrest --stanza=main archive-push %p
+

Notre configuration n’a pas encore été appliquée sur les instances +car un redémarrage est requis :

+
postgres@pg-1:~$ patronictl list -e
+
+ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+
+| Member | Host       | Role    | State   | TL | Lag in MB | Pending restart |
++--------+------------+---------+---------+----+-----------+-----------------+
+| pg-1   | 10.0.3.201 | Leader  | running |  8 |           | *               |
+| pg-2   | 10.0.3.202 | Replica | running |  8 |         0 | *               |
+| pg-3   | 10.0.3.203 | Replica | running |  8 |         0 | *               |
++--------+------------+---------+---------+----+-----------+-----------------+
+
postgres@pg-1:~$ patronictl restart 14-main --force
++ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+
+| Member | Host       | Role    | State   | TL | Lag in MB | Pending restart |
++--------+------------+---------+---------+----+-----------+-----------------+
+| pg-1   | 10.0.3.201 | Leader  | running |  8 |           | *               |
+| pg-2   | 10.0.3.202 | Replica | running |  8 |         0 | *               |
+| pg-3   | 10.0.3.203 | Replica | running |  8 |         0 | *               |
++--------+------------+---------+---------+----+-----------+-----------------+
+Success: restart on member pg-1
+Success: restart on member pg-3
+Success: restart on member pg-2
+

Test de la configuration de l’archivage sur le nœud +pg-1 :

+
postgres@pg-1:~$ pgbackrest --stanza main --log-level-console detail  check
+
2021-11-12 15:57:04.000 P00   INFO: check command begin 2.35: --exec-id=13216-
+4a7c4a92 --log-level-console=detail --log-level-file=detail --pg1-path=/var/lib/
+postgresql/14/main --pg1-port=5432 --pg1-socket-path=/var/run/postgresql --
+repo1-host=backup --repo1-host-user=postgres --stanza=main
+2021-11-12 15:57:04.616 P00   INFO: check repo1 configuration (primary)
+2021-11-12 15:57:05.083 P00   INFO: check repo1 archive for WAL (primary)
+2021-11-12 15:57:08.425 P00   INFO: WAL segment 000000080000000000000005 
+successfully archived to '/var/lib/pgbackrest/archive/main/14-1/
+0000000800000000/000000080000000000000005-
+b0929d740c7996974992ecd7b9b189b37d06a896.gz' on repo1
+2021-11-12 15:57:08.528 P00   INFO: check command end: completed successfully 
+(4531ms)
+

Configuration +sur la machine hébergeant les sauvegardes

+

Sur la machine backup, créer le script de détermination +du leader (le rendre exécutable) :

+
postgres@backup:~$ vim ~/leader.sh && chmod +x leader.sh
+
#! /bin/bash
+SCOPE='14-main'
+curl -s http://e1:2379/v2/keys/postgresql-common/"$SCOPE"/leader | jq -r .node.value
+
Configuration de pgBackrest
+

La configuration se fait dans le fichier +/etc/pgbackrest.conf :

+
[global]
+repo1-path=/var/lib/pgbackrest
+repo1-retention-full=2
+start-fast=y
+log-level-console=detail
+
+[main]
+pg1-path=/var/lib/postgresql/14/main
+pg1-host-user=postgres
+pg1-user=postgres
+pg1-port=5432
+
test d’une sauvegarde
+
postgres@backup:~$ pgbackrest --stanza main --pg1-host=$(./leader.sh) backup 
+--type=full
+
2021-11-12 16:32:32.128 P00   INFO: backup command begin 2.35: --exec-id=6717-
+e7512f6c --log-level-console=detail --pg1-host=pg-1 --pg1-host-user=postgres --
+pg1-path=/var/lib/postgresql/14/main --pg1-port=5432 --pg1-user=postgres --
+repo1-path=/var/lib/pgbackrest --repo1-retention-full=2 --stanza=main --start-
+fast --type=full
+2021-11-12 16:32:33.114 P00   INFO: execute non-exclusive pg_start_backup(): 
+backup begins after the requested immediate checkpoint completes
+2021-11-12 16:32:34.129 P00   INFO: backup start archive = 
+00000008000000000000000B, lsn = 0/B000028
+2021-11-12 16:32:36.709 P01 DETAIL: backup file pg-1:/var/lib/postgresql/14/
+main/base/13707/1255 (752KB, 2%) checksum 
+2bac9bc6e62f6059736f9152a045bb43c0832231
+2021-11-12 16:32:37.119 P01 DETAIL: backup file pg-1:/var/lib/postgresql/14/
+main/base/13706/1255 (752KB, 5%) checksum 
+2bac9bc6e62f6059736f9152a045bb43c0832231 
+...
+...
+2021-11-12 16:32:45.786 P01 DETAIL: backup file pg-1:/var/lib/postgresql/14/
+main/base/1/13528 (0B, 100%)
+2021-11-12 16:32:45.791 P00   INFO: execute non-exclusive pg_stop_backup() and 
+wait for all WAL segments to archive
+2021-11-12 16:32:46.095 P00   INFO: backup stop archive = 
+00000008000000000000000B, lsn = 0/B000138
+2021-11-12 16:32:46.101 P00 DETAIL: wrote 'backup_label' file returned from 
+pg_stop_backup()
+2021-11-12 16:32:46.103 P00   INFO: check archive for segment(s) 
+00000008000000000000000B:00000008000000000000000B
+2021-11-12 16:32:49.611 P00   INFO: new backup label = 20211112-163233F
+2021-11-12 16:32:49.673 P00   INFO: full backup size = 25.1MB, file total = 952
+2021-11-12 16:32:49.674 P00   INFO: backup command end: completed successfully 
+(17556ms)
+2021-11-12 16:32:49.675 P00   INFO: expire command begin 2.35: --exec-id=6717-
+e7512f6c --log-level-console=detail --repo1-path=/var/lib/pgbackrest --repo1-
+retention-full=2 --stanza=main
+2021-11-12 16:32:49.686 P00   INFO: expire command end: completed successfully 
+(11ms)
+

Vérification de l’état de la sauvegarde :

+
postgres@backup:~$ pgbackrest --stanza main info
+
stanza: main
+    status: ok
+    cipher: none
+
+    db (current)
+        wal archive min/max (14): 000000010000000000000001/00000008000000000000000B
+
+        full backup: 20211112-163233F
+            timestamp start/stop: 2021-11-12 16:32:33 / 2021-11-12 16:32:45
+            wal start/stop: 00000008000000000000000B / 00000008000000000000000B
+            database size: 25.1MB, database backup size: 25.1MB
+            repo1: backup set size: 3.2MB, backup size: 3.2MB
+
+
+

Références

+ +
+ +
+
+
+
+ + +
+ + diff --git a/fr/patroni/_archives/pgs14/patroni.html b/fr/patroni/_archives/pgs14/patroni.html new file mode 100644 index 0000000..14782fb --- /dev/null +++ b/fr/patroni/_archives/pgs14/patroni.html @@ -0,0 +1,7208 @@ + + + + + + + + Haute disponibilité avec Patroni + + + + + + + + + + + + + + + +
+
+ +
+

Haute disponibilité avec Patroni

+

Workshop Patroni

+

Dalibo & Contributors

+
+
+true +
+ + +
+

Haute disponibilité de service avec Patroni

+
+PostgreSQL + +
+ +
+
+ +

Introduction

+
+
    +
  • Principes
  • +
  • Mise en place
  • +
  • Installation et configuration des services
  • +
  • Construction d’un agrégat à bascule automatique
  • +
  • Création d’incidents
  • +
+
+ +
+
+ +

Principes

+
+
    +
  • Arbitrage par un quorum : DCS Etcd
  • +
  • Service PostgreSQL : désactivé
  • +
  • Contrôle complet par Patroni
  • +
+
+ +
+
+ +

DCS : Etcd

+
+
    +
  • Arbitre en cas de bascules
  • +
  • Stockage distribué de la configuration
  • +
  • Jeton leader (Etcd)
  • +
  • Instance primaire PostgreSQL
  • +
+
+ +
+
+ +

Mise en place de +l’infrastructure

+
+
    +
  • Connexion à la VM
  • +
  • Récupération du playbook Ansible
  • +
+
+ +
+
+ +

Connexion à votre machine +virtuelle

+
+

un seul point d’entrée : eformation.dalibo.com un port +attribué : 22XX

+
  $ ssh -p 22XX dalibo@eformation.dalibo.com
+
+ +
+
+ +

Playbook Ansible

+
+

Récupération du playbook Ansible à cette +adresse :

+

https://github.com/dalibo/workshops/tree/workshop_patroni/fr/patroni/playbook/etcd-patroni

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FichierDescription
inventory.ymlinventaire des machines
setup.ymlplaybook principal
exchange_ssh_keys.ymlplaybook d’échange de clés +ssh
teardown.ymlplaybook de destruction +massive
demarre_tout.shdémarre tous les conteneurs
stoppe_tout.sharrête tous les conteneurs
teardown.ymlplaybook de destruction +massive
+
+ +
+
+ +
+

L’infrastructure complète peut être créée à l’aide des +commandes :

+
 $ sudo apt install -y ansible
+ $ sudo ansible-playbook -f 7 -i inventory.yml setup.yml
+...
+

Cette opération peut durer jusqu’à une vingtaine de minutes.

+
+ +
+
+ +

Installation d’Etcd

+
+
    +
  • Installation des paquets
  • +
  • Configuration
  • +
  • Démarrage du service
  • +
  • Vérification
  • +
+
+ +
+
+ +

Installation des paquets

+
+
    +
  • Paquets essentiels : +
      +
    • etcd
    • +
    • curl
    • +
    • jq
    • +
    • iputils-ping
    • +
  • +
+
+ +
+
+ +

Configuration du service +Etcd

+
+
    +
  • Fichier : /etc/default/etcd
  • +
+
+ +
+
+ +

Démarrage du service

+
+
    +
  • Réinitialisation des bases Etcd
  • +
  • Démarrage du service etcd +
      +
    • systemctl start etcd
    • +
  • +
+
+ +
+
+ +

Installation de PostgreSQL / +Patroni

+
+
    +
  • Installation +
      +
    • PostgreSQL
    • +
    • Patroni
    • +
    • pgBackrest
    • +
  • +
+
+ +
+
+ +

Configuration de Patroni

+
+

Sur tous les nœuds PostgreSQL/Patroni

+
    +
  • Configuration du DCS +
      +
    • /etc/patroni/dcs.yml
    • +
  • +
  • Génération de la configuration +
      +
    • pg_createconfig_patroni 15 main
    • +
  • +
+
+ +

Ces opérations doivent être répétées sur tous nœuds +PostgreSQL/Patroni.

+
+
+ +

Création de l’agrégat

+
+
    +
  • Démarrage du primaire
  • +
  • Création de l’utilisateur de réplication
  • +
  • Suppression des instances secondaires
  • +
  • Démarrage des instances secondaires
  • +
+
+ +
+
+ +
Vérifications
+
+
    +
  • Liste des nœuds Patroni
  • +
  • Test de bascule manuelle vers chaque nœud
  • +
+
+ +
+
+ +

Création d’incidents

+
+
    +
  • Perte totale du DCS
  • +
  • Freeze du nœud primaire Patroni
  • +
  • Bascule manuelle
  • +
+
+ +
+
+ +

Perte totale du DCS

+
+
    +
  • Perte de tous les nœuds Etcd
  • +
+
+ +
+
+ +

Perte du nœud primaire +Patroni

+
+
    +
  • Perte du primaire courant
  • +
+
+ +
+
+ +

Modification de la +configuration

+
+
    +
  • patronictl edit-config
  • +
+
+ +
+
+ +

Sauvegardes

+
+
    +
  • Installation pgBackrest
  • +
  • Configuration
  • +
  • Détermination du primaire
  • +
  • Archivage
  • +
  • Sauvegarde
  • +
+
+ +
+
+ +

Références

+ + +
+
+ +
+
+
+ + + + + + + + + + diff --git a/fr/patroni/_archives/pgs14/patroni.local.html b/fr/patroni/_archives/pgs14/patroni.local.html new file mode 100644 index 0000000..e49e5ec --- /dev/null +++ b/fr/patroni/_archives/pgs14/patroni.local.html @@ -0,0 +1,1204 @@ + + + + + + + + Haute disponibilité avec Patroni + + + + + + + + + + + + + + + +
+
+ +
+

Haute disponibilité avec Patroni

+

Workshop Patroni

+

Dalibo & Contributors

+
+
+true +
+ + +
+

Haute disponibilité de service avec Patroni

+
+PostgreSQL + +
+ +
+
+ +

Introduction

+
+
    +
  • Principes
  • +
  • Mise en place
  • +
  • Installation et configuration des services
  • +
  • Construction d’un agrégat à bascule automatique
  • +
  • Création d’incidents
  • +
+
+ +
+
+ +

Principes

+
+
    +
  • Arbitrage par un quorum : DCS Etcd
  • +
  • Service PostgreSQL : désactivé
  • +
  • Contrôle complet par Patroni
  • +
+
+ +
+
+ +

DCS : Etcd

+
+
    +
  • Arbitre en cas de bascules
  • +
  • Stockage distribué de la configuration
  • +
  • Jeton leader (Etcd)
  • +
  • Instance primaire PostgreSQL
  • +
+
+ +
+
+ +

Mise en place de +l’infrastructure

+
+
    +
  • Connexion à la VM
  • +
  • Récupération du playbook Ansible
  • +
+
+ +
+
+ +

Connexion à votre machine +virtuelle

+
+

un seul point d’entrée : eformation.dalibo.com un port +attribué : 22XX

+
  $ ssh -p 22XX dalibo@eformation.dalibo.com
+
+ +
+
+ +

Playbook Ansible

+
+

Récupération du playbook Ansible à cette +adresse :

+

https://github.com/dalibo/workshops/tree/workshop_patroni/fr/patroni/playbook/etcd-patroni

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FichierDescription
inventory.ymlinventaire des machines
setup.ymlplaybook principal
exchange_ssh_keys.ymlplaybook d’échange de clés +ssh
teardown.ymlplaybook de destruction +massive
demarre_tout.shdémarre tous les conteneurs
stoppe_tout.sharrête tous les conteneurs
teardown.ymlplaybook de destruction +massive
+
+ +
+
+ +
+

L’infrastructure complète peut être créée à l’aide des +commandes :

+
 $ sudo apt install -y ansible
+ $ sudo ansible-playbook -f 7 -i inventory.yml setup.yml
+...
+

Cette opération peut durer jusqu’à une vingtaine de minutes.

+
+ +
+
+ +

Installation d’Etcd

+
+
    +
  • Installation des paquets
  • +
  • Configuration
  • +
  • Démarrage du service
  • +
  • Vérification
  • +
+
+ +
+
+ +

Installation des paquets

+
+
    +
  • Paquets essentiels : +
      +
    • etcd
    • +
    • curl
    • +
    • jq
    • +
    • iputils-ping
    • +
  • +
+
+ +
+
+ +

Configuration du service +Etcd

+
+
    +
  • Fichier : /etc/default/etcd
  • +
+
+ +
+
+ +

Démarrage du service

+
+
    +
  • Réinitialisation des bases Etcd
  • +
  • Démarrage du service etcd +
      +
    • systemctl start etcd
    • +
  • +
+
+ +
+
+ +

Installation de PostgreSQL / +Patroni

+
+
    +
  • Installation +
      +
    • PostgreSQL
    • +
    • Patroni
    • +
    • pgBackrest
    • +
  • +
+
+ +
+
+ +

Configuration de Patroni

+
+

Sur tous les nœuds PostgreSQL/Patroni

+
    +
  • Configuration du DCS +
      +
    • /etc/patroni/dcs.yml
    • +
  • +
  • Génération de la configuration +
      +
    • pg_createconfig_patroni 15 main
    • +
  • +
+
+ +

Ces opérations doivent être répétées sur tous nœuds +PostgreSQL/Patroni.

+
+
+ +

Création de l’agrégat

+
+
    +
  • Démarrage du primaire
  • +
  • Création de l’utilisateur de réplication
  • +
  • Suppression des instances secondaires
  • +
  • Démarrage des instances secondaires
  • +
+
+ +
+
+ +
Vérifications
+
+
    +
  • Liste des nœuds Patroni
  • +
  • Test de bascule manuelle vers chaque nœud
  • +
+
+ +
+
+ +

Création d’incidents

+
+
    +
  • Perte totale du DCS
  • +
  • Freeze du nœud primaire Patroni
  • +
  • Bascule manuelle
  • +
+
+ +
+
+ +

Perte totale du DCS

+
+
    +
  • Perte de tous les nœuds Etcd
  • +
+
+ +
+
+ +

Perte du nœud primaire +Patroni

+
+
    +
  • Perte du primaire courant
  • +
+
+ +
+
+ +

Modification de la +configuration

+
+
    +
  • patronictl edit-config
  • +
+
+ +
+
+ +

Sauvegardes

+
+
    +
  • Installation pgBackrest
  • +
  • Configuration
  • +
  • Détermination du primaire
  • +
  • Archivage
  • +
  • Sauvegarde
  • +
+
+ +
+
+ +

Références

+ + +
+
+ +
+
+
+ + + + + + + + + + diff --git a/fr/patroni/_archives/pgs14/patroni.md b/fr/patroni/_archives/pgs14/patroni.md new file mode 100644 index 0000000..28f1b2e --- /dev/null +++ b/fr/patroni/_archives/pgs14/patroni.md @@ -0,0 +1,1413 @@ +--- +subtitle : 'Workshop Patroni' +title : 'Haute disponibilité de service - Patroni' +keywords: +- postgres +- postgresql +- workshop +- patroni +- etcd +- ha +- haute disponibilité + +linkcolor: + +licence : PostgreSQL +author: Dalibo & Contributors +revision: 18.06 +url : http://dalibo.com/formations + +# +# PDF Options +# + +#toc: true + +## Limiter la profondeur de la table des matières +toc-depth: 4 + +## Mettre les lien http en pieds de page +links-as-notes: true + +## Police plus petite dans un bloc de code + +code-blocks-fontsize: small + +## Filtre : pandoc-latex-env = cadres de couleurs +## OBSOLETE voir pandoc-latex-admonition +latex-environment: + importantframe: [important] + warningframe: [warning] + tipframe: [tip] + noteframe: [note] + frshaded: [slide-content] + +## Filtre : pandoc-latex-admonition +## order of definition is important +pandoc-latex-admonition: + - color: LightPink + classes: [important] + linewidth: 4 + - color: Khaki + classes: [warning] + linewidth: 4 + - color: DarkSeaGreen + classes: [tip] + linewidth: 4 + - color: Ivory + classes: [note] + linewidth: 4 + - color: DodgerBlue + classes: [slide-content] + linewidth: 4 + +# +# Reveal Options +# + +# Taille affichage +width: 1200 +height: 768 + +## beige/blood/moon/simple/solarized/black/league/night/serif/sky/white +theme: white + +## None - Fade - Slide - Convex - Concave - Zoom +transition: None + +transition-speed: fast + +# Barre de progression +progress: true + +# Affiche N° de slide +slideNumber: true + +# Le numero de slide apparait dans la barre d'adresse +history: true + +# Defilement des slides avec la roulette +mouseWheel: false + +# Annule la transformation uppercase de certains themes +title-transform : none + +# Cache l'auteur sur la première slide +# Mettre en commentaire pour désactiver +hide_author_in_slide: true + + +--- + +# Haute disponibilité de service avec Patroni + + +![PostgreSQL](medias/etcd-patroni.png) + +
+ + +
+ +--- + +## Introduction + +
+ + * Principes + * Mise en place + * Installation et configuration des services + * Construction d'un agrégat à bascule automatique + * Création d'incidents +
+ +
+ +
+ +--- + +\newpage + +## Principes + +
+ + * Arbitrage par un quorum : _DCS_ Etcd + * Service PostgreSQL : désactivé + * Contrôle complet par Patroni + +
+ +
+ + +
+ +--- + +### DCS : Etcd + +
+ + * Arbitre en cas de bascules + * Stockage distribué de la configuration + * Jeton _leader_ (Etcd) + * Instance primaire PostgreSQL + +
+ +
+ +Pour arbitrer les bascules automatiques, confirmer le primaire PostgreSQL ou distribuer la configuration, Patroni utilise un _DCS_ (_distributed configuration system_). + +Pour ce rôle, nous utiliserons Etcd. + +
+ +--- + +### Service PostgreSQL et Patroni + +
+ + * Service PostgreSQL désactivé + +
+ +
+ + +Le service PostgreSQL doit être **désactivé** pour ne pas se lancer au démarrage, le contrôle total de l'instance est délégué à Patroni : + + +```Bash + $ for node in pg-1 pg-2 pg-3; do + sudo systemctl disable --now postgresql + sudo systemctl status postgresql +done +``` +```console +Synchronizing state of postgresql.service with SysV service script with /lib/ +systemd/systemd-sysv-install. +Executing: /lib/systemd/systemd-sysv-install disable postgresql +· postgresql.service - PostgreSQL RDBMS + Loaded: loaded (/lib/systemd/system/postgresql.service; disabled; vendor + preset: enabled) + Active: inactive (dead) +Synchronizing state of postgresql.service with SysV service script with /lib/ +systemd/systemd-sysv-install. +Executing: /lib/systemd/systemd-sysv-install disable postgresql +· postgresql.service - PostgreSQL RDBMS + Loaded: loaded (/lib/systemd/system/postgresql.service; disabled; vendor + preset: enabled) + Active: inactive (dead) +Synchronizing state of postgresql.service with SysV service script with /lib/ +systemd/systemd-sysv-install. +Executing: /lib/systemd/systemd-sysv-install disable postgresql +· postgresql.service - PostgreSQL RDBMS + Loaded: loaded (/lib/systemd/system/postgresql.service; disabled; vendor + preset: enabled) + Active: inactive (dead) +``` + +
+ +--- + +## Mise en place de l'infrastructure + +
+ + * Connexion à la VM + * Récupération du _playbook_ _Ansible_ + +
+ +
+ +Vous disposez d'une machine virtuelle dédiée dans laquelle nous construirons 7 conteneurs _lxc_ : + + * 3 Etcd + * 3 Patroni + * 1 backup optionnel : (sauvegardes, archivage) + +
+ +--- + +### Connexion à votre machine virtuelle + +
+ +un seul point d'entrée : `eformation.dalibo.com` +un port attribué : 22XX + +```Bash +  $ ssh -p 22XX dalibo@eformation.dalibo.com +``` + +
+ + +
+ +Exemple de configuration pour une connexion simplifiée : + +```console + +# .ssh/config + +Host vm38 +Hostname eformation.dalibo.com +User dalibo +port 2238 + +``` + +```Bash + $ ssh vm38 +``` +```console +Last login: Wed Nov 10 13:23:26 2021 from 78.213.160.12 +dalibo@vm38:~$ +``` + +
+ +--- + +### Playbook Ansible + +
+ + Récupération du _playbook_ _Ansible_ à cette adresse : + + + + +| Fichier | Description | +| :------------- | :------------- | +| inventory.yml | inventaire des machines | +| setup.yml | _playbook_ principal | +| warmup.sh | script d'amorçage | +| | | +| exchange_ssh_keys.yml | _playbook_ d'échange de clés _ssh_ | +| teardown.yml | _playbook_ de destruction massive | + +
+ +
+ +Quatre fichiers Yaml, un script shell : + + +Le script `warmup.sh` permet de précharger une image debian pour accélérer la création des autres conteneurs : + +```Bash + $ sudo ./warmup.sh +``` + +
+ +--- + +
+ +L'infrastructure complète peut être créée à l'aide des commandes : + +``` + $ sudo apt install -y ansible + $ sudo ansible-playbook -f 7 -i inventory.yml setup.yml +... +``` + +Cette opération peut durer jusqu'à une vingtaine de minutes. + +
+ + +
+ +Vous pouvez suivre l'évolution de la création des conteneurs dans un autre terminal : + +```Bash + $ watch -n 1 sudo lxc-ls -f +``` + +```console + $ sudo lxc-ls -f + NAME STATE AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED + backup STOPPED 0 - - - false + e1 STOPPED 0 - - - false + e2 STOPPED 0 - - - false + e3 STOPPED 0 - - - false + pg-1 STOPPED 0 - - - false + pg-2 STOPPED 0 - - - false + pg-3 STOPPED 0 - - - false +``` + +L'état final de chaque conteneur étant *RUNNING* avec une adresse *IPV4* attribuée : + +```console + $ sudo lxc-ls -f + NAME STATE AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED + backup RUNNING 0 - 10.0.3.204 - false + e1 RUNNING 0 - 10.0.3.101 - false + e2 RUNNING 0 - 10.0.3.102 - false + e3 RUNNING 0 - 10.0.3.103 - false + pg-1 RUNNING 0 - 10.0.3.201 - false + pg-2 RUNNING 0 - 10.0.3.202 - false + pg-3 RUNNING 0 - 10.0.3.203 - false + +``` + +Sur tous les conteneurs, le fichier `/etc/hosts` est automatiquement renseigné par le _playbook_ et devrait contenir au moins : + +```ini +10.0.3.101 e1 +10.0.3.102 e2 +10.0.3.103 e3 +10.0.3.201 pg-1 +10.0.3.202 pg-2 +10.0.3.203 pg-3 +10.0.3.204 backup +``` + +
+ +--- + +\newpage + + +### Installation d'Etcd + +
+ + * Installation des paquets + * Configuration + * Démarrage du service + * Vérification + +
+ +
+ + +
+ +--- + +#### Installation des paquets + +
+ + * Paquets essentiels : + * etcd + * curl + * jq + * iputils-ping + +
+ +
+ + + +```Bash + $ for node in e1 e2 e3; do + sudo ssh $node sudo apt install etcd curl iputils-ping jq + done +``` + +Le démarrage du service est automatique sous Debian. +```Bash + $ for node in e1 e2 e3; do + sudo ssh $node "systemctl status etcd | grep -i active" + done + +``` + +```console + Active: active (running) since Wed 2021-11-10 17:48:26 UTC; 3min 28s ago + Active: active (running) since Wed 2021-11-10 17:48:36 UTC; 3min 18s ago + Active: active (running) since Wed 2021-11-10 17:48:46 UTC; 3min 8s ago +``` + +##### Vérification + +```Bash +$ for node in e1 e2 e3; do +sudo ssh $node etcdctl member list +done +``` + +```console +8e9e05c52164694d: name=e1 peerURLs=http://localhost:2380 +clientURLs=http://localhost:2379 isLeader=true +8e9e05c52164694d: name=e2 peerURLs=http://localhost:2380 +clientURLs=http://localhost:2379 isLeader=true +8e9e05c52164694d: name=e3 peerURLs=http://localhost:2380 +clientURLs=http://localhost:2379 isLeader=true +``` + +Les nœuds sont tous des _leaders_ indépendants, ce qui ne nous intéresse pas. Il faut donc les configurer pour qu'ils fonctionnent en agrégat. + +Nous arrêtons donc les services : + +```Bash + $ for node in e1 e2 e3; do +sudo ssh $node "systemctl stop etcd && systemctl status etcd | grep -i active" +done +``` +```console + Active: inactive (dead) since Wed 2021-11-10 17:59:35 UTC; 2min 46s ago + Active: inactive (dead) since Wed 2021-11-10 17:59:35 UTC; 2min 46s ago + Active: inactive (dead) since Wed 2021-11-10 17:59:35 UTC; 2min 46s ago +``` + +
+ +--- + +#### Configuration du service Etcd + +
+ + * Fichier : `/etc/default/etcd` + +
+ +
+ + +La configuration du service Etcd se trouve dans le fichier `/etc/default/etcd`, elle doit décrire notre agrégat sur chaque nœud : + + + +
+ +Attention aux caractères invisibles ou aux sauts de ligne +
+ +**Sur le nœud e1 :** + +```sh +ETCD_NAME='e1' + +ETCD_DATA_DIR='/var/lib/etcd/default' + +ETCD_LISTEN_PEER_URLS='http://127.0.0.1:2380,http://10.0.3.101:2380' +ETCD_LISTEN_CLIENT_URLS='http://127.0.0.1:2379,http://10.0.3.101:2379' +ETCD_INITIAL_ADVERTISE_PEER_URLS='http://10.0.3.101:2380' + +ETCD_INITIAL_CLUSTER_STATE='new' +ETCD_INITIAL_CLUSTER_TOKEN='etcd-cluster' + +ETCD_INITIAL_CLUSTER+='e1=http://10.0.3.101:2380' +ETCD_INITIAL_CLUSTER+='e2=http://10.0.3.102:2380' +ETCD_INITIAL_CLUSTER+='e3=http://10.0.3.103:2380' + +ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.101:2379' +ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.102:2379' +ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.103:2379' +``` + +**Sur le nœud e2 :** + + +```sh +ETCD_NAME='e2' + +ETCD_DATA_DIR='/var/lib/etcd/default' + +ETCD_LISTEN_PEER_URLS='http://127.0.0.1:2380,http://10.0.3.102:2380' +ETCD_LISTEN_CLIENT_URLS='http://127.0.0.1:2379,http://10.0.3.102:2379' +ETCD_INITIAL_ADVERTISE_PEER_URLS='http://10.0.3.102:2380' + +ETCD_INITIAL_CLUSTER_STATE='new' +ETCD_INITIAL_CLUSTER_TOKEN='etcd-cluster' + +ETCD_INITIAL_CLUSTER+='e1=http://10.0.3.101:2380' +ETCD_INITIAL_CLUSTER+='e2=http://10.0.3.102:2380' +ETCD_INITIAL_CLUSTER+='e3=http://10.0.3.103:2380' + +ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.101:2379' +ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.102:2379' +ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.103:2379' +``` + +**Sur le nœud e3 :** + +```sh +ETCD_NAME='e3' + +ETCD_DATA_DIR='/var/lib/etcd/default' + +ETCD_LISTEN_PEER_URLS='http://127.0.0.1:2380,http://10.0.3.103:2380' +ETCD_LISTEN_CLIENT_URLS='http://127.0.0.1:2379,http://10.0.3.103:2379' +ETCD_INITIAL_ADVERTISE_PEER_URLS='http://10.0.3.103:2380' + +ETCD_INITIAL_CLUSTER_STATE='new' +ETCD_INITIAL_CLUSTER_TOKEN='etcd-cluster' + +ETCD_INITIAL_CLUSTER+='e1=http://10.0.3.101:2380' +ETCD_INITIAL_CLUSTER+='e2=http://10.0.3.102:2380' +ETCD_INITIAL_CLUSTER+='e3=http://10.0.3.103:2380' + +ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.101:2379' +ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.102:2379' +ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.103:2379' +``` + +
+ +--- + +#### Démarrage du service + +
+ + * Réinitialisation des bases Etcd + * Démarrage du service `etcd` + * `systemctl start etcd` + +
+ +
+ + +Avant de démarrer le service sur chaque nœud, il faut réinitialiser les répertoires de données des nœuds, afin qu'ils reparte sur un répertoire neuf. + +Le nœud `e1`, que nous considérons comme premier _leader_ sera démarré en premier : + +```Bash + $ for node in e1 e2 e3; do + echo "$node :" ; sudo ssh $node "rm -rf ~etcd/default/member" + done +``` + + +```Bash + $ for node in e1 e2 e3; do + sudo ssh -o StrictHostKeyChecking=no $node "systemctl start etcd" & + sleep 1 + done +``` + +En cas d'échec de démarrage, utilisez la commande _Systemd_ pour en diagnostiquer la cause : + +```Bash + e1:~$ sudo journalctl -xfu etcd +``` + +**Vérification que le nœud `e1` ayant démarré en premier, est bien le _leader_ :** + +```Bash + $ for node in e1 e2 e3; do + echo "sur $node :" + sudo ssh $node "etcdctl member list" +done +``` + +```console +sur e1 : +736293150f1cffb7: name=e1 peerURLs=http://10.0.3.101:2380 +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 +isLeader=true +7ef9d5bb55cefbcc: name=e3 peerURLs=http://10.0.3.103:2380 +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 +isLeader=false +97463691c7858a7b: name=e2 peerURLs=http://10.0.3.102:2380 +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 +isLeader=false +sur e2 : +736293150f1cffb7: name=e1 peerURLs=http://10.0.3.101:2380 +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 +isLeader=true +7ef9d5bb55cefbcc: name=e3 peerURLs=http://10.0.3.103:2380 +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 +isLeader=false +97463691c7858a7b: name=e2 peerURLs=http://10.0.3.102:2380 +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 +isLeader=false +sur e3 : +736293150f1cffb7: name=e1 peerURLs=http://10.0.3.101:2380 +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 +isLeader=true +7ef9d5bb55cefbcc: name=e3 peerURLs=http://10.0.3.103:2380 +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 +isLeader=false +97463691c7858a7b: name=e2 peerURLs=http://10.0.3.102:2380 +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 +isLeader=false +``` + +
+ +--- + +### Installation de PostgreSQL / Patroni + +
+ + * Installation + * PostgreSQL + * Patroni + * pgBackrest + +
+ +
+ +Le dépôt _pgdg_ est déjà préconfiguré dans les conteneurs pg-1, pg-2 et pg-3, l'installation est donc triviale : + +```Bash + $ for node in pg-1 pg-2 pg-3; do +sudo ssh $node "apt-get update && apt-get install -y postgresql patroni pgbackrest" +done +``` + + +Vérification : + +```Bash + $ for node in pg-1 pg-2 pg-3; do sudo ssh $node "dpkg -l postgresql patroni +pgbackrest | grep ^ii | cut -d ' ' -f 1,3"; done +ii patroni +ii pgbackrest +ii postgresql +ii patroni +ii pgbackrest +ii postgresql +ii patroni +ii pgbackrest +ii postgresql +``` + +Le service PostgreSQL doit êtrre désactivé car la gestion totale de l'instance sera déléguée à Patroni : + +```Bash +$ for node in pg-1 pg-2 pg-3; do +sudo ssh $node "systemctl disable --now postgresql@14-main" +done +``` + +
+ +--- + +#### Configuration de Patroni + +
+ +Sur tous les nœuds + + * Configuration du DCS + * `/etc/patroni/dcs.yml` + * Génération de la configuration + * `pg_createconfig_patroni 14 main` + + +
+ +
+ +La configuration sous Debian se fait d'abord en renseignant comment contacter le DCS, puis en lançant le script de génération automatique de la configuration de Patroni. + +```yaml +# /etc/patroni/dcs.yml +etcd: + hosts: e1:2379, e2:2379, e3:2379 +``` + +```Bash + $ sudo ssh pg-1 "pg_createconfig_patroni 14 main" +``` + +La configuration `/etc/patroni/14-main.yml` est générée. + +
+ +--- + +#### Création de l'agrégat + +
+ + * Démarrage du primaire + * Création de l'utilisateur de réplication + * Suppression des instances secondaires + * Démarrage des instances secondaires + +
+ +
+ +##### Démarrage du primaire + + +La création de l'agrégat commence par la mise en route du primaire sur le nœud `pg-1`, c'est lui qui sera la référence pour les secondaires. + +L'utilisateur permettant la mise en réplication doit être créé sur ce nœud, avec le mot de passe renseigné dans la configuration de Patroni : + +```Bash + $ sudo ssh pg-1 "sudo systemctl enable --now patroni@14-main" +``` + +##### Création de l'utilisateur de réplication + +```Bash + $ sudo ssh pg-1 "sudo -iu postgres psql -c \"create user replicator replication + password 'rep-pass'\" " +``` + +##### Suppression des instances secondaires + +Les instances secondaires ont été initialisées lors de l'installation du paquet Debian, il faut donc vider leur répertoire de données :. + + +`pg-1` étant notre primaire : + +```Bash + $ for node in pg-2 pg-3; do + sudo ssh $node "rm -rf /var/lib/postgresql/14/main/*" +done +``` + +Les secondaires seront recréés automatiquement depuis le primaire par Patroni. + +##### Démarrage des instances secondaires + +Nous pouvons raccrocher nos secondaires en démarrant les deux instances : + +```Bash + $ for node in pg-2 pg-3; do + sudo ssh $node "systemctl start patroni@14-main" + done +``` + +
+ +--- + +##### Vérifications + +
+ + * Liste des nœuds Patroni + * Test de bascule manuelle vers chaque nœud + +
+ +
+ +###### Liste des nœuds Patroni + +Sur chaque nœud Patroni, modifier le `.profile` de l'utilisateur `postgres` en ajoutant : + +```Bash +export PATRONICTL_CONFIG_FILE=/etc/patroni/14-main.yml +``` + + +```Bash + $ sudo ssh pg-1 sudo -iu postgres patronictl list +``` +```console + + Cluster: 14-main (7029596050496494965) -+----+-----------+ + | Member | Host | Role | State | TL | Lag in MB | + +--------+------------+---------+---------+----+-----------+ + | pg-1 | 10.0.3.201 | Leader | running | 3 | | + | pg-2 | 10.0.3.202 | Replica | running | 3 | 0 | + | pg-3 | 10.0.3.203 | Replica | running | 3 | 0 | +``` + +###### Test de bascule manuelle vers chaque nœud + +```Bash + $ sudo ssh pg-1 sudo -iu postgres patronictl switchover +``` +```console +Master [pg-1]: +Candidate ['pg-2', 'pg-3'] []: pg-2 +When should the switchover take place (e.g. 2021-11-12T12:21 ) [now]: +Current cluster topology ++ Cluster: 14-main (7029596050496494965) -+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------+------------+---------+---------+----+-----------+ +| pg-1 | 10.0.3.201 | Leader | running | 3 | | +| pg-2 | 10.0.3.202 | Replica | running | 3 | 0 | +| pg-3 | 10.0.3.203 | Replica | running | 3 | 0 | ++--------+------------+---------+---------+----+-----------+ +Are you sure you want to switchover cluster 14-main, demoting current master +pg-1? [y/N]: y +2021-11-12 11:21:20.08091 Successfully switched over to "pg-2" ++ Cluster: 14-main (7029596050496494965) -+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------+------------+---------+---------+----+-----------+ +| pg-1 | 10.0.3.201 | Replica | stopped | | unknown | +| pg-2 | 10.0.3.202 | Leader | running | 3 | | +| pg-3 | 10.0.3.203 | Replica | running | 3 | 0 | ++--------+------------+---------+---------+----+-----------+ +``` + +
+ +--- + +## Création d'incidents + +
+ + * Perte totale du DCS + * Freeze du nœud primaire Patroni + * Bascule manuelle + +
+ +
+ + +
+ +--- + +### Perte totale du DCS + +
+ + * Perte de tous les nœuds Etcd + +
+ +
+ +Nous simulons un incident majeur au niveau du _DCS_ : + +```Bash + $ for node in e1 e2 e3; do + sudo lxc-freeze $node +done +``` + +La commande classique `patronictl list` échoue faute de _DCS_ pour la renseigner. + +Nous interrogeons directement sur les instances : + +```Bash + $ for node in pg-1 pg-2 pg-3; do +echo "$node :" +sudo ssh $node "sudo -iu postgres psql -c 'select pg_is_in_recovery()'" +done +``` +```console +pg-1 : + pg_is_in_recovery +------------------- + t +(1 ligne) + +pg-2 : + pg_is_in_recovery +------------------- + t +(1 ligne) + +pg-3 : + pg_is_in_recovery +------------------- + t +(1 ligne) +``` + +Nous constatons que l'intégralité des nœuds est passée en lecture seule (_stand-by_). + +Nous débloquons la situation : + +```Bash + $ for node in e1 e2 e3; do +echo "$node :" +sudo lxc-unfreeze $node +done +``` + +Nous pouvons observer le retour à la normale : + +```Bash + postgres@pg-1:~$ patronictl list -ew 1 +``` + +
+ +--- + +### Perte du nœud primaire Patroni + +
+ + * Perte du primaire courant + +
+ +
+ + +Dans un autre terminal, nous observons l'état de l'agrégat sur le nœud `pg-2` : + +```Bash + postgres@pg-2:~$ patronictl list -ew 1 +``` + +Nous simulons une perte du primaire `pg-1` : + +```Bash + $ sudo lxc-freeze pg-1 +``` + +Nous observons la disparition de `pg-1` de la liste des nœuds et une bascule automatique se déclenche vers un des nœuds secondaires disponibles : + +```console ++ Cluster: 14-main (7029596050496494965) -+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------+------------+---------+---------+----+-----------+ +| pg-2 | 10.0.3.202 | Replica | running | 7 | 0 | +| pg-3 | 10.0.3.203 | Leader | running | 7 | | ++--------+------------+---------+---------+----+-----------+ +``` + +Nous rétablissons la situation : + +```Bash +$ sudo lxc-unfreeze pg-1 + +``` + +```console ++ Cluster: 14-main (7029596050496494965) -+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------+------------+---------+---------+----+-----------+ +| pg-1 | 10.0.3.201 | Replica | running | 6 | 0 | +| pg-2 | 10.0.3.202 | Replica | running | 7 | 0 | +| pg-3 | 10.0.3.203 | Leader | running | 7 | | ++--------+------------+---------+---------+----+-----------+ +``` + +Pour un retour à l'état nominal, il suffit de procéder à une bascule manuelle (adapter la commande si votre primaire n'est pas `pg-3`) : + +```Bash +postgres@pg-1:~$ patronictl switchover --master pg-3 --candidate pg-1 --force +``` +```console +Current cluster topology ++ Cluster: 14-main (7029596050496494965) -+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------+------------+---------+---------+----+-----------+ +| pg-1 | 10.0.3.201 | Replica | running | 7 | 0 | +| pg-2 | 10.0.3.202 | Replica | running | 7 | 0 | +| pg-3 | 10.0.3.203 | Leader | running | 7 | | ++--------+------------+---------+---------+----+-----------+ +2021-11-12 13:18:36.05884 Successfully switched over to "pg-1" ++ Cluster: 14-main (7029596050496494965) -+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------+------------+---------+---------+----+-----------+ +| pg-1 | 10.0.3.201 | Leader | running | 7 | | +| pg-2 | 10.0.3.202 | Replica | running | 7 | 0 | +| pg-3 | 10.0.3.203 | Replica | stopped | | unknown | ++--------+------------+---------+---------+----+-----------+ +``` + +
+ +--- + + + +## Modification de la configuration + +
+ + * patronictl edit-config + +
+ +
+ +L'un des avantages de bénéficier d'une configuration distribuée est qu'il est possible de modifier cette configuration pour tous les nœuds en une seule opération. + +Si le paramètre nécessite un rechargement de la configuration, elle sera lancée sur chaque nœud. + +Si la modification nécessite un redémarrage, l' drapeau _pending restart_ sera positionné sur toutes les instances et attendrons une action de votre part pour l'effectuer. + +L'installation de la commande `less` est un pré-requis : + +```Bash + $ for i in pg-1 pg-2 pg-3; do apt install less done + ... +``` + +La modification peut se faire sur n'importe quel nœud : + +```Bash +postgres@pg-2:~$ patronictl edit-config +``` + +Nous ajoutons une ligne fille de la ligne ` parameters:` + +```yaml +loop_wait: 10 +maximum_lag_on_failover: 1048576 +postgresql: + parameters: + max_connections: 123 + ... +``` + +Une confirmation est demandée après la sortie de l'éditeur : + +```console +patronictl edit-config +--- ++++ +@@ -1,7 +1,8 @@ + loop_wait: 10 + maximum_lag_on_failover: 1048576 + postgresql: +- parameters: null ++ parameters: ++ max_connections: 123 + pg_hba: + - local all all peer + - host all all 127.0.0.1/32 md5 + +Apply these changes? [y/N]: y +Configuration changed +``` + +Après modification, il convient de regarder si notre modification ne nécessite pas de redémarrage : + +```Bash +postgres@pg-2:~$ patronictl list -e +``` +```console ++ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+ +| Member | Host | Role | State | TL | Lag in MB | Pending restart | ++--------+------------+---------+---------+----+-----------+-----------------+ +| pg-1 | 10.0.3.201 | Leader | running | 8 | | * | +| pg-2 | 10.0.3.202 | Replica | running | 8 | 0 | * | +| pg-3 | 10.0.3.203 | Replica | running | 8 | 0 | * | ++--------+------------+---------+---------+----+-----------+-----------------+ +``` + +Dans notre cas, un redémarrage de toutes les instances est nécessaire : + +```Bash +postgres@pg-2:~$ patronictl restart 14-main +``` +```console ++ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+ +| Member | Host | Role | State | TL | Lag in MB | Pending restart | ++--------+------------+---------+---------+----+-----------+-----------------+ +| pg-1 | 10.0.3.201 | Leader | running | 8 | | * | +| pg-2 | 10.0.3.202 | Replica | running | 8 | 0 | * | +| pg-3 | 10.0.3.203 | Replica | running | 8 | 0 | * | ++--------+------------+---------+---------+----+-----------+-----------------+ +When should the restart take place (e.g. 2021-11-12T14:37) [now]: +Are you sure you want to restart members pg-3, pg-2, pg-1? [y/N]: y +Restart if the PostgreSQL version is less than provided (e.g. 9.5.2) []: +Success: restart on member pg-3 +Success: restart on member pg-2 +Success: restart on member pg-1 +``` + + + +```Bash +postgres@pg-2:~$ patronictl list -e +``` +```console ++ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+ +| Member | Host | Role | State | TL | Lag in MB | Pending restart | ++--------+------------+---------+---------+----+-----------+-----------------+ +| pg-1 | 10.0.3.201 | Leader | running | 8 | | | +| pg-2 | 10.0.3.202 | Replica | running | 8 | 0 | | +| pg-3 | 10.0.3.203 | Replica | running | 8 | 0 | | ++--------+------------+---------+---------+----+-----------+-----------------+ +``` + +```Bash + $ for node in pg-1 pg-2 pg-3; do + echo "$node :" + sudo ssh $node "sudo -iu postgres psql -c 'show max_connections'" + done +``` +```console +pg-1 : + max_connections +----------------- + 123 +(1 ligne) + +pg-2 : + max_connections +----------------- + 123 +(1 ligne) + +pg-3 : + max_connections +----------------- + 123 +(1 ligne) +``` + + +L'application d'un paramètre qui ne nécessite pas de redémarrage est transparente, le rechargement de la configuration sur tous les nœuds est automatiquement déclenchée par Patroni. + +
+ +--- + +## Sauvegardes + +
+ + * Installation pgBackrest + * Configuration + * Détermination du primaire + * Archivage + * Sauvegarde + +
+ + +
+ +### Détermination du primaire + +Nous proposons de déclencher la sauvegarde sur le primaire courant, il faut donc d'abord l'identifier. + +Le script suivant est une solution permettant de récupérer le primaire de notre agrégat à partir d'un nœud Etcd ezt de l'API mise à disposition : + +```Bash +#! /bin/bash +SCOPE=$(grep -i scope: /etc/patroni/14-main.yml | cut -d '"' -f 2) +curl -s http://e1:2379/v2/keys/postgresql-common/"$SCOPE"/leader | jq -r .node.value +``` + +### Configuration de pgBackrest + +Sur chacun des nœuds, il faut configurer le _stanza_ et l'initialiser : + +```ini +# /etc/pgbackrest.conf +[main] +pg1-path=/var/lib/postgresql/14/main +pg1-socket-path=/var/run/postgresql +pg1-port=5432 + +[global] +log-level-file=detail +log-level-console=detail +repo1-host=backup +repo1-host-user=postgres + +``` + +Tous les nœuds doivent permettre la connexion _ssh_ sans mot de passe, le _playbook_ _Ansible_ nommé `exchange_ssh_keys` permet de faire ce travail rapidement : + +```Bash + $ sudo ansible-playbook -i inventory.yml exchange_ssh_keys.yml -f 7 +``` + +Nous pouvons alors tenter de créer le _stanza_ sur le primaire : + +```Bash +postgres@pg-1:~$ pgbackrest --stanza main stanza-create +postgres@pg-1:/var/lib/pgbackrest$ pgbackrest --stanza main check +ERROR: [087]: archive_mode must be enabled +``` + +#### Configuration de l'archivage + +Toutes les instances doivent être en mesure d'archiver leurs journaux de transactions au moyen de pgBackrest : + +```Bash +postgres@pg-1:~$ patronictl edit-config +``` +```yaml +postgresql: + parameters: + max_connections: 123 + archive_mode: 'on' + archive_command: pgbackrest --stanza=main archive-push %p +``` + +Notre configuration n'a pas encore été appliquée sur les instances car un redémarrage est requis : + +```Bash +postgres@pg-1:~$ patronictl list -e +``` +```console ++ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+ +| Member | Host | Role | State | TL | Lag in MB | Pending restart | ++--------+------------+---------+---------+----+-----------+-----------------+ +| pg-1 | 10.0.3.201 | Leader | running | 8 | | * | +| pg-2 | 10.0.3.202 | Replica | running | 8 | 0 | * | +| pg-3 | 10.0.3.203 | Replica | running | 8 | 0 | * | ++--------+------------+---------+---------+----+-----------+-----------------+ +``` + +```Bash +postgres@pg-1:~$ patronictl restart 14-main --force ++ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+ +| Member | Host | Role | State | TL | Lag in MB | Pending restart | ++--------+------------+---------+---------+----+-----------+-----------------+ +| pg-1 | 10.0.3.201 | Leader | running | 8 | | * | +| pg-2 | 10.0.3.202 | Replica | running | 8 | 0 | * | +| pg-3 | 10.0.3.203 | Replica | running | 8 | 0 | * | ++--------+------------+---------+---------+----+-----------+-----------------+ +Success: restart on member pg-1 +Success: restart on member pg-3 +Success: restart on member pg-2 +``` + +Test de la configuration de l'archivage sur le nœud `pg-1` : + +```Bash +postgres@pg-1:~$ pgbackrest --stanza main --log-level-console detail check +``` +```console +2021-11-12 15:57:04.000 P00 INFO: check command begin 2.35: --exec-id=13216- +4a7c4a92 --log-level-console=detail --log-level-file=detail --pg1-path=/var/lib/ +postgresql/14/main --pg1-port=5432 --pg1-socket-path=/var/run/postgresql -- +repo1-host=backup --repo1-host-user=postgres --stanza=main +2021-11-12 15:57:04.616 P00 INFO: check repo1 configuration (primary) +2021-11-12 15:57:05.083 P00 INFO: check repo1 archive for WAL (primary) +2021-11-12 15:57:08.425 P00 INFO: WAL segment 000000080000000000000005 +successfully archived to '/var/lib/pgbackrest/archive/main/14-1/ +0000000800000000/000000080000000000000005- +b0929d740c7996974992ecd7b9b189b37d06a896.gz' on repo1 +2021-11-12 15:57:08.528 P00 INFO: check command end: completed successfully +(4531ms) +``` + +#### Configuration sur la machine hébergeant les sauvegardes + +Sur la machine `backup`, créer le script de détermination du _leader_ (le rendre exécutable) : + +```Bash +postgres@backup:~$ vim ~/leader.sh && chmod +x leader.sh +``` + + +```Bash +#! /bin/bash +SCOPE='14-main' +curl -s http://e1:2379/v2/keys/postgresql-common/"$SCOPE"/leader | jq -r .node.value +``` + +##### Configuration de pgBackrest + +La configuration se fait dans le fichier `/etc/pgbackrest.conf` : + +```ini +[global] +repo1-path=/var/lib/pgbackrest +repo1-retention-full=2 +start-fast=y +log-level-console=detail + +[main] +pg1-path=/var/lib/postgresql/14/main +pg1-host-user=postgres +pg1-user=postgres +pg1-port=5432 +``` + +##### test d'une sauvegarde + +```Bash +postgres@backup:~$ pgbackrest --stanza main --pg1-host=$(./leader.sh) backup +--type=full +``` +```console +2021-11-12 16:32:32.128 P00 INFO: backup command begin 2.35: --exec-id=6717- +e7512f6c --log-level-console=detail --pg1-host=pg-1 --pg1-host-user=postgres -- +pg1-path=/var/lib/postgresql/14/main --pg1-port=5432 --pg1-user=postgres -- +repo1-path=/var/lib/pgbackrest --repo1-retention-full=2 --stanza=main --start- +fast --type=full +2021-11-12 16:32:33.114 P00 INFO: execute non-exclusive pg_start_backup(): +backup begins after the requested immediate checkpoint completes +2021-11-12 16:32:34.129 P00 INFO: backup start archive = +00000008000000000000000B, lsn = 0/B000028 +2021-11-12 16:32:36.709 P01 DETAIL: backup file pg-1:/var/lib/postgresql/14/ +main/base/13707/1255 (752KB, 2%) checksum +2bac9bc6e62f6059736f9152a045bb43c0832231 +2021-11-12 16:32:37.119 P01 DETAIL: backup file pg-1:/var/lib/postgresql/14/ +main/base/13706/1255 (752KB, 5%) checksum +2bac9bc6e62f6059736f9152a045bb43c0832231 +... +... +2021-11-12 16:32:45.786 P01 DETAIL: backup file pg-1:/var/lib/postgresql/14/ +main/base/1/13528 (0B, 100%) +2021-11-12 16:32:45.791 P00 INFO: execute non-exclusive pg_stop_backup() and +wait for all WAL segments to archive +2021-11-12 16:32:46.095 P00 INFO: backup stop archive = +00000008000000000000000B, lsn = 0/B000138 +2021-11-12 16:32:46.101 P00 DETAIL: wrote 'backup_label' file returned from +pg_stop_backup() +2021-11-12 16:32:46.103 P00 INFO: check archive for segment(s) +00000008000000000000000B:00000008000000000000000B +2021-11-12 16:32:49.611 P00 INFO: new backup label = 20211112-163233F +2021-11-12 16:32:49.673 P00 INFO: full backup size = 25.1MB, file total = 952 +2021-11-12 16:32:49.674 P00 INFO: backup command end: completed successfully +(17556ms) +2021-11-12 16:32:49.675 P00 INFO: expire command begin 2.35: --exec-id=6717- +e7512f6c --log-level-console=detail --repo1-path=/var/lib/pgbackrest --repo1- +retention-full=2 --stanza=main +2021-11-12 16:32:49.686 P00 INFO: expire command end: completed successfully +(11ms) +``` + +Vérification de l'état de la sauvegarde : + +```Bash +postgres@backup:~$ pgbackrest --stanza main info +``` +```console +stanza: main + status: ok + cipher: none + + db (current) + wal archive min/max (14): 000000010000000000000001/00000008000000000000000B + + full backup: 20211112-163233F + timestamp start/stop: 2021-11-12 16:32:33 / 2021-11-12 16:32:45 + wal start/stop: 00000008000000000000000B / 00000008000000000000000B + database size: 25.1MB, database backup size: 25.1MB + repo1: backup set size: 3.2MB, backup size: 3.2MB +``` + +
+ +--- + +## Références + +
+ + * Etcd : + * Patroni : + * Dalibo : + +
+ +
+ +
+ +--- diff --git a/fr/patroni/_archives/pgs14/patroni.nocover.pdf b/fr/patroni/_archives/pgs14/patroni.nocover.pdf new file mode 100644 index 0000000..0abbddf Binary files /dev/null and b/fr/patroni/_archives/pgs14/patroni.nocover.pdf differ diff --git a/fr/patroni/_archives/pgs14/patroni.odt b/fr/patroni/_archives/pgs14/patroni.odt new file mode 100644 index 0000000..a6ed31d Binary files /dev/null and b/fr/patroni/_archives/pgs14/patroni.odt differ diff --git a/fr/patroni/_archives/pgs14/patroni.pdf b/fr/patroni/_archives/pgs14/patroni.pdf new file mode 100644 index 0000000..18ef771 Binary files /dev/null and b/fr/patroni/_archives/pgs14/patroni.pdf differ diff --git a/fr/patroni/_archives/pgs14/patroni.slides.html b/fr/patroni/_archives/pgs14/patroni.slides.html new file mode 100644 index 0000000..7a2aead --- /dev/null +++ b/fr/patroni/_archives/pgs14/patroni.slides.html @@ -0,0 +1,7253 @@ + + + + + + + + Haute disponibilité de service - Patroni + + + + + + + + + + + + + + + +
+
+ +
+

Haute disponibilité de service - Patroni

+

Workshop Patroni

+

Dalibo & Contributors

+
+ + +
+

Haute disponibilité de service avec Patroni

+
+PostgreSQL + +
+ +
+
+ +

Introduction

+
+
    +
  • Principes
  • +
  • Mise en place
  • +
  • Installation et configuration des services
  • +
  • Construction d’un agrégat à bascule automatique
  • +
  • Création d’incidents
  • +
+
+ +
+
+ +

Principes

+
+
    +
  • Arbitrage par un quorum : DCS Etcd
  • +
  • Service PostgreSQL : désactivé
  • +
  • Contrôle complet par Patroni
  • +
+
+ +
+
+ +

DCS : Etcd

+
+
    +
  • Arbitre en cas de bascules
  • +
  • Stockage distribué de la configuration
  • +
  • Jeton leader (Etcd)
  • +
  • Instance primaire PostgreSQL
  • +
+
+ +
+
+ +

Service PostgreSQL et +Patroni

+
+
    +
  • Service PostgreSQL désactivé
  • +
+
+ +
+
+ +

Mise en place de +l’infrastructure

+
+
    +
  • Connexion à la VM
  • +
  • Récupération du playbook Ansible
  • +
+
+ +
+
+ +

Connexion à votre machine +virtuelle

+
+

un seul point d’entrée : eformation.dalibo.com un port +attribué : 22XX

+
  $ ssh -p 22XX dalibo@eformation.dalibo.com
+
+ +
+
+ +

Playbook Ansible

+
+

Récupération du playbook Ansible à cette +adresse :

+

https://github.com/dalibo/workshops/tree/workshop_patroni/fr/patroni/playbook/etcd-patroni

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FichierDescription
inventory.ymlinventaire des machines
setup.ymlplaybook principal
warmup.shscript d’amorçage
exchange_ssh_keys.ymlplaybook d’échange de clés +ssh
teardown.ymlplaybook de destruction +massive
+
+ +
+
+ +
+

L’infrastructure complète peut être créée à l’aide des +commandes :

+
 $ sudo apt install -y ansible
+ $ sudo ansible-playbook -f 7 -i inventory.yml setup.yml
+...
+

Cette opération peut durer jusqu’à une vingtaine de minutes.

+
+ +
+
+ +

Installation d’Etcd

+
+
    +
  • Installation des paquets
  • +
  • Configuration
  • +
  • Démarrage du service
  • +
  • Vérification
  • +
+
+ +
+
+ +

Installation des paquets

+
+
    +
  • Paquets essentiels : +
      +
    • etcd
    • +
    • curl
    • +
    • jq
    • +
    • iputils-ping
    • +
  • +
+
+ +
+
+ +

Configuration du service +Etcd

+
+
    +
  • Fichier : /etc/default/etcd
  • +
+
+ +
+
+ +

Démarrage du service

+
+
    +
  • Réinitialisation des bases Etcd
  • +
  • Démarrage du service etcd +
      +
    • systemctl start etcd
    • +
  • +
+
+ +
+
+ +

Installation de PostgreSQL / +Patroni

+
+
    +
  • Installation +
      +
    • PostgreSQL
    • +
    • Patroni
    • +
    • pgBackrest
    • +
  • +
+
+ +
+
+ +

Configuration de Patroni

+
+

Sur tous les nœuds

+
    +
  • Configuration du DCS +
      +
    • /etc/patroni/dcs.yml
    • +
  • +
  • Génération de la configuration +
      +
    • pg_createconfig_patroni 14 main
    • +
  • +
+
+ +
+
+ +

Création de l’agrégat

+
+
    +
  • Démarrage du primaire
  • +
  • Création de l’utilisateur de réplication
  • +
  • Suppression des instances secondaires
  • +
  • Démarrage des instances secondaires
  • +
+
+ +
+
+ +
Vérifications
+
+
    +
  • Liste des nœuds Patroni
  • +
  • Test de bascule manuelle vers chaque nœud
  • +
+
+ +
+
+ +

Création d’incidents

+
+
    +
  • Perte totale du DCS
  • +
  • Freeze du nœud primaire Patroni
  • +
  • Bascule manuelle
  • +
+
+ +
+
+ +

Perte totale du DCS

+
+
    +
  • Perte de tous les nœuds Etcd
  • +
+
+ +
+
+ +

Perte du nœud primaire +Patroni

+
+
    +
  • Perte du primaire courant
  • +
+
+ +
+
+ +

Modification de la +configuration

+
+
    +
  • patronictl edit-config
  • +
+
+ +
+
+ +

Sauvegardes

+
+
    +
  • Installation pgBackrest
  • +
  • Configuration
  • +
  • Détermination du primaire
  • +
  • Archivage
  • +
  • Sauvegarde
  • +
+
+ +
+
+ +

Références

+ + +
+
+ +
+
+
+ + + + + + + + + + diff --git a/fr/patroni/patroni.epub b/fr/patroni/patroni.epub new file mode 100644 index 0000000..a979941 Binary files /dev/null and b/fr/patroni/patroni.epub differ diff --git a/fr/patroni/patroni.handout.html b/fr/patroni/patroni.handout.html new file mode 100644 index 0000000..8e9bf88 --- /dev/null +++ b/fr/patroni/patroni.handout.html @@ -0,0 +1,36041 @@ + + + + + + + Haute disponibilité avec Patroni + + + + + + + + + + + + + Haute disponibilité avec Patroni + + + + + + + + +
+ +
+
+

Haute disponibilité +avec Patroni

+

+ Révision 19.02 (février 2023) +

+

Dalibo +& Contributors

+
+
+ +
+ +
+

Haute disponibilité +de service avec Patroni

+
+PostgreSQL + +
+
+ +
+
+

Introduction

+
+
    +
  • Principes
  • +
  • Mise en place
  • +
  • Installation et configuration des services
  • +
  • Construction d’un agrégat à bascule automatique
  • +
  • Création d’incidents
  • +
+
+
+ +
+
+

Principes

+
+
    +
  • Arbitrage par un quorum : DCS Etcd
  • +
  • Service PostgreSQL : désactivé
  • +
  • Contrôle complet par Patroni
  • +
+
+
+ +
+
+

DCS : Etcd

+
+
    +
  • Arbitre en cas de bascules
  • +
  • Stockage distribué de la configuration
  • +
  • Jeton leader (Etcd)
  • +
  • Instance primaire PostgreSQL
  • +
+
+
+

Pour arbitrer les bascules automatiques, confirmer le primaire +PostgreSQL ou distribuer la configuration, Patroni utilise un +DCS (distributed configuration system).

+

Pour ce rôle, nous utiliserons Etcd.

+
+
+

Mise en place de +l’infrastructure

+
+
    +
  • Connexion à la VM
  • +
  • Récupération du playbook Ansible
  • +
+
+
+

Vous disposez d’une machine virtuelle dédiée dans laquelle nous +construirons 7 conteneurs lxc :

+
    +
  • 3 Etcd
  • +
  • 3 Patroni
  • +
  • 1 backup optionnel : (sauvegardes, archivage)
  • +
+
+
+

Connexion à votre machine +virtuelle

+
+

un seul point d’entrée : eformation.dalibo.com un port +attribué : 22XX

+
  $ ssh -p 22XX dalibo@eformation.dalibo.com
+
+
+

Exemple de configuration pour une connexion simplifiée :

+

+# .ssh/config
+
+Host vm38
+Hostname eformation.dalibo.com
+User dalibo
+port 2238
+
+
 $ ssh vm38
+
Last login: Wed Nov 10 13:23:26 2021 from 78.213.160.12
+dalibo@vm38:~$ 
+
+
+

Playbook Ansible

+
+

Récupération du playbook Ansible à cette +adresse :

+

https://github.com/dalibo/workshops/tree/ws15_patroni/fr/patroni/playbook/etcd-patroni

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FichierDescription
inventory.ymlinventaire des machines
setup.ymlplaybook +principal
exchange_ssh_keys.ymléchange des clefs ssh
demarre_tout.shdémarre tous les conteneurs
stoppe_tout.sharrête tous les conteneurs
teardown.ymlplaybook de destruction +massive
+
+
+

Quatre fichiers Yaml, deux scripts shell.

+
+
+
+

L’infrastructure complète peut être créée à l’aide des +commandes :

+
 $ sudo apt install -y ansible
+ $ sudo ansible-playbook -f 7 -i inventory.yml setup.yml
+...
+

Cette opération peut durer jusqu’à une vingtaine de minutes.

+
+
+

Vous pouvez suivre l’évolution de la création des conteneurs dans un +autre terminal :

+
 $ watch -n 1 -d sudo lxc-ls -f
+
 $ sudo lxc-ls -f
+ NAME   STATE   AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED 
+ backup STOPPED 0         -      -    -    false        
+ e1     STOPPED 0         -      -    -    false        
+ e2     STOPPED 0         -      -    -    false        
+ e3     STOPPED 0         -      -    -    false        
+ pg-1   STOPPED 0         -      -    -    false        
+ pg-2   STOPPED 0         -      -    -    false        
+ pg-3   STOPPED 0         -      -    -    false
+

L’état final de chaque conteneur étant RUNNING avec une +adresse IPV4 attribuée :

+
 $ sudo lxc-ls -f
+ NAME   STATE   AUTOSTART GROUPS IPV4       IPV6 UNPRIVILEGED
+ backup RUNNING 0         -      10.0.3.204 -    false
+ e1     RUNNING 0         -      10.0.3.101 -    false
+ e2     RUNNING 0         -      10.0.3.102 -    false
+ e3     RUNNING 0         -      10.0.3.103 -    false
+ pg-1   RUNNING 0         -      10.0.3.201 -    false
+ pg-2   RUNNING 0         -      10.0.3.202 -    false
+ pg-3   RUNNING 0         -      10.0.3.203 -    false
+
+

Sur toutes les machines, y compris l’hôte, le fichier +/etc/hosts est automatiquement renseigné par le +playbook et devrait contenir au moins :

+
10.0.3.101 e1
+10.0.3.102 e2
+10.0.3.103 e3
+10.0.3.201 pg-1
+10.0.3.202 pg-2
+10.0.3.203 pg-3
+10.0.3.204 backup 
+
+
+

Installation d’Etcd

+
+
    +
  • Installation des paquets
  • +
  • Configuration
  • +
  • Démarrage du service
  • +
  • Vérification
  • +
+
+
+ +
+
+

Installation des +paquets

+
+
    +
  • Paquets essentiels : +
      +
    • etcd
    • +
    • curl
    • +
    • jq
    • +
    • iputils-ping
    • +
  • +
+
+
+
 $ for node in e1 e2 e3; do 
+ sudo ssh $node sudo apt-get install -qqy etcd curl iputils-ping jq
+ done
+

Le démarrage du service est automatique sous Debian.

+
 $ for node in e1 e2 e3; do
+ sudo ssh $node  "systemctl status etcd | grep -i active"
+ done
+ 
+
   Active: active (running) since Wed 2021-11-10 17:48:26 UTC; 3min 28s ago
+   Active: active (running) since Wed 2021-11-10 17:48:36 UTC; 3min 18s ago
+   Active: active (running) since Wed 2021-11-10 17:48:46 UTC; 3min 8s ago
+

Vérification de l’état des nœuds

+
$ for node in e1 e2 e3; do  
+sudo ssh $node etcdctl member list
+done
+
8e9e05c52164694d: name=e1 peerURLs=http://localhost:2380 
+clientURLs=http://localhost:2379 isLeader=true
+8e9e05c52164694d: name=e2 peerURLs=http://localhost:2380 
+clientURLs=http://localhost:2379 isLeader=true
+8e9e05c52164694d: name=e3 peerURLs=http://localhost:2380 
+clientURLs=http://localhost:2379 isLeader=true
+

Les nœuds sont tous des leaders indépendants, ce qui ne nous +intéresse pas. Il faut donc les configurer pour qu’ils fonctionnent en +collaboration.

+

Nous arrêtons donc les services :

+
 $ for node in e1 e2 e3; do
+sudo ssh $node "systemctl stop etcd && systemctl status etcd | grep -i active"
+done
+
 Active: inactive (dead) since Wed 2021-11-10 17:59:35 UTC; 2min 46s ago
+ Active: inactive (dead) since Wed 2021-11-10 17:59:35 UTC; 2min 46s ago
+ Active: inactive (dead) since Wed 2021-11-10 17:59:35 UTC; 2min 46s ago
+
+
+

Configuration du service +Etcd

+
+
    +
  • Fichier : /etc/default/etcd
  • +
+
+
+

La configuration du service Etcd se trouve dans le fichier +/etc/default/etcd, elle doit décrire notre agrégat sur +chaque nœud :

+ +
+
+

Attention aux caractères invisibles ou aux sauts de ligne

+
+
+

Sur le nœud e1 :

+
ETCD_NAME='e1'
+
+ETCD_DATA_DIR='/var/lib/etcd/default'
+
+ETCD_LISTEN_PEER_URLS='http://127.0.0.1:2380,http://10.0.3.101:2380'
+ETCD_LISTEN_CLIENT_URLS='http://127.0.0.1:2379,http://10.0.3.101:2379'
+ETCD_INITIAL_ADVERTISE_PEER_URLS='http://10.0.3.101:2380'
+
+ETCD_INITIAL_CLUSTER_STATE='new'
+ETCD_INITIAL_CLUSTER_TOKEN='etcd-cluster'
+
+ETCD_INITIAL_CLUSTER='e1=http://10.0.3.101:2380,e2=http://10.0.3.102:2380,e3=http://10.0.3.103:2380'
+
+ETCD_ADVERTISE_CLIENT_URLS='http://10.0.3.101:2379'
+
+ETCD_ENABLE_V2=true
+

Sur le nœud e2 :

+
ETCD_NAME='e2'
+
+ETCD_DATA_DIR='/var/lib/etcd/default'
+
+ETCD_LISTEN_PEER_URLS='http://127.0.0.1:2380,http://10.0.3.102:2380'
+ETCD_LISTEN_CLIENT_URLS='http://127.0.0.1:2379,http://10.0.3.102:2379'
+ETCD_INITIAL_ADVERTISE_PEER_URLS='http://10.0.3.102:2380'
+
+ETCD_INITIAL_CLUSTER_STATE='new'
+ETCD_INITIAL_CLUSTER_TOKEN='etcd-cluster'
+
+ETCD_INITIAL_CLUSTER='e1=http://10.0.3.101:2380,e2=http://10.0.3.102:2380,e3=http://10.0.3.103:2380'
+
+ETCD_ADVERTISE_CLIENT_URLS='http://10.0.3.102:2379'
+
+ETCD_ENABLE_V2=true
+

Sur le nœud e3 :

+
ETCD_NAME='e3'
+
+ETCD_DATA_DIR='/var/lib/etcd/default'
+
+ETCD_LISTEN_PEER_URLS='http://127.0.0.1:2380,http://10.0.3.103:2380'
+ETCD_LISTEN_CLIENT_URLS='http://127.0.0.1:2379,http://10.0.3.103:2379'
+ETCD_INITIAL_ADVERTISE_PEER_URLS='http://10.0.3.103:2380'
+
+ETCD_INITIAL_CLUSTER_STATE='new'
+ETCD_INITIAL_CLUSTER_TOKEN='etcd-cluster'
+
+ETCD_INITIAL_CLUSTER='e1=http://10.0.3.101:2380,e2=http://10.0.3.102:2380,e3=http://10.0.3.103:2380'
+
+ETCD_ADVERTISE_CLIENT_URLS='http://10.0.3.103:2379'
+
+ETCD_ENABLE_V2=true
+
+
+

Démarrage du service

+
+
    +
  • Réinitialisation des bases Etcd
  • +
  • Démarrage du service etcd : +systemctl start etcd
  • +
+
+
+

Avant de démarrer le service sur chaque nœud, il faut réinitialiser +les répertoires de données des nœuds, afin qu’ils reparte sur un +répertoire neuf.

+

Le nœud e1, que nous considérons comme premier +leader sera démarré en premier mais il est possible qu’un autre +nœud prenne le dessus s’il arrive à démarrer plus vite :

+
 $ for node in e1 e2 e3; do 
+ echo "$node :" ; sudo ssh $node "rm -rf ~etcd/default/*"
+ done
+
 $ for node in e1 e2 e3; do 
+ sudo ssh $node "systemctl start etcd" &
+ sleep 1
+ done
+

En cas d’échec de démarrage, utilisez la commande Systemd +pour en diagnostiquer la cause :

+
 e1:~$ sudo journalctl -xfu etcd
+

Vérification :

+
 $ for node in e1 e2 e3; do 
+ echo "sur $node :" 
+ sudo ssh $node "etcdctl member list"
+done
+
sur e1 :
+736293150f1cffb7: name=e1 peerURLs=http://10.0.3.101:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=true
+7ef9d5bb55cefbcc: name=e3 peerURLs=http://10.0.3.103:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=false
+97463691c7858a7b: name=e2 peerURLs=http://10.0.3.102:2380
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=false
+sur e2 :
+736293150f1cffb7: name=e1 peerURLs=http://10.0.3.101:2380
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=true
+7ef9d5bb55cefbcc: name=e3 peerURLs=http://10.0.3.103:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=false
+97463691c7858a7b: name=e2 peerURLs=http://10.0.3.102:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=false
+sur e3 :
+736293150f1cffb7: name=e1 peerURLs=http://10.0.3.101:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=true
+7ef9d5bb55cefbcc: name=e3 peerURLs=http://10.0.3.103:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=false
+97463691c7858a7b: name=e2 peerURLs=http://10.0.3.102:2380 
+clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=false
+
+
+

Le leader doit être identique sur les trois nœuds, les trois +nœuds doivent retourner la même liste de membres.

+
+
+

Installation de PostgreSQL / +Patroni

+
+
    +
  • Installation +
      +
    • PostgreSQL
    • +
    • Patroni
    • +
    • pgBackrest
    • +
  • +
+
+
+

Le dépôt pgdg est déjà préconfiguré dans les conteneurs +pg-1, pg-2 et pg-3, l’installation est donc triviale :

+
 $ for node in pg-1 pg-2 pg-3; do
+sudo ssh $node "apt-get update && apt-get install -qqy postgresql patroni pgbackrest" &
+done
+

Vérification :

+
 $ for node in pg-1 pg-2 pg-3; do sudo ssh $node "dpkg -l postgresql patroni 
+pgbackrest | grep ^ii | cut -d ' ' -f 1,3"; done
+ii patroni
+ii pgbackrest
+ii postgresql
+ii patroni
+ii pgbackrest
+ii postgresql
+ii patroni
+ii pgbackrest
+ii postgresql
+

Le service PostgreSQL doit être désactivé car la gestion totale de +l’instance sera déléguée à Patroni :

+
$ for node in pg-1 pg-2 pg-3; do 
+sudo ssh $node "systemctl disable --now postgresql@15-main"
+done
+
+
+

Configuration de +Patroni

+
+

Sur tous les nœuds PostgreSQL/Patroni

+
    +
  • Configuration du DCS +
      +
    • /etc/patroni/dcs.yml
    • +
  • +
  • Génération de la configuration +
      +
    • pg_createconfig_patroni 15 main
    • +
  • +
+
+
+

La configuration sous Debian se fait d’abord en renseignant comment +contacter le DCS, puis en lançant le script de génération automatique de +la configuration de Patroni.

+

Le port par défaut du service Etcd est le 2379.

+
$ sudo ssh pg-1
+root@pg-1:~# vim /etc/patroni/dcs.yml
+
# /etc/patroni/dcs.yml
+etcd:
+  hosts: 
+  - 10.0.3.101:2379
+  - 10.0.3.102:2379
+  - 10.0.3.103:2379
+
 root@pg-1:~# pg_createconfig_patroni 15 main"
+

La configuration /etc/patroni/15-main.yml est +générée.

+
+

Ces opérations doivent être répétées sur tous les nœuds +PostgreSQL/Patroni.

+
+

Création de +l’agrégat

+
+
    +
  • Démarrage du primaire
  • +
  • Création de l’utilisateur de réplication
  • +
  • Suppression des instances secondaires
  • +
  • Démarrage des instances secondaires
  • +
+
+
+
Démarrage du +primaire
+

La création de l’agrégat commence par la mise en route du primaire +sur le nœud pg-1, c’est lui qui sera la référence pour les +secondaires.

+
root@pg-1:~# systemctl enable --now patroni@15-main
+

L’instance doit être promue pour pouvoir être accessible +écriture :

+
root@pg-1:~# sudo -iu postgres psql -c 'select pg_promote();'' 
+

L’utilisateur permettant la mise en réplication doit être +créé sur ce nœud, avec le mot de passe renseigné dans la configuration +de Patroni :

+
root@pg-1:~# sudo -iu postgres psql -c "create user replicator replication password 'rep-pass';" 
+
Superuser +d’administration locale
+

Chaque nœud doit pouvoir récupérer la timeline et le +LSN courants

+
root@pg-1:~# sudo -iu postgres psql -c "create user dba superuser password 'admin'" 
+

Si l’utilisateur est différent de postgres, il faudra +désactiver le socket unix sinon Patroni essaiera la connexion locale +authentifiée par la méthode peer. L’utilisateur +dba n’existant pas au niveau système, il y aurait +échec.

+

La configuration de chaque nœud doit être modifiée :

+
#/etc/patroni/15-main.yaml
+
+postgresql:
+
+    #...
+
+ use_unix_socket: false
+
+ #...
+
+    superuser:
+      username: "dba"
+      password: "admin"
+      #...
+
Suppression des instances +secondaires
+

Les instances secondaires ont été initialisées lors de l’installation +du paquet Debian, il faut donc vider leur répertoire de données car +Patroni refusera d’écraser des données existantes. Nous utilisons le +wrapper Debian :

+

pg-1 étant notre primaire :

+
 $ for node in pg-2 pg-3; do sudo ssh  $node "pg_dropcluster 15 main"; done
+

Les secondaires seront recréés automatiquement par Patroni, depuis le +primaire par réplication.

+

Le primaire doit être redémarré :

+
postgres@pg-1:~ $ patronictl restart 15-main pg-1 --force
+

les nœuds secondaires doivent être démarrés :

+
$ for node in pg-2 pg-3; do sudo ssh $node "systemctl start patroni@15-main"; done
+

La vérification se fait dans les traces de Patroni des nœuds +secondaires :

+
Feb 09 17:12:38 pg-3 patroni@15-main[1029]: 2023-02-09 17:12:38,984 INFO: Lock owner: pg-1; I am pg-3
+Feb 09 17:12:38 pg-3 patroni@15-main[1029]: 2023-02-09 17:12:38,986 INFO: Local timeline=7 lsn=0/5000148
+Feb 09 17:12:39 pg-3 patroni@15-main[1029]: 2023-02-09 17:12:39,037 INFO: master_timeline=7
+
+
+
+
Vérifications
+
+
    +
  • Liste des nœuds Patroni
  • +
  • Test de bascule manuelle vers chaque nœud
  • +
+
+
+
Liste des nœuds +Patroni
+

Sur chaque nœud Patroni, modifier le .profile de +l’utilisateur postgres en ajoutant :

+
export PATRONICTL_CONFIG_FILE=/etc/patroni/15-main.yml
+
 $ sudo ssh pg-1 sudo -iu postgres patronictl list
+
 + Cluster: 15-main (7029596050496494965) -+----+-----------+
+ | Member | Host       | Role    | State   | TL | Lag in MB |
+ +--------+------------+---------+---------+----+-----------+
+ | pg-1   | 10.0.3.201 | Leader  | running |  3 |           |
+ | pg-2   | 10.0.3.202 | Replica | running |  3 |         0 |
+ | pg-3   | 10.0.3.203 | Replica | running |  3 |         0 |
+
Test de +bascule manuelle vers chaque nœud
+
 $ sudo ssh pg-1 sudo -iu postgres patronictl switchover
+
Master [pg-1]:
+Candidate ['pg-2', 'pg-3'] []: pg-2
+When should the switchover take place (e.g. 2021-11-12T12:21 )  [now]:                          
+Current cluster topology
++ Cluster: 15-main (7029596050496494965) -+----+-----------+                                    
+| Member | Host       | Role    | State   | TL | Lag in MB |                                    
++--------+------------+---------+---------+----+-----------+                                    
+| pg-1   | 10.0.3.201 | Leader  | running |  3 |           |                                    
+| pg-2   | 10.0.3.202 | Replica | running |  3 |         0 |                                    
+| pg-3   | 10.0.3.203 | Replica | running |  3 |         0 |                                    
++--------+------------+---------+---------+----+-----------+                                    
+Are you sure you want to switchover cluster 15-main, demoting current master 
+pg-1? [y/N]: y     
+2021-11-12 11:21:20.08091 Successfully switched over to "pg-2"                                  
++ Cluster: 15-main (7029596050496494965) -+----+-----------+                                    
+| Member | Host       | Role    | State   | TL | Lag in MB |                                    
++--------+------------+---------+---------+----+-----------+                                    
+| pg-1   | 10.0.3.201 | Replica | stopped |    |   unknown |                                    
+| pg-2   | 10.0.3.202 | Leader  | running |  3 |           |                                    
+| pg-3   | 10.0.3.203 | Replica | running |  3 |         0 |                                    
++--------+------------+---------+---------+----+-----------+
+
+
+

Création d’incidents

+
+
    +
  • Perte totale du DCS
  • +
  • Freeze du nœud primaire Patroni
  • +
  • Bascule manuelle
  • +
+
+
+ +
+
+

Perte totale du DCS

+
+
    +
  • Perte de tous les nœuds Etcd
  • +
+
+
+

Nous simulons un incident majeur au niveau du DCS :

+
 $ for node in e1 e2 e3; do
+  sudo lxc-freeze $node
+done
+

La commande classique patronictl list échoue faute de +DCS pour la renseigner.

+

Nous interrogeons directement sur les instances :

+
 $ for node in pg-1 pg-2 pg-3; do 
+echo "$node :"
+sudo ssh $node "sudo -iu postgres psql -c 'select pg_is_in_recovery()'"
+done
+
pg-1 :
+ pg_is_in_recovery 
+-------------------
+ t
+(1 ligne)
+
+pg-2 :
+ pg_is_in_recovery 
+-------------------
+ t
+(1 ligne)
+
+pg-3 :
+ pg_is_in_recovery 
+-------------------
+ t
+(1 ligne)
+

Nous constatons que l’intégralité des nœuds est passée en lecture +seule (stand-by).

+

Nous débloquons la situation :

+
 $ for node in e1 e2 e3; do 
+echo "$node :"
+sudo lxc-unfreeze $node
+done
+

Nous pouvons observer le retour à la normale :

+
 postgres@pg-1:~$ patronictl list -ew 1
+
+
+

Perte du nœud primaire +Patroni

+
+
    +
  • Perte du primaire courant
  • +
+
+
+

Dans un autre terminal, nous observons l’état de l’agrégat sur le +nœud pg-2 :

+
 postgres@pg-2:~$ patronictl list -ew 1
+

Nous simulons une perte du primaire pg-1 :

+
 $ sudo lxc-freeze pg-1
+

Nous observons la disparition de pg-1 de la liste des +nœuds et une bascule automatique se déclenche vers un des nœuds +secondaires disponibles :

+
+ Cluster: 15-main (7029596050496494965) -+----+-----------+
+| Member | Host       | Role    | State   | TL | Lag in MB |
++--------+------------+---------+---------+----+-----------+
+| pg-2   | 10.0.3.202 | Replica | running |  7 |         0 |
+| pg-3   | 10.0.3.203 | Leader  | running |  7 |           |
++--------+------------+---------+---------+----+-----------+
+

Nous rétablissons la situation :

+
$ sudo lxc-unfreeze pg-1
+
+ Cluster: 15-main (7029596050496494965) -+----+-----------+
+| Member | Host       | Role    | State   | TL | Lag in MB |
++--------+------------+---------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Replica | running |  6 |         0 |
+| pg-2   | 10.0.3.202 | Replica | running |  7 |         0 |
+| pg-3   | 10.0.3.203 | Leader  | running |  7 |           |
++--------+------------+---------+---------+----+-----------+
+

Pour un retour à l’état nominal, il suffit de procéder à une bascule +manuelle (adapter la commande si votre primaire n’est pas +pg-3) :

+
postgres@pg-1:~$ patronictl switchover --master pg-3 --candidate pg-1 --force
+
Current cluster topology
++ Cluster: 15-main (7029596050496494965) -+----+-----------+
+| Member | Host       | Role    | State   | TL | Lag in MB |
++--------+------------+---------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Replica | running |  7 |         0 |
+| pg-2   | 10.0.3.202 | Replica | running |  7 |         0 |
+| pg-3   | 10.0.3.203 | Leader  | running |  7 |           |
++--------+------------+---------+---------+----+-----------+
+2021-11-12 13:18:36.05884 Successfully switched over to "pg-1"
++ Cluster: 15-main (7029596050496494965) -+----+-----------+
+| Member | Host       | Role    | State   | TL | Lag in MB |
++--------+------------+---------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader  | running |  7 |           |
+| pg-2   | 10.0.3.202 | Replica | running |  7 |         0 |
+| pg-3   | 10.0.3.203 | Replica | stopped |    |   unknown |
++--------+------------+---------+---------+----+-----------+
+
+
+

Modification de la +configuration

+
+
    +
  • patronictl edit-config
  • +
+
+
+

L’un des avantages de bénéficier d’une configuration distribuée est +qu’il est possible de modifier cette configuration pour tous les nœuds +en une seule opération.

+

Si le paramètre nécessite un rechargement de la configuration, elle +sera lancée sur chaque nœud.

+

Si la modification nécessite un redémarrage, l’ drapeau pending +restart sera positionné sur toutes les instances et attendrons une +action de votre part pour l’effectuer.

+
+

L’installation de la commande less est un +pré-requis :

+
 $ for node in pg-1 pg-2 pg-3; do
+     ssh $node apt install less
+   done
+
+

La modification peut se faire sur n’importe quel nœud :

+
postgres@pg-2:~$ patronictl edit-config
+

Nous ajoutons une ligne fille de la ligne + parameters:

+
loop_wait: 10
+maximum_lag_on_failover: 1048576
+postgresql:
+  parameters: 
+    max_connections: 123
+ ...
+

Une confirmation est demandée après la sortie de l’éditeur :

+
patronictl edit-config
+--- 
++++ 
+@@ -1,7 +1,8 @@
+ loop_wait: 10
+ maximum_lag_on_failover: 1048576
+ postgresql:
+-  parameters: null
++  parameters: 
++    max_connections: 123
+   pg_hba:
+   - local   all             all                                     peer
+   - host    all             all             127.0.0.1/32            md5
+
+Apply these changes? [y/N]: y
+Configuration changed
+

Après modification, il convient de regarder si notre modification ne +nécessite pas de redémarrage :

+
postgres@pg-2:~$ patronictl list -e
+
+ Cluster: 15-main (7029596050496494965) -+----+-----------+-----------------+
+| Member | Host       | Role    | State   | TL | Lag in MB | Pending restart |
++--------+------------+---------+---------+----+-----------+-----------------+
+| pg-1   | 10.0.3.201 | Leader  | running |  8 |           | *               |
+| pg-2   | 10.0.3.202 | Replica | running |  8 |         0 | *               | 
+| pg-3   | 10.0.3.203 | Replica | running |  8 |         0 | *               |
++--------+------------+---------+---------+----+-----------+-----------------+
+

Dans notre cas, un redémarrage de toutes les instances est +nécessaire :

+
postgres@pg-2:~$ patronictl restart 15-main
+
+ Cluster: 15-main (7029596050496494965) -+----+-----------+-----------------+
+| Member | Host       | Role    | State   | TL | Lag in MB | Pending restart |
++--------+------------+---------+---------+----+-----------+-----------------+
+| pg-1   | 10.0.3.201 | Leader  | running |  8 |           | *               |
+| pg-2   | 10.0.3.202 | Replica | running |  8 |         0 | *               |
+| pg-3   | 10.0.3.203 | Replica | running |  8 |         0 | *               |
++--------+------------+---------+---------+----+-----------+-----------------+
+When should the restart take place (e.g. 2021-11-12T14:37)  [now]: 
+Are you sure you want to restart members pg-3, pg-2, pg-1? [y/N]: y
+Restart if the PostgreSQL version is less than provided (e.g. 9.5.2)  []: 
+Success: restart on member pg-3
+Success: restart on member pg-2
+Success: restart on member pg-1
+
postgres@pg-2:~$ patronictl list -e
+
+ Cluster: 15-main (7029596050496494965) -+----+-----------+-----------------+
+| Member | Host       | Role    | State   | TL | Lag in MB | Pending restart |
++--------+------------+---------+---------+----+-----------+-----------------+
+| pg-1   | 10.0.3.201 | Leader  | running |  8 |           |                 |
+| pg-2   | 10.0.3.202 | Replica | running |  8 |         0 |                 |
+| pg-3   | 10.0.3.203 | Replica | running |  8 |         0 |                 |
++--------+------------+---------+---------+----+-----------+-----------------+
+
 $ for node in pg-1 pg-2 pg-3; do
+  echo "$node :"
+  sudo ssh $node "sudo -iu postgres psql -c 'show max_connections'"
+  done
+
pg-1 :
+ max_connections 
+-----------------
+ 123
+(1 ligne)
+
+pg-2 :
+ max_connections 
+-----------------
+ 123
+(1 ligne)
+
+pg-3 :
+ max_connections 
+-----------------
+ 123
+(1 ligne)
+

L’application d’un paramètre qui ne nécessite pas de redémarrage est +transparente, le rechargement de la configuration sur tous les nœuds est +automatiquement déclenchée par Patroni.

+
+
+

Sauvegardes

+
+
    +
  • Installation pgBackrest
  • +
  • Configuration
  • +
  • Détermination du primaire
  • +
  • Archivage
  • +
  • Sauvegarde
  • +
+
+
+

Détermination du primaire

+

Nous proposons de déclencher la sauvegarde sur le primaire courant, +il faut donc d’abord l’identifier.

+

Le script suivant est une solution permettant de récupérer le +primaire de notre agrégat à partir d’un nœud Etcd et de l’API mise à +disposition :

+
#! /bin/bash
+SCOPE=$(grep -i scope: /etc/patroni/15-main.yml | cut -d '"' -f 2)
+curl -s http://e1:2379/v2/keys/postgresql-common/"$SCOPE"/leader | jq -r .node.value
+

Configuration de pgBackrest

+

Sur chacun des nœuds, il faut configurer le +stanza et l’initialiser :

+
# /etc/pgbackrest.conf
+[main]
+pg1-path=/var/lib/postgresql/15/main
+pg1-socket-path=/var/run/postgresql
+pg1-port=5432
+
+[global]
+log-level-file=detail
+log-level-console=detail
+repo1-host=backup
+repo1-host-user=postgres
+

Tous les nœuds doivent permettre la connexion ssh sans mot +de passe, le playbook Ansible nommé +exchange_ssh_keys permet de faire ce travail +rapidement :

+
 $ sudo ansible-playbook -i inventory.yml exchange_ssh_keys.yml  -f 7
+

La première connexion ssh entre backup et les nœuds +PostgreSQL demande une confirmation. Il faut donc lancer les trois +commandes :

+
postgres@backup:~ $ ssh pg-1
+
+postgres@backup:~ $ ssh pg-2
+
+postgres@backup:~ $ ssh pg-3
+

Nous pouvons alors tenter de créer le stanza sur le +primaire :

+
postgres@pg-1:~$ pgbackrest --stanza main stanza-create
+postgres@pg-1:/var/lib/pgbackrest$ pgbackrest --stanza  main check
+ERROR: [087]: archive_mode must be enabled
+

L’archivage est en erreur puisque non configuré.

+

Configuration de +l’archivage

+

Toutes les instances doivent être en mesure d’archiver leurs journaux +de transactions au moyen de pgBackrest :

+
postgres@pg-1:~$ patronictl edit-config
+
postgresql:
+  parameters:
+    max_connections: 123
+    archive_mode: 'on'
+    archive_command: pgbackrest --stanza=main archive-push %p
+

Notre configuration n’a pas encore été appliquée sur les instances +car un redémarrage est requis :

+
postgres@pg-1:~$ patronictl list -e
+
+ Cluster: 15-main (7029596050496494965) -+----+-----------+-----------------+
+| Member | Host       | Role    | State   | TL | Lag in MB | Pending restart |
++--------+------------+---------+---------+----+-----------+-----------------+
+| pg-1   | 10.0.3.201 | Leader  | running |  8 |           | *               |
+| pg-2   | 10.0.3.202 | Replica | running |  8 |         0 | *               |
+| pg-3   | 10.0.3.203 | Replica | running |  8 |         0 | *               |
++--------+------------+---------+---------+----+-----------+-----------------+
+
postgres@pg-1:~$ patronictl restart 15-main --force
++ Cluster: 15-main (7029596050496494965) -+----+-----------+-----------------+
+| Member | Host       | Role    | State   | TL | Lag in MB | Pending restart |
++--------+------------+---------+---------+----+-----------+-----------------+
+| pg-1   | 10.0.3.201 | Leader  | running |  8 |           | *               |
+| pg-2   | 10.0.3.202 | Replica | running |  8 |         0 | *               |
+| pg-3   | 10.0.3.203 | Replica | running |  8 |         0 | *               |
++--------+------------+---------+---------+----+-----------+-----------------+
+Success: restart on member pg-1
+Success: restart on member pg-3
+Success: restart on member pg-2
+

Test de la configuration de l’archivage sur le nœud +pg-1 :

+
postgres@pg-1:~$ pgbackrest --stanza main check
+
2021-11-12 15:57:04.000 P00   INFO: check command begin 2.35: --exec-id=13216-
+4a7c4a92 --log-level-console=detail --log-level-file=detail --pg1-path=/var/lib/
+postgresql/15/main --pg1-port=5432 --pg1-socket-path=/var/run/postgresql --
+repo1-host=backup --repo1-host-user=postgres --stanza=main
+2021-11-12 15:57:04.616 P00   INFO: check repo1 configuration (primary)
+2021-11-12 15:57:05.083 P00   INFO: check repo1 archive for WAL (primary)
+2021-11-12 15:57:08.425 P00   INFO: WAL segment 000000080000000000000005 
+successfully archived to '/var/lib/pgbackrest/archive/main/15-1/
+0000000800000000/000000080000000000000005-
+b0929d740c7996974992ecd7b9b189b37d06a896.gz' on repo1
+2021-11-12 15:57:08.528 P00   INFO: check command end: completed successfully 
+(4531ms)
+

Configuration +sur la machine hébergeant les sauvegardes

+

Sur la machine backup, créer le script de détermination +du leader (le rendre exécutable) :

+
postgres@backup:~$ vim ~/leader.sh && chmod +x leader.sh
+
#! /bin/bash
+SCOPE='15-main'
+curl -s http://e1:2379/v2/keys/postgresql-common/"$SCOPE"/leader | jq -r .node.value
+
Configuration de +pgBackrest
+

Nous avons choisit d’opérer en mode pull, les sauvegardes +seront exécutées sur la machine backup et récupérées depuis +le primaire courant.

+

La configuration se fait dans le fichier +/etc/pgbackrest.conf :

+
[global]
+repo1-path=/var/lib/pgbackrest
+repo1-retention-full=2
+start-fast=y
+log-level-console=info
+log-level-file=info
+
+[main]
+pg1-path=/var/lib/postgresql/15/main
+pg1-host-user=postgres
+pg1-user=postgres
+pg1-port=5432
+

On déterminera l’instance qui sera utilisée pour récupérer la +sauvegarde, au moment de la sauvegarde.

+

Test d’une sauvegarde

+
postgres@backup:~$ pgbackrest --stanza main --pg1-host=$(./leader.sh) backup 
+--type=full
+

+2023-02-09 18:43:38.424 P00   INFO: backup command begin 2.44: --exec-id=1116-00f26290 
+--log-level-console=info --log-level-file=info --pg1-host=pg-1 --pg1-host-user=postgres --
+pg1-path=/var/lib/postgresql/15/main --pg1-port=5432 --pg1-user=postgres --repo1-path=/var/
+lib/pgbackrest --repo1-retention-full=2 --stanza=main --start-fast --type=full
+2023-02-09 18:43:39.363 P00   INFO: execute non-exclusive backup start: backup begins 
+after the requested immediate checkpoint completes
+2023-02-09 18:43:40.475 P00   INFO: backup start archive = 000000070000000000000013, lsn = 0/13000028
+2023-02-09 18:43:40.475 P00   INFO: check archive for prior segment 000000070000000000000012
+2023-02-09 18:44:06.600 P00   INFO: execute non-exclusive backup stop and wait for all WAL segments to archive
+2023-02-09 18:44:06.905 P00   INFO: backup stop archive = 000000070000000000000013, lsn = 0/13000138
+2023-02-09 18:44:06.955 P00   INFO: check archive for segment(s) 
+000000070000000000000013:000000070000000000000013
+2023-02-09 18:44:07.533 P00   INFO: new backup label = 20230209-184339F
+2023-02-09 18:44:07.798 P00   INFO: full backup size = 29.2MB, file total = 1261
+2023-02-09 18:44:07.819 P00   INFO: backup command end: completed successfully (29396ms)
+2023-02-09 18:44:07.819 P00   INFO: expire command begin 2.44: --exec-id=1116-00f26290 
+--log-level-console=info --log-level-file=info --repo1-path=/var/lib/pgbackrest 
+--repo1-retention-full=2 --stanza=main
+2023-02-09 18:44:07.822 P00   INFO: repo1: expire full backup 20230209-183850F
+2023-02-09 18:44:07.892 P00   INFO: repo1: remove expired backup 20230209-183850F
+2023-02-09 18:44:07.971 P00   INFO: repo1: 15-1 remove archive, start = 000000070000000000000008, 
+stop = 00000007000000000000000A
+2023-02-09 18:44:07.971 P00   INFO: expire command end: completed successfully (152ms)
+
+

Vérification de l’état de la sauvegarde :

+
postgres@backup:~$ pgbackrest --stanza main info
+
stanza: main
+    status: ok
+    cipher: none
+
+    db (current)
+        wal archive min/max (14): 000000010000000000000001/00000008000000000000000B
+
+        full backup: 20211112-163233F
+            timestamp start/stop: 2021-11-12 16:32:33 / 2021-11-12 16:32:45
+            wal start/stop: 00000008000000000000000B / 00000008000000000000000B
+            database size: 25.1MB, database backup size: 25.1MB
+            repo1: backup set size: 3.2MB, backup size: 3.2MB
+
+
+

Réplication synchrone

+

La réplication synchrone permet de garantir que les données sont +écrites sur un ou plusieurs secondaires lors de la validation des +transactions.

+

Elle permet de réduire quasi-totalement la perte de donnée lors d’un +incident (RPO).

+

Il faut un minimum de trois paramètres ajoutés à la configuration +dynamique pour décrire la réplication synchrone :

+
synchronous_mode: true
+synchronous_node_count: 1
+synchronous_standby_names: '*'
+

Après quelques secondes, l’un des réplicas passe en mode +synchrone :

+
postgres@pg-1:~$ patronictl list
++ Cluster: 15-main (7198182122558146054) ------+----+-----------+
+| Member | Host       | Role         | State   | TL | Lag in MB |
++--------+------------+--------------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader       | running |  7 |           |
+| pg-2   | 10.0.3.202 | Replica      | running |  7 |         0 |
+| pg-3   | 10.0.3.203 | Sync Standby | running |  7 |         0 |
++--------+------------+--------------+---------+----+-----------+
+
    +
  • La prochaine bascule ne sera possible que sur le nœud +synchrone.
  • +
  • Si le nœud synchrone est défaillant, un des secondaires restant +passera en mode synchrone (synchronous_standby_names et +synchronous_node_count l’autorisent)
  • +
+

Perte du secondaire synchrone :

+
$ sudo lxc-freeze pg-3
+

Quelques secondes plus tard :

+
+ Cluster: 15-main (7198182122558146054) ------+----+-----------+
+| Member | Host       | Role         | State   | TL | Lag in MB |
++--------+------------+--------------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader       | running |  7 |           |
+| pg-2   | 10.0.3.202 | Sync Standby | running |  7 |         0 |
++--------+------------+--------------+---------+----+-----------+
+
+

Mise à jour +mineure sans interruption de service

+

Rappel : la réplication physique peut être mise en œuvre entre deux +instances de versions mineures différentes. (ex: 15.1 vers 15.2)

+

La mise à jour mineure peut être faite nœud par nœud en commençant +par les secondaires asynchrones, puis par les secondaires +synchrones.

+

Dès qu’un deuxième secondaire synchrone est présent, le mise peut +être faîte sur le premier secondaire synchrone.

+

Une fois tous les secondaires mis à jour, une bascule sur un des +secondaires synchrone à jour pourra être faite et l’ancien primaire sera +alors mis à jour de la même manière, puis redémarré :

+

État de départ :

+
+ Cluster: 15-main (7198182122558146054) ------+----+-----------+
+| Member | Host       | Role         | State   | TL | Lag in MB |
++--------+------------+--------------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader       | running |  7 |           |
+| pg-2   | 10.0.3.202 | Replica      | running |  7 |         0 |
+| pg-3   | 10.0.3.203 | Sync Standby | running |  7 |         0 |
++--------+------------+--------------+---------+----+-----------+
+

Mise à jour jour et redémarrage du premier secondaire +asynchrone pg-2 :

+
...
+$ patronictl restart 15-main pg-2
+

Passage à 2 nœuds synchrones :

+
$ patronictl edit-config
+
...
+synchronous_node_count: 2
+...
+
+ Cluster: 15-main (7198182122558146054) ------+----+-----------+
+| Member | Host       | Role         | State   | TL | Lag in MB |
++--------+------------+--------------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader       | running | 10 |           |
+| pg-2   | 10.0.3.202 | Sync Standby | running | 10 |         0 |
+| pg-3   | 10.0.3.203 | Sync Standby | running | 10 |         0 |
++--------+------------+--------------+---------+----+-----------+
+

Mise à jour du nœud synchrone +pg-3 :

+
...
+$ patronictl restart 15-main pg-3
+

Bascule vers le secondaire synchrone mis à jour +:

+
...
+$ patronictl switchover --master pg-1 --candidate pg-3 --force
+

Mise à jour du primaire :

+
...
+$ patronictl restart 15-main pg-1 --force
+

Effectuer la promotion et remettre le nombre de nœuds +synchrone à 1 :

+
$ patronictl switchover --candidate pg-1 --master pg-3 --force
+
+ Cluster: 15-main (7198182122558146054) ------+----+-----------+
+| Member | Host       | Role         | State   | TL | Lag in MB |
++--------+------------+--------------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader       | running | 11 |           |
+| pg-2   | 10.0.3.202 | Sync Standby | running | 11 |         0 |
+| pg-3   | 10.0.3.203 | Sync Standby | running | 11 |         0 |
++--------+------------+--------------+---------+----+-----------+
+
$ patronictl edit-config
+
...
+synchronous_node_count: 1
+...
+

Après quelques secondes :

+
+ Cluster: 15-main (7198182122558146054) ------+----+-----------+
+| Member | Host       | Role         | State   | TL | Lag in MB |
++--------+------------+--------------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader       | running | 11 |           |
+| pg-2   | 10.0.3.202 | Sync Standby | running | 11 |         0 |
+| pg-3   | 10.0.3.203 | Replica      | running | 11 |         0 |
++--------+------------+--------------+---------+----+-----------+
+

Aucun arrêt de service et aucune perte de données due à +l’opération.

+
+

Références

+ +
+ +
+
+
+
+ + +
+ + diff --git a/fr/patroni/patroni.local.html b/fr/patroni/patroni.local.html new file mode 100644 index 0000000..d76fa39 --- /dev/null +++ b/fr/patroni/patroni.local.html @@ -0,0 +1,1189 @@ + + + + + + + + Haute disponibilité avec Patroni + + + + + + + + + + + + + + + +
+
+ +
+

Haute disponibilité avec Patroni

+

Workshop Patroni

+

Dalibo & Contributors

+

+ v 19.02 (février 2023) +

+
+
+true +
+ + +
+

Haute disponibilité de service avec Patroni

+
+PostgreSQL + +
+ +
+
+ +

Introduction

+
+
    +
  • Principes
  • +
  • Mise en place
  • +
  • Installation et configuration des services
  • +
  • Construction d’un agrégat à bascule automatique
  • +
  • Création d’incidents
  • +
+
+ +
+
+ +

Principes

+
+
    +
  • Arbitrage par un quorum : DCS Etcd
  • +
  • Service PostgreSQL : désactivé
  • +
  • Contrôle complet par Patroni
  • +
+
+ +
+
+ +

DCS : Etcd

+
+
    +
  • Arbitre en cas de bascules
  • +
  • Stockage distribué de la configuration
  • +
  • Jeton leader (Etcd)
  • +
  • Instance primaire PostgreSQL
  • +
+
+ +
+
+ +

Mise en place de +l’infrastructure

+
+
    +
  • Connexion à la VM
  • +
  • Récupération du playbook Ansible
  • +
+
+ +
+
+ +

Connexion à votre machine +virtuelle

+
+

un seul point d’entrée : eformation.dalibo.com un port +attribué : 22XX

+
  $ ssh -p 22XX dalibo@eformation.dalibo.com
+
+ +
+
+ +

Playbook Ansible

+
+

Récupération du playbook Ansible à cette +adresse :

+

https://github.com/dalibo/workshops/tree/workshop_patroni/fr/patroni/playbook/etcd-patroni

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FichierDescription
inventory.ymlinventaire des machines
setup.ymlplaybook +principal
demarre_tout.shdémarre tous les conteneurs
stoppe_tout.sharrête tous les conteneurs
teardown.ymlplaybook de destruction +massive
+
+ +
+
+ +
+

L’infrastructure complète peut être créée à l’aide des +commandes :

+
 $ sudo apt install -y ansible
+ $ sudo ansible-playbook -f 7 -i inventory.yml setup.yml
+...
+

Cette opération peut durer jusqu’à une vingtaine de minutes.

+
+ +
+
+ +

Installation d’Etcd

+
+
    +
  • Installation des paquets
  • +
  • Configuration
  • +
  • Démarrage du service
  • +
  • Vérification
  • +
+
+ +
+
+ +

Installation des paquets

+
+
    +
  • Paquets essentiels : +
      +
    • etcd
    • +
    • curl
    • +
    • jq
    • +
    • iputils-ping
    • +
  • +
+
+ +
+
+ +

Configuration du service +Etcd

+
+
    +
  • Fichier : /etc/default/etcd
  • +
+
+ +
+
+ +

Démarrage du service

+
+
    +
  • Réinitialisation des bases Etcd
  • +
  • Démarrage du service etcd +
      +
    • systemctl start etcd
    • +
  • +
+
+ +
+

Le leader doit être identique sur les trois nœuds, les trois +nœuds doivent retourner la même liste de membres.

+
+
+
+ +

Installation de PostgreSQL / +Patroni

+
+
    +
  • Installation +
      +
    • PostgreSQL
    • +
    • Patroni
    • +
    • pgBackrest
    • +
  • +
+
+ +
+
+ +

Configuration de Patroni

+
+

Sur tous les nœuds PostgreSQL/Patroni

+
    +
  • Configuration du DCS +
      +
    • /etc/patroni/dcs.yml
    • +
  • +
  • Génération de la configuration +
      +
    • pg_createconfig_patroni 15 main
    • +
  • +
+
+ +

Ces opérations doivent être répétées sur tous nœuds +PostgreSQL/Patroni.

+
+
+ +

Création de l’agrégat

+
+
    +
  • Démarrage du primaire
  • +
  • Création de l’utilisateur de réplication
  • +
  • Suppression des instances secondaires
  • +
  • Démarrage des instances secondaires
  • +
+
+ +
+
+ +
Vérifications
+
+
    +
  • Liste des nœuds Patroni
  • +
  • Test de bascule manuelle vers chaque nœud
  • +
+
+ +
+
+ +

Création d’incidents

+
+
    +
  • Perte totale du DCS
  • +
  • Freeze du nœud primaire Patroni
  • +
  • Bascule manuelle
  • +
+
+ +
+
+ +

Perte totale du DCS

+
+
    +
  • Perte de tous les nœuds Etcd
  • +
+
+ +
+
+ +

Perte du nœud primaire +Patroni

+
+
    +
  • Perte du primaire courant
  • +
+
+ +
+
+ +

Modification de la +configuration

+
+
    +
  • patronictl edit-config
  • +
+
+ +
+
+ +

Sauvegardes

+
+
    +
  • Installation pgBackrest
  • +
  • Configuration
  • +
  • Détermination du primaire
  • +
  • Archivage
  • +
  • Sauvegarde
  • +
+
+ +
+
+ +

Références

+ + +
+
+ +
+
+
+ + + + + + + + + + diff --git a/fr/patroni/patroni.md b/fr/patroni/patroni.md index 28f1b2e..682ef3a 100644 --- a/fr/patroni/patroni.md +++ b/fr/patroni/patroni.md @@ -1,6 +1,6 @@ --- subtitle : 'Workshop Patroni' -title : 'Haute disponibilité de service - Patroni' +title : 'Haute disponibilité avec Patroni' keywords: - postgres - postgresql @@ -13,15 +13,16 @@ keywords: linkcolor: licence : PostgreSQL -author: Dalibo & Contributors -revision: 18.06 +author: Dalibo & Contributors +date: février 2023 +revision: 19.02 url : http://dalibo.com/formations # # PDF Options # -#toc: true +toc: false ## Limiter la profondeur de la table des matières toc-depth: 4 @@ -128,7 +129,6 @@ hide_author_in_slide: true --- -\newpage ## Principes @@ -168,53 +168,7 @@ Pour ce rôle, nous utiliserons Etcd. --- -### Service PostgreSQL et Patroni - -
- - * Service PostgreSQL désactivé -
- -
- - -Le service PostgreSQL doit être **désactivé** pour ne pas se lancer au démarrage, le contrôle total de l'instance est délégué à Patroni : - - -```Bash - $ for node in pg-1 pg-2 pg-3; do - sudo systemctl disable --now postgresql - sudo systemctl status postgresql -done -``` -```console -Synchronizing state of postgresql.service with SysV service script with /lib/ -systemd/systemd-sysv-install. -Executing: /lib/systemd/systemd-sysv-install disable postgresql -· postgresql.service - PostgreSQL RDBMS - Loaded: loaded (/lib/systemd/system/postgresql.service; disabled; vendor - preset: enabled) - Active: inactive (dead) -Synchronizing state of postgresql.service with SysV service script with /lib/ -systemd/systemd-sysv-install. -Executing: /lib/systemd/systemd-sysv-install disable postgresql -· postgresql.service - PostgreSQL RDBMS - Loaded: loaded (/lib/systemd/system/postgresql.service; disabled; vendor - preset: enabled) - Active: inactive (dead) -Synchronizing state of postgresql.service with SysV service script with /lib/ -systemd/systemd-sysv-install. -Executing: /lib/systemd/systemd-sysv-install disable postgresql -· postgresql.service - PostgreSQL RDBMS - Loaded: loaded (/lib/systemd/system/postgresql.service; disabled; vendor - preset: enabled) - Active: inactive (dead) -``` - -
- ---- ## Mise en place de l'infrastructure @@ -284,31 +238,27 @@ dalibo@vm38:~$ Récupération du _playbook_ _Ansible_ à cette adresse : - + + | Fichier | Description | | :------------- | :------------- | | inventory.yml | inventaire des machines | -| setup.yml | _playbook_ principal | -| warmup.sh | script d'amorçage | +| **setup.yml** | **_playbook_ principal** | +| exchange_ssh_keys.yml | échange des clefs ssh | | | | -| exchange_ssh_keys.yml | _playbook_ d'échange de clés _ssh_ | +| demarre_tout.sh | démarre tous les conteneurs | +| stoppe_tout.sh | arrête tous les conteneurs | | teardown.yml | _playbook_ de destruction massive |
-Quatre fichiers Yaml, un script shell : +Quatre fichiers Yaml, deux scripts shell. -Le script `warmup.sh` permet de précharger une image debian pour accélérer la création des autres conteneurs : - -```Bash - $ sudo ./warmup.sh -``` -
--- @@ -317,7 +267,7 @@ Le script `warmup.sh` permet de précharger une image debian pour accélérer la L'infrastructure complète peut être créée à l'aide des commandes : -``` +```Bash  $ sudo apt install -y ansible  $ sudo ansible-playbook -f 7 -i inventory.yml setup.yml ... @@ -333,7 +283,7 @@ Cette opération peut durer jusqu'à une vingtaine de minutes. Vous pouvez suivre l'évolution de la création des conteneurs dans un autre terminal : ```Bash - $ watch -n 1 sudo lxc-ls -f + $ watch -n 1 -d sudo lxc-ls -f ``` ```console @@ -363,7 +313,7 @@ L'état final de chaque conteneur étant *RUNNING* avec une adresse *IPV4* attri ``` -Sur tous les conteneurs, le fichier `/etc/hosts` est automatiquement renseigné par le _playbook_ et devrait contenir au moins : +Sur toutes les machines, y compris l'hôte, le fichier `/etc/hosts` est automatiquement renseigné par le _playbook_ et devrait contenir au moins : ```ini 10.0.3.101 e1 @@ -400,7 +350,7 @@ Sur tous les conteneurs, le fichier `/etc/hosts` est automatiquement renseigné --- -#### Installation des paquets +#### **Installation des paquets**
@@ -418,11 +368,12 @@ Sur tous les conteneurs, le fichier `/etc/hosts` est automatiquement renseigné ```Bash  $ for node in e1 e2 e3; do - sudo ssh $node sudo apt install etcd curl iputils-ping jq + sudo ssh $node sudo apt-get install -qqy etcd curl iputils-ping jq done ``` Le démarrage du service est automatique sous Debian. + ```Bash  $ for node in e1 e2 e3; do sudo ssh $node "systemctl status etcd | grep -i active" @@ -436,7 +387,7 @@ Le démarrage du service est automatique sous Debian. Active: active (running) since Wed 2021-11-10 17:48:46 UTC; 3min 8s ago ``` -##### Vérification +**Vérification de l'état des nœuds** ```Bash $ for node in e1 e2 e3; do @@ -453,7 +404,8 @@ clientURLs=http://localhost:2379 isLeader=true clientURLs=http://localhost:2379 isLeader=true ``` -Les nœuds sont tous des _leaders_ indépendants, ce qui ne nous intéresse pas. Il faut donc les configurer pour qu'ils fonctionnent en agrégat. +Les nœuds sont tous des _leaders_ indépendants, ce qui ne nous intéresse pas. +Il faut donc les configurer pour qu'ils fonctionnent en collaboration. Nous arrêtons donc les services : @@ -472,7 +424,7 @@ done --- -#### Configuration du service Etcd +#### **Configuration du service Etcd**
@@ -483,13 +435,14 @@ done
-La configuration du service Etcd se trouve dans le fichier `/etc/default/etcd`, elle doit décrire notre agrégat sur chaque nœud : +La configuration du service Etcd se trouve dans le fichier `/etc/default/etcd`, +elle doit décrire notre agrégat sur chaque nœud :
-Attention aux caractères invisibles ou aux sauts de ligne +> Attention aux caractères invisibles ou aux sauts de ligne
**Sur le nœud e1 :** @@ -506,13 +459,11 @@ ETCD_INITIAL_ADVERTISE_PEER_URLS='http://10.0.3.101:2380' ETCD_INITIAL_CLUSTER_STATE='new' ETCD_INITIAL_CLUSTER_TOKEN='etcd-cluster' -ETCD_INITIAL_CLUSTER+='e1=http://10.0.3.101:2380' -ETCD_INITIAL_CLUSTER+='e2=http://10.0.3.102:2380' -ETCD_INITIAL_CLUSTER+='e3=http://10.0.3.103:2380' +ETCD_INITIAL_CLUSTER='e1=http://10.0.3.101:2380,e2=http://10.0.3.102:2380,e3=http://10.0.3.103:2380' + +ETCD_ADVERTISE_CLIENT_URLS='http://10.0.3.101:2379' -ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.101:2379' -ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.102:2379' -ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.103:2379' +ETCD_ENABLE_V2=true ``` **Sur le nœud e2 :** @@ -530,13 +481,11 @@ ETCD_INITIAL_ADVERTISE_PEER_URLS='http://10.0.3.102:2380' ETCD_INITIAL_CLUSTER_STATE='new' ETCD_INITIAL_CLUSTER_TOKEN='etcd-cluster' -ETCD_INITIAL_CLUSTER+='e1=http://10.0.3.101:2380' -ETCD_INITIAL_CLUSTER+='e2=http://10.0.3.102:2380' -ETCD_INITIAL_CLUSTER+='e3=http://10.0.3.103:2380' +ETCD_INITIAL_CLUSTER='e1=http://10.0.3.101:2380,e2=http://10.0.3.102:2380,e3=http://10.0.3.103:2380' + +ETCD_ADVERTISE_CLIENT_URLS='http://10.0.3.102:2379' -ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.101:2379' -ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.102:2379' -ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.103:2379' +ETCD_ENABLE_V2=true ``` **Sur le nœud e3 :** @@ -553,26 +502,23 @@ ETCD_INITIAL_ADVERTISE_PEER_URLS='http://10.0.3.103:2380' ETCD_INITIAL_CLUSTER_STATE='new' ETCD_INITIAL_CLUSTER_TOKEN='etcd-cluster' -ETCD_INITIAL_CLUSTER+='e1=http://10.0.3.101:2380' -ETCD_INITIAL_CLUSTER+='e2=http://10.0.3.102:2380' -ETCD_INITIAL_CLUSTER+='e3=http://10.0.3.103:2380' +ETCD_INITIAL_CLUSTER='e1=http://10.0.3.101:2380,e2=http://10.0.3.102:2380,e3=http://10.0.3.103:2380' -ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.101:2379' -ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.102:2379' -ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.103:2379' +ETCD_ADVERTISE_CLIENT_URLS='http://10.0.3.103:2379' + +ETCD_ENABLE_V2=true ```
--- -#### Démarrage du service +#### **Démarrage du service**
* Réinitialisation des bases Etcd - * Démarrage du service `etcd` - * `systemctl start etcd` + * Démarrage du service `etcd` : `systemctl start etcd`
@@ -581,18 +527,19 @@ ETCD_ADVERTISE_CLIENT_URLS+='http://10.0.3.103:2379' Avant de démarrer le service sur chaque nœud, il faut réinitialiser les répertoires de données des nœuds, afin qu'ils reparte sur un répertoire neuf. -Le nœud `e1`, que nous considérons comme premier _leader_ sera démarré en premier : +Le nœud `e1`, que nous considérons comme premier _leader_ sera démarré en premier mais il est possible qu'un autre nœud prenne le dessus s'il arrive à +démarrer plus vite : ```Bash  $ for node in e1 e2 e3; do - echo "$node :" ; sudo ssh $node "rm -rf ~etcd/default/member" + echo "$node :" ; sudo ssh $node "rm -rf ~etcd/default/*" done ``` ```Bash  $ for node in e1 e2 e3; do - sudo ssh -o StrictHostKeyChecking=no $node "systemctl start etcd" & + sudo ssh $node "systemctl start etcd" &  sleep 1  done ``` @@ -603,7 +550,7 @@ En cas d'échec de démarrage, utilisez la commande _Systemd_ pour en diagnosti  e1:~$ sudo journalctl -xfu etcd ``` -**Vérification que le nœud `e1` ayant démarré en premier, est bien le _leader_ :** +**Vérification :** ```Bash  $ for node in e1 e2 e3; do @@ -615,38 +562,32 @@ done ```console sur e1 : 736293150f1cffb7: name=e1 peerURLs=http://10.0.3.101:2380 -clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 -isLeader=true +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=true 7ef9d5bb55cefbcc: name=e3 peerURLs=http://10.0.3.103:2380 -clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 -isLeader=false +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=false 97463691c7858a7b: name=e2 peerURLs=http://10.0.3.102:2380 -clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 -isLeader=false +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=false sur e2 : 736293150f1cffb7: name=e1 peerURLs=http://10.0.3.101:2380 -clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 -isLeader=true +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=true 7ef9d5bb55cefbcc: name=e3 peerURLs=http://10.0.3.103:2380 -clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 -isLeader=false +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=false 97463691c7858a7b: name=e2 peerURLs=http://10.0.3.102:2380 -clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 -isLeader=false +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=false sur e3 : 736293150f1cffb7: name=e1 peerURLs=http://10.0.3.101:2380 -clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 -isLeader=true +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=true 7ef9d5bb55cefbcc: name=e3 peerURLs=http://10.0.3.103:2380 -clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 -isLeader=false +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=false 97463691c7858a7b: name=e2 peerURLs=http://10.0.3.102:2380 -clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 -isLeader=false +clientURLs=http://10.0.3.101:2379,http://10.0.3.102:2379,http://10.0.3.103:2379 isLeader=false ```
+> Le _leader_ doit être identique sur les trois nœuds, +> les trois nœuds doivent retourner la même liste de membres. + --- ### Installation de PostgreSQL / Patroni @@ -666,15 +607,15 @@ Le dépôt _pgdg_ est déjà préconfiguré dans les conteneurs pg-1, pg-2 et pg ```Bash  $ for node in pg-1 pg-2 pg-3; do -sudo ssh $node "apt-get update && apt-get install -y postgresql patroni pgbackrest" +sudo ssh $node "apt-get update && apt-get install -qqy postgresql patroni pgbackrest" & done ``` -Vérification : +**Vérification :** ```Bash - $ for node in pg-1 pg-2 pg-3; do sudo ssh $node "dpkg -l postgresql patroni + $ for node in pg-1 pg-2 pg-3; do sudo ssh $node "dpkg -l postgresql patroni \ pgbackrest | grep ^ii | cut -d ' ' -f 1,3"; done ii patroni ii pgbackrest @@ -687,11 +628,11 @@ ii pgbackrest ii postgresql ``` -Le service PostgreSQL doit êtrre désactivé car la gestion totale de l'instance sera déléguée à Patroni : +Le service PostgreSQL doit être désactivé car la gestion totale de l'instance sera déléguée à Patroni : ```Bash $ for node in pg-1 pg-2 pg-3; do -sudo ssh $node "systemctl disable --now postgresql@14-main" +sudo ssh $node "systemctl disable --now postgresql@15-main" done ``` @@ -699,16 +640,16 @@ done --- -#### Configuration de Patroni +#### **Configuration de Patroni**
-Sur tous les nœuds +Sur tous les nœuds PostgreSQL/Patroni * Configuration du DCS * `/etc/patroni/dcs.yml` * Génération de la configuration - * `pg_createconfig_patroni 14 main` + * `pg_createconfig_patroni 15 main`
@@ -717,23 +658,36 @@ Sur tous les nœuds La configuration sous Debian se fait d'abord en renseignant comment contacter le DCS, puis en lançant le script de génération automatique de la configuration de Patroni. +Le port par défaut du service Etcd est le `2379`. + + +```Bash +$ sudo ssh pg-1 +root@pg-1:~# vim /etc/patroni/dcs.yml +``` + ```yaml # /etc/patroni/dcs.yml etcd: - hosts: e1:2379, e2:2379, e3:2379 + hosts: + - 10.0.3.101:2379 + - 10.0.3.102:2379 + - 10.0.3.103:2379 ``` ```Bash - $ sudo ssh pg-1 "pg_createconfig_patroni 14 main" + root@pg-1:~# pg_createconfig_patroni 15 main" ``` -La configuration `/etc/patroni/14-main.yml` est générée. +La configuration `/etc/patroni/15-main.yml` est générée.
+Ces opérations doivent être répétées sur tous les nœuds PostgreSQL/Patroni. + --- -#### Création de l'agrégat +#### **Création de l'agrégat**
@@ -746,54 +700,117 @@ La configuration `/etc/patroni/14-main.yml` est générée.
-##### Démarrage du primaire +##### **Démarrage du primaire** La création de l'agrégat commence par la mise en route du primaire sur le nœud `pg-1`, c'est lui qui sera la référence pour les secondaires. -L'utilisateur permettant la mise en réplication doit être créé sur ce nœud, avec le mot de passe renseigné dans la configuration de Patroni : +```Bash +root@pg-1:~# systemctl enable --now patroni@15-main +``` + +L'instance doit être promue pour pouvoir être accessible écriture : + +```Bash +root@pg-1:~# sudo -iu postgres psql -c 'select pg_promote();' +``` + +**L'utilisateur permettant la mise en réplication doit être créé sur ce nœud, avec le mot de passe renseigné dans la configuration de Patroni :** ```Bash - $ sudo ssh pg-1 "sudo systemctl enable --now patroni@14-main" +root@pg-1:~# sudo -iu postgres psql -c "create user replicator replication password 'rep-pass';" ``` -##### Création de l'utilisateur de réplication + +##### **Superuser d'administration locale** + +Chaque nœud doit pouvoir récupérer la _timeline_ et le _LSN_ courants ```Bash - $ sudo ssh pg-1 "sudo -iu postgres psql -c \"create user replicator replication - password 'rep-pass'\" " +root@pg-1:~# sudo -iu postgres psql -c "create user dba superuser password 'admin'" ``` +Si l'utilisateur est différent de `postgres`, il faudra désactiver le socket unix +sinon Patroni essaiera la connexion locale authentifiée par la méthode `peer`. +L'utilisateur `dba` n'existant pas au niveau système, il y aurait échec. + + +La configuration de chaque nœud doit être modifiée : + + +```yaml +#/etc/patroni/15-main.yml + +postgresql: + + #... + + use_unix_socket: false + + #... + + superuser: + username: "dba" + password: "admin" + #... + +``` + +On redémarre patroni: + +```Bash +systemctl restart patroni@15-main +``` + + ##### Suppression des instances secondaires -Les instances secondaires ont été initialisées lors de l'installation du paquet Debian, il faut donc vider leur répertoire de données :. +Les instances secondaires ont été initialisées lors de l'installation du paquet Debian, +il faut donc vider leur répertoire de données car Patroni refusera d'écraser des +données existantes. Nous utilisons le _wrapper_ Debian : `pg-1` étant notre primaire : ```Bash - $ for node in pg-2 pg-3; do - sudo ssh $node "rm -rf /var/lib/postgresql/14/main/*" -done + $ for node in pg-2 pg-3; do sudo ssh $node "pg_dropcluster 15 main"; done ``` -Les secondaires seront recréés automatiquement depuis le primaire par Patroni. +Les secondaires seront recréés automatiquement par Patroni, depuis le primaire +par réplication. -##### Démarrage des instances secondaires -Nous pouvons raccrocher nos secondaires en démarrant les deux instances : +Le primaire doit être redémarré : ```Bash - $ for node in pg-2 pg-3; do - sudo ssh $node "systemctl start patroni@14-main" - done +postgres@pg-1:~ $ patronictl restart 15-main pg-1 --force +``` + +les nœuds secondaires doivent être démarrés : + +```Bash +$ for node in pg-2 pg-3; do sudo ssh $node "systemctl start patroni@15-main"; done ``` + + +La vérification se fait dans les traces de Patroni des nœuds secondaires : +\small +``` +Feb 09 17:12:38 pg-3 patroni@15-main[1029]: 2023-02-09 17:12:38,984 INFO: Lock owner: pg-1; I am pg-3 +Feb 09 17:12:38 pg-3 patroni@15-main[1029]: 2023-02-09 17:12:38,986 INFO: Local timeline=7 lsn=0/5000148 +Feb 09 17:12:39 pg-3 patroni@15-main[1029]: 2023-02-09 17:12:39,037 INFO: master_timeline=7 + +``` +\normalsize + + +
--- -##### Vérifications +##### **Vérifications**
@@ -804,12 +821,12 @@ Nous pouvons raccrocher nos secondaires en démarrant les deux instances :
-###### Liste des nœuds Patroni +###### **Liste des nœuds Patroni** Sur chaque nœud Patroni, modifier le `.profile` de l'utilisateur `postgres` en ajoutant : ```Bash -export PATRONICTL_CONFIG_FILE=/etc/patroni/14-main.yml +export PATRONICTL_CONFIG_FILE=/etc/patroni/15-main.yml ``` @@ -817,7 +834,7 @@ export PATRONICTL_CONFIG_FILE=/etc/patroni/14-main.yml  $ sudo ssh pg-1 sudo -iu postgres patronictl list ``` ```console - + Cluster: 14-main (7029596050496494965) -+----+-----------+ + + Cluster: 15-main (7029596050496494965) -+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +--------+------------+---------+---------+----+-----------+ | pg-1 | 10.0.3.201 | Leader | running | 3 | | @@ -825,7 +842,7 @@ export PATRONICTL_CONFIG_FILE=/etc/patroni/14-main.yml | pg-3 | 10.0.3.203 | Replica | running | 3 | 0 | ``` -###### Test de bascule manuelle vers chaque nœud +###### **Test de bascule manuelle vers chaque nœud** ```Bash  $ sudo ssh pg-1 sudo -iu postgres patronictl switchover @@ -835,17 +852,17 @@ Master [pg-1]: Candidate ['pg-2', 'pg-3'] []: pg-2 When should the switchover take place (e.g. 2021-11-12T12:21 ) [now]: Current cluster topology -+ Cluster: 14-main (7029596050496494965) -+----+-----------+ ++ Cluster: 15-main (7029596050496494965) -+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +--------+------------+---------+---------+----+-----------+ | pg-1 | 10.0.3.201 | Leader | running | 3 | | | pg-2 | 10.0.3.202 | Replica | running | 3 | 0 | | pg-3 | 10.0.3.203 | Replica | running | 3 | 0 | +--------+------------+---------+---------+----+-----------+ -Are you sure you want to switchover cluster 14-main, demoting current master +Are you sure you want to switchover cluster 15-main, demoting current master pg-1? [y/N]: y 2021-11-12 11:21:20.08091 Successfully switched over to "pg-2" -+ Cluster: 14-main (7029596050496494965) -+----+-----------+ ++ Cluster: 15-main (7029596050496494965) -+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +--------+------------+---------+---------+----+-----------+ | pg-1 | 10.0.3.201 | Replica | stopped | | unknown | @@ -967,10 +984,11 @@ Nous simulons une perte du primaire `pg-1` :  $ sudo lxc-freeze pg-1 ``` -Nous observons la disparition de `pg-1` de la liste des nœuds et une bascule automatique se déclenche vers un des nœuds secondaires disponibles : +Nous observons la disparition de `pg-1` de la liste des nœuds et une bascule +automatique se déclenche vers un des nœuds secondaires disponibles : ```console -+ Cluster: 14-main (7029596050496494965) -+----+-----------+ ++ Cluster: 15-main (7029596050496494965) -+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +--------+------------+---------+---------+----+-----------+ | pg-2 | 10.0.3.202 | Replica | running | 7 | 0 | @@ -986,7 +1004,7 @@ $ sudo lxc-unfreeze pg-1 ``` ```console -+ Cluster: 14-main (7029596050496494965) -+----+-----------+ ++ Cluster: 15-main (7029596050496494965) -+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +--------+------------+---------+---------+----+-----------+ | pg-1 | 10.0.3.201 | Replica | running | 6 | 0 | @@ -1002,7 +1020,7 @@ postgres@pg-1:~$ patronictl switchover --master pg-3 --candidate pg-1 --force ``` ```console Current cluster topology -+ Cluster: 14-main (7029596050496494965) -+----+-----------+ ++ Cluster: 15-main (7029596050496494965) -+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +--------+------------+---------+---------+----+-----------+ | pg-1 | 10.0.3.201 | Replica | running | 7 | 0 | @@ -1010,7 +1028,7 @@ Current cluster topology | pg-3 | 10.0.3.203 | Leader | running | 7 | | +--------+------------+---------+---------+----+-----------+ 2021-11-12 13:18:36.05884 Successfully switched over to "pg-1" -+ Cluster: 14-main (7029596050496494965) -+----+-----------+ ++ Cluster: 15-main (7029596050496494965) -+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +--------+------------+---------+---------+----+-----------+ | pg-1 | 10.0.3.201 | Leader | running | 7 | | @@ -1041,12 +1059,12 @@ Si le paramètre nécessite un rechargement de la configuration, elle sera lanc Si la modification nécessite un redémarrage, l' drapeau _pending restart_ sera positionné sur toutes les instances et attendrons une action de votre part pour l'effectuer. -L'installation de la commande `less` est un pré-requis : - -```Bash - $ for i in pg-1 pg-2 pg-3; do apt install less done - ... -``` +> L'installation de la commande `less` est un pré-requis : +> ```Bash +>  $ for node in pg-1 pg-2 pg-3; do +> sudo ssh $node apt install less +> done +> ``` La modification peut se faire sur n'importe quel nœud : @@ -1067,7 +1085,7 @@ postgresql: Une confirmation est demandée après la sortie de l'éditeur : -```console +```diff patronictl edit-config --- +++ @@ -1092,7 +1110,7 @@ Après modification, il convient de regarder si notre modification ne nécessite postgres@pg-2:~$ patronictl list -e ``` ```console -+ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+ ++ Cluster: 15-main (7029596050496494965) -+----+-----------+-----------------+ | Member | Host | Role | State | TL | Lag in MB | Pending restart | +--------+------------+---------+---------+----+-----------+-----------------+ | pg-1 | 10.0.3.201 | Leader | running | 8 | | * | @@ -1104,10 +1122,10 @@ postgres@pg-2:~$ patronictl list -e Dans notre cas, un redémarrage de toutes les instances est nécessaire : ```Bash -postgres@pg-2:~$ patronictl restart 14-main +postgres@pg-2:~$ patronictl restart 15-main ``` ```console -+ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+ ++ Cluster: 15-main (7029596050496494965) -+----+-----------+-----------------+ | Member | Host | Role | State | TL | Lag in MB | Pending restart | +--------+------------+---------+---------+----+-----------+-----------------+ | pg-1 | 10.0.3.201 | Leader | running | 8 | | * | @@ -1128,7 +1146,7 @@ Success: restart on member pg-1 postgres@pg-2:~$ patronictl list -e ``` ```console -+ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+ ++ Cluster: 15-main (7029596050496494965) -+----+-----------+-----------------+ | Member | Host | Role | State | TL | Lag in MB | Pending restart | +--------+------------+---------+---------+----+-----------+-----------------+ | pg-1 | 10.0.3.201 | Leader | running | 8 | | | @@ -1189,22 +1207,22 @@ L'application d'un paramètre qui ne nécessite pas de redémarrage est transpar Nous proposons de déclencher la sauvegarde sur le primaire courant, il faut donc d'abord l'identifier. -Le script suivant est une solution permettant de récupérer le primaire de notre agrégat à partir d'un nœud Etcd ezt de l'API mise à disposition : +Le script suivant est une solution permettant de récupérer le primaire de notre agrégat à partir d'un nœud Etcd et de l'API mise à disposition : ```Bash #! /bin/bash -SCOPE=$(grep -i scope: /etc/patroni/14-main.yml | cut -d '"' -f 2) +SCOPE=$(grep -i scope: /etc/patroni/15-main.yml | cut -d '"' -f 2) curl -s http://e1:2379/v2/keys/postgresql-common/"$SCOPE"/leader | jq -r .node.value ``` ### Configuration de pgBackrest -Sur chacun des nœuds, il faut configurer le _stanza_ et l'initialiser : +**Sur chacun des nœuds**, il faut configurer le _stanza_ et l'initialiser : ```ini # /etc/pgbackrest.conf [main] -pg1-path=/var/lib/postgresql/14/main +pg1-path=/var/lib/postgresql/15/main pg1-socket-path=/var/run/postgresql pg1-port=5432 @@ -1222,6 +1240,17 @@ Tous les nœuds doivent permettre la connexion _ssh_ sans mot de passe, le _play  $ sudo ansible-playbook -i inventory.yml exchange_ssh_keys.yml -f 7 ``` +La première connexion ssh entre `backup` et les nœuds PostgreSQL demande une +confirmation. Il faut donc lancer les trois commandes : + +``` Bash +postgres@backup:~ $ ssh pg-1 + +postgres@backup:~ $ ssh pg-2 + +postgres@backup:~ $ ssh pg-3 +``` + Nous pouvons alors tenter de créer le _stanza_ sur le primaire : ```Bash @@ -1230,7 +1259,10 @@ postgres@pg-1:/var/lib/pgbackrest$ pgbackrest --stanza main check ERROR: [087]: archive_mode must be enabled ``` -#### Configuration de l'archivage +L'archivage est en erreur puisque non configuré. + + +#### **Configuration de l'archivage** Toutes les instances doivent être en mesure d'archiver leurs journaux de transactions au moyen de pgBackrest : @@ -1251,7 +1283,7 @@ Notre configuration n'a pas encore été appliquée sur les instances car un red postgres@pg-1:~$ patronictl list -e ``` ```console -+ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+ ++ Cluster: 15-main (7029596050496494965) -+----+-----------+-----------------+ | Member | Host | Role | State | TL | Lag in MB | Pending restart | +--------+------------+---------+---------+----+-----------+-----------------+ | pg-1 | 10.0.3.201 | Leader | running | 8 | | * | @@ -1261,8 +1293,8 @@ postgres@pg-1:~$ patronictl list -e ``` ```Bash -postgres@pg-1:~$ patronictl restart 14-main --force -+ Cluster: 14-main (7029596050496494965) -+----+-----------+-----------------+ +postgres@pg-1:~$ patronictl restart 15-main --force ++ Cluster: 15-main (7029596050496494965) -+----+-----------+-----------------+ | Member | Host | Role | State | TL | Lag in MB | Pending restart | +--------+------------+---------+---------+----+-----------+-----------------+ | pg-1 | 10.0.3.201 | Leader | running | 8 | | * | @@ -1277,24 +1309,24 @@ Success: restart on member pg-2 Test de la configuration de l'archivage sur le nœud `pg-1` : ```Bash -postgres@pg-1:~$ pgbackrest --stanza main --log-level-console detail check +postgres@pg-1:~$ pgbackrest --stanza main check ``` ```console 2021-11-12 15:57:04.000 P00 INFO: check command begin 2.35: --exec-id=13216- 4a7c4a92 --log-level-console=detail --log-level-file=detail --pg1-path=/var/lib/ -postgresql/14/main --pg1-port=5432 --pg1-socket-path=/var/run/postgresql -- +postgresql/15/main --pg1-port=5432 --pg1-socket-path=/var/run/postgresql -- repo1-host=backup --repo1-host-user=postgres --stanza=main 2021-11-12 15:57:04.616 P00 INFO: check repo1 configuration (primary) 2021-11-12 15:57:05.083 P00 INFO: check repo1 archive for WAL (primary) 2021-11-12 15:57:08.425 P00 INFO: WAL segment 000000080000000000000005 -successfully archived to '/var/lib/pgbackrest/archive/main/14-1/ +successfully archived to '/var/lib/pgbackrest/archive/main/15-1/ 0000000800000000/000000080000000000000005- b0929d740c7996974992ecd7b9b189b37d06a896.gz' on repo1 2021-11-12 15:57:08.528 P00 INFO: check command end: completed successfully (4531ms) ``` -#### Configuration sur la machine hébergeant les sauvegardes +#### **Configuration sur la machine hébergeant les sauvegardes** Sur la machine `backup`, créer le script de détermination du _leader_ (le rendre exécutable) : @@ -1305,12 +1337,15 @@ postgres@backup:~$ vim ~/leader.sh && chmod +x leader.sh ```Bash #! /bin/bash -SCOPE='14-main' +SCOPE='15-main' curl -s http://e1:2379/v2/keys/postgresql-common/"$SCOPE"/leader | jq -r .node.value ``` -##### Configuration de pgBackrest +##### **Configuration de pgBackrest** +Nous avons choisit d'opérer en mode _pull_, les sauvegardes seront exécutées +sur la machine `backup` et récupérées depuis le primaire courant. + La configuration se fait dans le fichier `/etc/pgbackrest.conf` : ```ini @@ -1318,58 +1353,51 @@ La configuration se fait dans le fichier `/etc/pgbackrest.conf` : repo1-path=/var/lib/pgbackrest repo1-retention-full=2 start-fast=y -log-level-console=detail +log-level-console=info +log-level-file=info [main] -pg1-path=/var/lib/postgresql/14/main +pg1-path=/var/lib/postgresql/15/main pg1-host-user=postgres pg1-user=postgres pg1-port=5432 ``` -##### test d'une sauvegarde +On déterminera l'instance qui sera utilisée pour récupérer la sauvegarde, au +moment de la sauvegarde. + +**Test d'une sauvegarde** ```Bash postgres@backup:~$ pgbackrest --stanza main --pg1-host=$(./leader.sh) backup --type=full ``` ```console -2021-11-12 16:32:32.128 P00 INFO: backup command begin 2.35: --exec-id=6717- -e7512f6c --log-level-console=detail --pg1-host=pg-1 --pg1-host-user=postgres -- -pg1-path=/var/lib/postgresql/14/main --pg1-port=5432 --pg1-user=postgres -- -repo1-path=/var/lib/pgbackrest --repo1-retention-full=2 --stanza=main --start- -fast --type=full -2021-11-12 16:32:33.114 P00 INFO: execute non-exclusive pg_start_backup(): -backup begins after the requested immediate checkpoint completes -2021-11-12 16:32:34.129 P00 INFO: backup start archive = -00000008000000000000000B, lsn = 0/B000028 -2021-11-12 16:32:36.709 P01 DETAIL: backup file pg-1:/var/lib/postgresql/14/ -main/base/13707/1255 (752KB, 2%) checksum -2bac9bc6e62f6059736f9152a045bb43c0832231 -2021-11-12 16:32:37.119 P01 DETAIL: backup file pg-1:/var/lib/postgresql/14/ -main/base/13706/1255 (752KB, 5%) checksum -2bac9bc6e62f6059736f9152a045bb43c0832231 -... -... -2021-11-12 16:32:45.786 P01 DETAIL: backup file pg-1:/var/lib/postgresql/14/ -main/base/1/13528 (0B, 100%) -2021-11-12 16:32:45.791 P00 INFO: execute non-exclusive pg_stop_backup() and -wait for all WAL segments to archive -2021-11-12 16:32:46.095 P00 INFO: backup stop archive = -00000008000000000000000B, lsn = 0/B000138 -2021-11-12 16:32:46.101 P00 DETAIL: wrote 'backup_label' file returned from -pg_stop_backup() -2021-11-12 16:32:46.103 P00 INFO: check archive for segment(s) -00000008000000000000000B:00000008000000000000000B -2021-11-12 16:32:49.611 P00 INFO: new backup label = 20211112-163233F -2021-11-12 16:32:49.673 P00 INFO: full backup size = 25.1MB, file total = 952 -2021-11-12 16:32:49.674 P00 INFO: backup command end: completed successfully -(17556ms) -2021-11-12 16:32:49.675 P00 INFO: expire command begin 2.35: --exec-id=6717- -e7512f6c --log-level-console=detail --repo1-path=/var/lib/pgbackrest --repo1- -retention-full=2 --stanza=main -2021-11-12 16:32:49.686 P00 INFO: expire command end: completed successfully -(11ms) + +2023-02-09 18:43:38.424 P00 INFO: backup command begin 2.44: --exec-id=1116-00f26290 +--log-level-console=info --log-level-file=info --pg1-host=pg-1 --pg1-host-user=postgres -- +pg1-path=/var/lib/postgresql/15/main --pg1-port=5432 --pg1-user=postgres --repo1-path=/var/ +lib/pgbackrest --repo1-retention-full=2 --stanza=main --start-fast --type=full +2023-02-09 18:43:39.363 P00 INFO: execute non-exclusive backup start: backup begins +after the requested immediate checkpoint completes +2023-02-09 18:43:40.475 P00 INFO: backup start archive = 000000070000000000000013, lsn = 0/13000028 +2023-02-09 18:43:40.475 P00 INFO: check archive for prior segment 000000070000000000000012 +2023-02-09 18:44:06.600 P00 INFO: execute non-exclusive backup stop and wait for all WAL segments to archive +2023-02-09 18:44:06.905 P00 INFO: backup stop archive = 000000070000000000000013, lsn = 0/13000138 +2023-02-09 18:44:06.955 P00 INFO: check archive for segment(s) +000000070000000000000013:000000070000000000000013 +2023-02-09 18:44:07.533 P00 INFO: new backup label = 20230209-184339F +2023-02-09 18:44:07.798 P00 INFO: full backup size = 29.2MB, file total = 1261 +2023-02-09 18:44:07.819 P00 INFO: backup command end: completed successfully (29396ms) +2023-02-09 18:44:07.819 P00 INFO: expire command begin 2.44: --exec-id=1116-00f26290 +--log-level-console=info --log-level-file=info --repo1-path=/var/lib/pgbackrest +--repo1-retention-full=2 --stanza=main +2023-02-09 18:44:07.822 P00 INFO: repo1: expire full backup 20230209-183850F +2023-02-09 18:44:07.892 P00 INFO: repo1: remove expired backup 20230209-183850F +2023-02-09 18:44:07.971 P00 INFO: repo1: 15-1 remove archive, start = 000000070000000000000008, +stop = 00000007000000000000000A +2023-02-09 18:44:07.971 P00 INFO: expire command end: completed successfully (152ms) + ``` Vérification de l'état de la sauvegarde : @@ -1394,6 +1422,188 @@ stanza: main
+--- + +## Réplication synchrone + +La réplication synchrone permet de garantir que les données sont +écrites sur un ou plusieurs secondaires lors de la validation des +transactions. + +Elle permet de réduire quasi-totalement la perte de donnée lors d'un incident +(RPO). + +Il faut un minimum de trois paramètres ajoutés à la configuration dynamique pour +décrire la réplication synchrone : + +``` +synchronous_mode: true +synchronous_node_count: 1 +synchronous_standby_names: '*' +``` + +Après quelques secondes, l'un des réplicas passe en mode synchrone : + + +``` +postgres@pg-1:~$ patronictl list ++ Cluster: 15-main (7198182122558146054) ------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------+------------+--------------+---------+----+-----------+ +| pg-1 | 10.0.3.201 | Leader | running | 7 | | +| pg-2 | 10.0.3.202 | Replica | running | 7 | 0 | +| pg-3 | 10.0.3.203 | Sync Standby | running | 7 | 0 | ++--------+------------+--------------+---------+----+-----------+ +``` + + * La prochaine bascule ne sera possible que sur le nœud synchrone. + * Si le nœud synchrone est défaillant, un des secondaires restant passera en + mode synchrone (`synchronous_standby_names` et `synchronous_node_count` l'autorisent) + +**Perte du secondaire synchrone :** + +```Bash +$ sudo lxc-freeze pg-3 +``` + +**Quelques secondes plus tard :** + +``` ++ Cluster: 15-main (7198182122558146054) ------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------+------------+--------------+---------+----+-----------+ +| pg-1 | 10.0.3.201 | Leader | running | 7 | | +| pg-2 | 10.0.3.202 | Sync Standby | running | 7 | 0 | ++--------+------------+--------------+---------+----+-----------+ +``` + +--- + + +## Mise à jour mineure sans interruption de service + +Rappel : la réplication physique peut être mise en œuvre entre deux instances de +versions mineures différentes. (ex: 15.1 vers 15.2) + +La mise à jour mineure peut être faite nœud par nœud en commençant par les +secondaires asynchrones, puis par les secondaires synchrones. + +Dès qu'un deuxième secondaire synchrone est présent, le mise peut être faîte sur +le premier secondaire synchrone. + +Une fois tous les secondaires mis à jour, une bascule sur un des secondaires +synchrone à jour pourra être faite et l'ancien primaire sera alors mis à jour +de la même manière, puis redémarré : + + +**État de départ :** + +``` ++ Cluster: 15-main (7198182122558146054) ------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------+------------+--------------+---------+----+-----------+ +| pg-1 | 10.0.3.201 | Leader | running | 7 | | +| pg-2 | 10.0.3.202 | Replica | running | 7 | 0 | +| pg-3 | 10.0.3.203 | Sync Standby | running | 7 | 0 | ++--------+------------+--------------+---------+----+-----------+ +``` + + +**Mise à jour jour et redémarrage du premier secondaire asynchrone `pg-2` :** + +```Bash +... +$ patronictl restart 15-main pg-2 +``` + +**Passage à 2 nœuds synchrones :** + +```Bash +$ patronictl edit-config + +``` +```yaml +... +synchronous_node_count: 2 +... + +``` + +``` ++ Cluster: 15-main (7198182122558146054) ------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------+------------+--------------+---------+----+-----------+ +| pg-1 | 10.0.3.201 | Leader | running | 10 | | +| pg-2 | 10.0.3.202 | Sync Standby | running | 10 | 0 | +| pg-3 | 10.0.3.203 | Sync Standby | running | 10 | 0 | ++--------+------------+--------------+---------+----+-----------+ +``` + +**Mise à jour du nœud synchrone `pg-3` :** + +```Bash +... +$ patronictl restart 15-main pg-3 +``` + +**Bascule vers le secondaire synchrone mis à jour :** + +```Bash +... +$ patronictl switchover --master pg-1 --candidate pg-3 --force +``` + +**Mise à jour du primaire :** + +```Bash +... +$ patronictl restart 15-main pg-1 --force +``` + +**Effectuer la promotion et remettre le nombre de nœuds synchrone à `1` :** + + +```Bash +$ patronictl switchover --candidate pg-1 --master pg-3 --force +``` + +``` ++ Cluster: 15-main (7198182122558146054) ------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------+------------+--------------+---------+----+-----------+ +| pg-1 | 10.0.3.201 | Leader | running | 11 | | +| pg-2 | 10.0.3.202 | Sync Standby | running | 11 | 0 | +| pg-3 | 10.0.3.203 | Sync Standby | running | 11 | 0 | ++--------+------------+--------------+---------+----+-----------+ +``` + +```Bash +$ patronictl edit-config + +``` +```yaml +... +synchronous_node_count: 1 +... + +``` + +**Après quelques secondes :** + +``` ++ Cluster: 15-main (7198182122558146054) ------+----+-----------+ +| Member | Host | Role | State | TL | Lag in MB | ++--------+------------+--------------+---------+----+-----------+ +| pg-1 | 10.0.3.201 | Leader | running | 11 | | +| pg-2 | 10.0.3.202 | Sync Standby | running | 11 | 0 | +| pg-3 | 10.0.3.203 | Replica | running | 11 | 0 | ++--------+------------+--------------+---------+----+-----------+ +``` + +Aucun arrêt de service et aucune perte de données due à l'opération. + + + --- ## Références @@ -1402,6 +1612,7 @@ stanza: main * Etcd : * Patroni : + * Formation HAPAT : * Dalibo :
diff --git a/fr/patroni/patroni.pdf b/fr/patroni/patroni.pdf new file mode 100644 index 0000000..24f17bb Binary files /dev/null and b/fr/patroni/patroni.pdf differ diff --git a/fr/patroni/patroni.slides.html b/fr/patroni/patroni.slides.html new file mode 100644 index 0000000..59ccc1c --- /dev/null +++ b/fr/patroni/patroni.slides.html @@ -0,0 +1,7371 @@ + + + + + + + + Haute disponibilité avec Patroni + + + + + + + + + + + + + + + +
+
+ +
+

Haute disponibilité avec Patroni

+

Workshop Patroni

+

Dalibo & Contributors

+

+ v 19.02 (février 2023) +

+
+ + +
+

Haute disponibilité de service avec Patroni

+
+PostgreSQL + +
+ +
+
+ +

Introduction

+
+
    +
  • Principes
  • +
  • Mise en place
  • +
  • Installation et configuration des services
  • +
  • Construction d’un agrégat à bascule automatique
  • +
  • Création d’incidents
  • +
+
+ +
+
+ +

Principes

+
+
    +
  • Arbitrage par un quorum : DCS Etcd
  • +
  • Service PostgreSQL : désactivé
  • +
  • Contrôle complet par Patroni
  • +
+
+ +
+
+ +

DCS : Etcd

+
+
    +
  • Arbitre en cas de bascules
  • +
  • Stockage distribué de la configuration
  • +
  • Jeton leader (Etcd)
  • +
  • Instance primaire PostgreSQL
  • +
+
+ +
+
+ +

Mise en place de +l’infrastructure

+
+
    +
  • Connexion à la VM
  • +
  • Récupération du playbook Ansible
  • +
+
+ +
+
+ +

Connexion à votre machine +virtuelle

+
+

un seul point d’entrée : eformation.dalibo.com un port +attribué : 22XX

+
  $ ssh -p 22XX dalibo@eformation.dalibo.com
+
+ +
+
+ +

Playbook Ansible

+
+

Récupération du playbook Ansible à cette +adresse :

+

https://github.com/dalibo/workshops/tree/ws15_patroni/fr/patroni/playbook/etcd-patroni

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FichierDescription
inventory.ymlinventaire des machines
setup.ymlplaybook +principal
exchange_ssh_keys.ymléchange des clefs ssh
demarre_tout.shdémarre tous les conteneurs
stoppe_tout.sharrête tous les conteneurs
teardown.ymlplaybook de destruction +massive
+
+ +
+
+ +
+

L’infrastructure complète peut être créée à l’aide des +commandes :

+
 $ sudo apt install -y ansible
+ $ sudo ansible-playbook -f 7 -i inventory.yml setup.yml
+...
+

Cette opération peut durer jusqu’à une vingtaine de minutes.

+
+ +
+
+ +

Installation d’Etcd

+
+
    +
  • Installation des paquets
  • +
  • Configuration
  • +
  • Démarrage du service
  • +
  • Vérification
  • +
+
+ +
+
+ +

Installation des +paquets

+
+
    +
  • Paquets essentiels : +
      +
    • etcd
    • +
    • curl
    • +
    • jq
    • +
    • iputils-ping
    • +
  • +
+
+ +
+
+ +

Configuration du service +Etcd

+
+
    +
  • Fichier : /etc/default/etcd
  • +
+
+ +
+
+ +

Démarrage du service

+
+
    +
  • Réinitialisation des bases Etcd
  • +
  • Démarrage du service etcd : +systemctl start etcd
  • +
+
+ +
+

Le leader doit être identique sur les trois nœuds, les trois +nœuds doivent retourner la même liste de membres.

+
+
+
+ +

Installation de PostgreSQL / +Patroni

+
+
    +
  • Installation +
      +
    • PostgreSQL
    • +
    • Patroni
    • +
    • pgBackrest
    • +
  • +
+
+ +
+
+ +

Configuration de +Patroni

+
+

Sur tous les nœuds PostgreSQL/Patroni

+
    +
  • Configuration du DCS +
      +
    • /etc/patroni/dcs.yml
    • +
  • +
  • Génération de la configuration +
      +
    • pg_createconfig_patroni 15 main
    • +
  • +
+
+ +

Ces opérations doivent être répétées sur tous les nœuds +PostgreSQL/Patroni.

+
+
+ +

Création de +l’agrégat

+
+
    +
  • Démarrage du primaire
  • +
  • Création de l’utilisateur de réplication
  • +
  • Suppression des instances secondaires
  • +
  • Démarrage des instances secondaires
  • +
+
+ +
+
+ +
Vérifications
+
+
    +
  • Liste des nœuds Patroni
  • +
  • Test de bascule manuelle vers chaque nœud
  • +
+
+ +
+
+ +

Création d’incidents

+
+
    +
  • Perte totale du DCS
  • +
  • Freeze du nœud primaire Patroni
  • +
  • Bascule manuelle
  • +
+
+ +
+
+ +

Perte totale du DCS

+
+
    +
  • Perte de tous les nœuds Etcd
  • +
+
+ +
+
+ +

Perte du nœud primaire +Patroni

+
+
    +
  • Perte du primaire courant
  • +
+
+ +
+
+ +

Modification de la +configuration

+
+
    +
  • patronictl edit-config
  • +
+
+ +
+
+ +

Sauvegardes

+
+
    +
  • Installation pgBackrest
  • +
  • Configuration
  • +
  • Détermination du primaire
  • +
  • Archivage
  • +
  • Sauvegarde
  • +
+
+ +
+
+ +

Réplication synchrone

+

La réplication synchrone permet de garantir que les données sont +écrites sur un ou plusieurs secondaires lors de la validation des +transactions.

+

Elle permet de réduire quasi-totalement la perte de donnée lors d’un +incident (RPO).

+

Il faut un minimum de trois paramètres ajoutés à la configuration +dynamique pour décrire la réplication synchrone :

+
synchronous_mode: true
+synchronous_node_count: 1
+synchronous_standby_names: '*'
+

Après quelques secondes, l’un des réplicas passe en mode +synchrone :

+
postgres@pg-1:~$ patronictl list
++ Cluster: 15-main (7198182122558146054) ------+----+-----------+
+| Member | Host       | Role         | State   | TL | Lag in MB |
++--------+------------+--------------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader       | running |  7 |           |
+| pg-2   | 10.0.3.202 | Replica      | running |  7 |         0 |
+| pg-3   | 10.0.3.203 | Sync Standby | running |  7 |         0 |
++--------+------------+--------------+---------+----+-----------+
+
    +
  • La prochaine bascule ne sera possible que sur le nœud +synchrone.
  • +
  • Si le nœud synchrone est défaillant, un des secondaires restant +passera en mode synchrone (synchronous_standby_names et +synchronous_node_count l’autorisent)
  • +
+

Perte du secondaire synchrone :

+
$ sudo lxc-freeze pg-3
+

Quelques secondes plus tard :

+
+ Cluster: 15-main (7198182122558146054) ------+----+-----------+
+| Member | Host       | Role         | State   | TL | Lag in MB |
++--------+------------+--------------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader       | running |  7 |           |
+| pg-2   | 10.0.3.202 | Sync Standby | running |  7 |         0 |
++--------+------------+--------------+---------+----+-----------+
+
+
+ +

Mise à jour +mineure sans interruption de service

+

Rappel : la réplication physique peut être mise en œuvre entre deux +instances de versions mineures différentes. (ex: 15.1 vers 15.2)

+

La mise à jour mineure peut être faite nœud par nœud en commençant +par les secondaires asynchrones, puis par les secondaires +synchrones.

+

Dès qu’un deuxième secondaire synchrone est présent, le mise peut +être faîte sur le premier secondaire synchrone.

+

Une fois tous les secondaires mis à jour, une bascule sur un des +secondaires synchrone à jour pourra être faite et l’ancien primaire sera +alors mis à jour de la même manière, puis redémarré :

+

État de départ :

+
+ Cluster: 15-main (7198182122558146054) ------+----+-----------+
+| Member | Host       | Role         | State   | TL | Lag in MB |
++--------+------------+--------------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader       | running |  7 |           |
+| pg-2   | 10.0.3.202 | Replica      | running |  7 |         0 |
+| pg-3   | 10.0.3.203 | Sync Standby | running |  7 |         0 |
++--------+------------+--------------+---------+----+-----------+
+

Mise à jour jour et redémarrage du premier secondaire +asynchrone pg-2 :

+
...
+$ patronictl restart 15-main pg-2
+

Passage à 2 nœuds synchrones :

+
$ patronictl edit-config
+
...
+synchronous_node_count: 2
+...
+
+ Cluster: 15-main (7198182122558146054) ------+----+-----------+
+| Member | Host       | Role         | State   | TL | Lag in MB |
++--------+------------+--------------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader       | running | 10 |           |
+| pg-2   | 10.0.3.202 | Sync Standby | running | 10 |         0 |
+| pg-3   | 10.0.3.203 | Sync Standby | running | 10 |         0 |
++--------+------------+--------------+---------+----+-----------+
+

Mise à jour du nœud synchrone +pg-3 :

+
...
+$ patronictl restart 15-main pg-3
+

Bascule vers le secondaire synchrone mis à jour +:

+
...
+$ patronictl switchover --master pg-1 --candidate pg-3 --force
+

Mise à jour du primaire :

+
...
+$ patronictl restart 15-main pg-1 --force
+

Effectuer la promotion et remettre le nombre de nœuds +synchrone à 1 :

+
$ patronictl switchover --candidate pg-1 --master pg-3 --force
+
+ Cluster: 15-main (7198182122558146054) ------+----+-----------+
+| Member | Host       | Role         | State   | TL | Lag in MB |
++--------+------------+--------------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader       | running | 11 |           |
+| pg-2   | 10.0.3.202 | Sync Standby | running | 11 |         0 |
+| pg-3   | 10.0.3.203 | Sync Standby | running | 11 |         0 |
++--------+------------+--------------+---------+----+-----------+
+
$ patronictl edit-config
+
...
+synchronous_node_count: 1
+...
+

Après quelques secondes :

+
+ Cluster: 15-main (7198182122558146054) ------+----+-----------+
+| Member | Host       | Role         | State   | TL | Lag in MB |
++--------+------------+--------------+---------+----+-----------+
+| pg-1   | 10.0.3.201 | Leader       | running | 11 |           |
+| pg-2   | 10.0.3.202 | Sync Standby | running | 11 |         0 |
+| pg-3   | 10.0.3.203 | Replica      | running | 11 |         0 |
++--------+------------+--------------+---------+----+-----------+
+

Aucun arrêt de service et aucune perte de données due à +l’opération.

+
+
+ +

Références

+ + +
+
+ +
+
+
+ + + + + + + + + + diff --git a/fr/patroni/playbook/etcd-patroni/demarre_tout.sh b/fr/patroni/playbook/etcd-patroni/demarre_tout.sh new file mode 100755 index 0000000..4e83bd8 --- /dev/null +++ b/fr/patroni/playbook/etcd-patroni/demarre_tout.sh @@ -0,0 +1 @@ +for i in e1 e2 e3 backup pg-1 pg-2 pg-3 ; do sudo lxc-start $i ; done diff --git a/fr/patroni/playbook/etcd-patroni/setup.yml b/fr/patroni/playbook/etcd-patroni/setup.yml index 1bfc47e..1a9f70a 100644 --- a/fr/patroni/playbook/etcd-patroni/setup.yml +++ b/fr/patroni/playbook/etcd-patroni/setup.yml @@ -1,29 +1,43 @@ --- - # CREATE STOPPED CONTAINERS - hosts: localhost connection: local become: true become_user: root - gather_facts: false + gather_facts: true vars: - interface: lxcbr0 tasks: +# CHECK IF DISTRO AND RELEASE + - name: 'check distro and release' + fail: msg="Only Buster and Bullseye releases of Debian are supported here" + when: ansible_distribution != "Debian" and ( ansible_distribution_release != "bullseye" or ansible_distribution != "buster" ) - - name: apt lxc packages are installed on host + - name: apt lxc packages are installed on host (Debian Bullseye) apt: name: - lxc - lxc-dev - python3-pip - python3-lxc + - sudo + when: ansible_distribution_release == "bullseye" + + - name: apt lxc packages are installed on host (Debian Buster) + apt: + name: + - lxc + - lxc-dev - python-lxc + - python3-pip + - python3-lxc - sudo + when: ansible_distribution_release == "buster" - name: generate local root ssh-key if not there shell: @@ -86,14 +100,14 @@ connection: local become: true become_user: root - gather_facts: false + gather_facts: true vars: - interface: lxcbr0 tasks: - - name: Create a stopped container + - name: Create a stopped container (Buster) delegate_to: localhost lxc_container: name: "{{ inventory_hostname }}" @@ -107,6 +121,38 @@ - lxc.net.0.link = {{ interface }} - lxc.net.0.ipv4.address = {{ ansible_host }}/24 - lxc.net.0.ipv4.gateway = auto + when: ansible_distribution_release == "buster" + + - name: Create a stopped container (Bullseye) + delegate_to: localhost + lxc_container: + name: "{{ inventory_hostname }}" + container_log: true + template: debian + state: started + template_options: --release bullseye + container_config: + - lxc.net.0.type = veth + - lxc.net.0.flags = up + - lxc.net.0.link = {{ interface }} + - lxc.net.0.ipv4.address = {{ ansible_host }}/24 + - lxc.net.0.ipv4.gateway = auto + when: ansible_distribution_release == "bullseye" + +# File /etc/hosts + +- hosts: localhost + gather_facts: false + tasks: + + - name: add all the hosts to /etc/hosts + lineinfile: + path: "/etc/hosts" + regexp: "{{ hostvars[item].ansible_host }} {{ item }}" + line: "{{ hostvars[item].ansible_host }} {{ item }}" + state: present + backup: no + loop: "{{ groups['all'] }}" # SETUP CONTAINERS @@ -122,7 +168,6 @@ my_ssh_key: "~root/.ssh/id_rsa.pub" - # CLEANUP known_hosts root - name: cleanup local know_hosts by name for root delegate_to: localhost @@ -244,20 +289,40 @@ state: present update_cache: false - - name: Configure pgdg repository - become: true - become_user: root - copy: - dest: /etc/apt/sources.list.d/pgdg.list - content: 'deb http://apt.postgresql.org/pub/repos/apt {{ debian_codename }}-pgdg main' +#- - name: Import pgdg gnupg key +#- become: true +#- become_user: root +#- shell: +#- warn: false +#- cmd: +#- curl -s https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /etc/apt/trusted.gpg.d/apt.postgresql.org.gpg >/dev/null + + - name: "Adding postgres key" + apt_key: + url: "https://www.postgresql.org/media/keys/ACCC4CF8.asc" + state: "present" + + - name: "Adding postgres repo" + apt_repository: + filename: "pgdg" + repo: "deb http://apt.postgresql.org/pub/repos/apt {{ ansible_distribution_release }}-pgdg main" + state: "present" + + + # ------------- +#- - name: Configure pgdg repository +#- become: true +#- become_user: root +#- copy: +#- dest: /etc/apt/sources.list.d/pgdg.list +#- content: 'deb http://apt.postgresql.org/pub/repos/apt {{ ansible_distribution_release }}-pgdg main' +#- + + #------------------ + + + - - name: Import pgdg gnupg key - become: true - become_user: root - shell: - warn: false - cmd: - curl -s https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /etc/apt/trusted.gpg.d/apt.postgresql.org.gpg >/dev/null - name: apt update become: yes @@ -308,12 +373,33 @@ - pgbackrest state: present -# File /etc/hosts -- hosts: localhost - gather_facts: false +- hosts: all + gather_facts: no + become: yes + become_user: root + tasks: + - name: setup network interfaces + copy: + dest: /etc/network/interfaces + content: | + auto lo + iface lop inet loopback + auto eth0 + iface eth0 inet static + address {{ ansible_host }}/24 + gateway 10.0.3.1 + + - name: restart a container + delegate_to: localhost + become: yes + become_user: root + lxc_container: + name: "{{ inventory_hostname }}" + state: restarted + - name: add all the hosts to /etc/hosts lineinfile: path: "/etc/hosts" @@ -323,5 +409,3 @@ backup: no loop: "{{ groups['all'] }}" -# # --------------- -# # EOF diff --git a/fr/patroni/playbook/etcd-patroni/stoppe_tout.sh b/fr/patroni/playbook/etcd-patroni/stoppe_tout.sh new file mode 100755 index 0000000..12d11a4 --- /dev/null +++ b/fr/patroni/playbook/etcd-patroni/stoppe_tout.sh @@ -0,0 +1,3 @@ +#!/bin/bash +set -x +for i in pg-2 pg-3 pg-1 e1 e2 e3 backup ; do sudo lxc-stop $i ; done diff --git a/fr/patroni/playbook/etcd-patroni/warmup.sh b/fr/patroni/playbook/etcd-patroni/warmup.sh index 851d756..83830d6 100755 --- a/fr/patroni/playbook/etcd-patroni/warmup.sh +++ b/fr/patroni/playbook/etcd-patroni/warmup.sh @@ -1,5 +1,8 @@ #! /bin/bash +# Ce script permet de récupérer l'image Debian de base pour +# accélérer la création des conteneurs LXC suivants. + set -x sudo lxc-create -n warmup -t debian -- -r buster diff --git a/fr/ws14/140-postgresql_14.md b/fr/ws14/140-postgresql_14.md index 4c0defc..2c82bed 100644 --- a/fr/ws14/140-postgresql_14.md +++ b/fr/ws14/140-postgresql_14.md @@ -247,7 +247,7 @@ Nous allons décrire ces nouveautés plus en détail. \newpage -### Partionnement +### Partitionnement ---- @@ -263,12 +263,15 @@ Nous allons décrire ces nouveautés plus en détail. !include include/109_add_support_for_partitioned_tables_and_indexes_in_reindex.md + + https://gitlab.dalibo.info/formation/workshops/-/issues/110 !include include/110_autovacuum_handle_analyze_for_partitioned_tables.md +REVERT !! +--> ---- @@ -371,7 +374,6 @@ possible. ---- - #### Lecture asynchrone des tables distantes diff --git a/fr/ws14/include/101_idle_session_timeout.md b/fr/ws14/include/101_idle_session_timeout.md index c3150a0..f6995d0 100644 --- a/fr/ws14/include/101_idle_session_timeout.md +++ b/fr/ws14/include/101_idle_session_timeout.md @@ -25,7 +25,7 @@ Discussion Le paramètre `idle_session_timeout` définit la durée maximale sans activité entre deux requêtes lorsque l'utilisateur n'est pas dans une transaction. Son comportement est similaire à celui du paramètre `idle_in_transaction_session_timeout` -introduit dans PostgreSQL 9.6, qui ne concerne que les session en statut +introduit dans PostgreSQL 9.6, qui ne concerne que les sessions en statut `idle in transaction`. Ce paramètre a pour conséquence d'interrompre toute session inactive depuis plus diff --git a/fr/ws14/include/110_autovacuum_handle_analyze_for_partitioned_tables.md b/fr/ws14/include/110_autovacuum_handle_analyze_for_partitioned_tables.md index c601c87..2f8d4c3 100644 --- a/fr/ws14/include/110_autovacuum_handle_analyze_for_partitioned_tables.md +++ b/fr/ws14/include/110_autovacuum_handle_analyze_for_partitioned_tables.md @@ -8,8 +8,16 @@ Discussion * https://gitlab.dalibo.info/formation/workshops/-/issues/110 +REVERT ! -> suppression du slide + + --> + +https://www.postgresql.org/message-id/E1mFkCk-0001UK-F7%40gemulon.postgresql.org + + +
* Les tables partitionnées ne sont plus exclues lors de la phase `ANALYZE` de l'autovacuum