{"id":6853,"date":"2026-05-12T18:05:01","date_gmt":"2026-05-12T16:05:01","guid":{"rendered":"https:\/\/rootfan.com\/?p=6853"},"modified":"2026-05-12T18:28:18","modified_gmt":"2026-05-12T16:28:18","slug":"laboratoire-de-sauvegarde-et-de-restauration-postgresql","status":"publish","type":"post","link":"https:\/\/rootfan.com\/fr\/postgresql-backup-recovery-lab\/","title":{"rendered":"Laboratoire de sauvegarde et de r\u00e9cup\u00e9ration PostgreSQL 18 sur Ubuntu 24.04 \u2014 pg_dump, pg_basebackup et pgBackRest"},"content":{"rendered":"<p>Si vous travaillez avec PostgreSQL en production, les sauvegardes ne sont pas facultatives.<\/p>\n\n\n\n<p>Dans ce laboratoire, j'ai mis en place un environnement complet de sauvegarde et de restauration PostgreSQL 18 sur Ubuntu 24.04 et test\u00e9 les trois principales approches de sauvegarde :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>sauvegardes logiques avec <code>pg_dump<\/code><\/li>\n\n\n\n<li>sauvegardes physiques avec <code>pg_basebackup<\/code><\/li>\n\n\n\n<li>sauvegardes de niveau production avec pgBackRest, y compris l'archivage des WAL et la r\u00e9cup\u00e9ration \u00e0 un instant T (PITR)<\/li>\n<\/ul>\n\n\n\n<p>Tout a \u00e9t\u00e9 test\u00e9 sur une vraie VM avec des exercices de r\u00e9cup\u00e9ration r\u00e9els \u2014 pas des simulations.<\/p>\n\n\n\n<!--more-->\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>Table des mati\u00e8res<\/h2><nav><ul><li><a href=\"#the-environment\">L'environnement<\/a><\/li><li><a href=\"#installing-postgresql-18\">Installation de PostgreSQL 18<\/a><\/li><li><a href=\"#creating-the-lab-database\">Cr\u00e9ation de la base de donn\u00e9es du laboratoire<\/a><\/li><li><a href=\"#creating-the-tables\">Cr\u00e9ation des tables<\/a><\/li><li><a href=\"#creating-backup-directories\">Cr\u00e9ation de r\u00e9pertoires de sauvegarde<\/a><\/li><li><a href=\"#part-1-pg-dump\">Partie 1 - pg_dump<\/a><ul><li><a href=\"#full-database-backup\">Sauvegarde compl\u00e8te de la base de donn\u00e9es<\/a><\/li><li><a href=\"#schema-only-backup\">Sauvegarde uniquement du sch\u00e9ma<\/a><\/li><li><a href=\"#single-table-backup\">Sauvegarde d'une seule table<\/a><\/li><li><a href=\"#full-restore-test\">Test de restauration compl\u00e8te<\/a><\/li><li><a href=\"#disaster-recovery-drill\">Exercice de reprise apr\u00e8s sinistre \u2014 Restauration d'une table<\/a><\/li><\/ul><\/li><li><a href=\"#part-2-pg-basebackup\">Partie 2 \u2014 pg_basebackup<\/a><ul><li><a href=\"#checking-wal-configuration\">V\u00e9rification de la configuration de WAL<\/a><\/li><li><a href=\"#creating-the-physical-backup\">Cr\u00e9ation de la sauvegarde physique<\/a><\/li><li><a href=\"#verifying-the-backup\">V\u00e9rification de la sauvegarde<\/a><\/li><li><a href=\"#full-physical-restore-drill\">Exercice de restauration physique compl\u00e8te<\/a><\/li><\/ul><\/li><li><a href=\"#part-3-pgbackrest\">Partie 3 \u2014 pgBackRest<\/a><ul><li><a href=\"#installing-pgbackrest\">Installation de pgBackRest<\/a><\/li><li><a href=\"#creating-the-repository-directory\">Cr\u00e9er le r\u00e9pertoire du d\u00e9p\u00f4t<\/a><\/li><li><a href=\"#configuring-pgbackrest\">Configuration de pgBackRest<\/a><\/li><li><a href=\"#configuring-wal-archiving\">Configuration de l'archivage WAL<\/a><\/li><li><a href=\"#creating-the-stanza-and-running-check\">Cr\u00e9ation de la strophe et ex\u00e9cution de la v\u00e9rification<\/a><\/li><li><a href=\"#full-backup\">Sauvegarde compl\u00e8te<\/a><\/li><li><a href=\"#differential-backup\">Sauvegarde diff\u00e9rentielle<\/a><\/li><li><a href=\"#incremental-backup\">Sauvegarde incr\u00e9mentielle<\/a><\/li><li><a href=\"#point-in-time-recovery\">Restauration \u00e0 un instant T<\/a><\/li><\/ul><\/li><li><a href=\"#summary\">R\u00e9sum\u00e9<\/a><\/li><li><a href=\"#final-thoughts\">R\u00e9flexions finales<\/a><\/li><\/ul><\/nav><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-environment\">L'environnement<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Composant<\/th><th>Valeur<\/th><\/tr><\/thead><tbody><tr><td>Syst\u00e8me d'exploitation<\/td><td>Ubuntu 24.04<\/td><\/tr><tr><td>PostgreSQL<\/td><td>18 (d\u00e9p\u00f4t PGDG)<\/td><\/tr><tr><td>Outils de sauvegarde<\/td><td>pg_dump, pg_basebackup, pgBackRest<\/td><\/tr><tr><td>Type de laboratoire<\/td><td>VM unique<\/td><\/tr><tr><td>D\u00e9p\u00f4t<\/td><td>Syst\u00e8me de fichiers local<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"installing-postgresql-18\">Installation de PostgreSQL 18<\/h2>\n\n\n\n<p>J'ai utilis\u00e9 le d\u00e9p\u00f4t officiel PGDG plut\u00f4t que le paquet par d\u00e9faut d'Ubuntu, qui contient une version plus ancienne.<\/p>\n\n\n\n<p>Installer l'assistant de d\u00e9p\u00f4t :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo apt install -y postgresql-common\n<\/pre><\/div>\n\n\n<p>Ex\u00e9cutez le script de configuration PGDG :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo \/usr\/share\/postgresql-common\/pgdg\/apt.postgresql.org.sh\n<\/pre><\/div>\n\n\n<p>Installer PostgreSQL 18 :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo apt install -y postgresql-18\n<\/pre><\/div>\n\n\n<p>V\u00e9rifiez que le cluster est en cours d'ex\u00e9cution.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\npg_lsclusters\n<\/pre><\/div>\n\n\n<p>R\u00e9sultat attendu :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Ver Cluster Port Status Owner    R\u00e9pertoire de donn\u00e9es\n18  principal 5432 en ligne postgres \/var\/lib\/postgresql\/18\/main<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"creating-the-lab-database\">Cr\u00e9ation de la base de donn\u00e9es du laboratoire<\/h2>\n\n\n\n<p>Cr\u00e9er l'utilisateur de l'application :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres psql -c &quot;CREATE USER banking WITH PASSWORD &#039;banking&#039;;&quot;\n<\/pre><\/div>\n\n\n<p>Cr\u00e9er la base de donn\u00e9es :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres psql -c &quot;CREATE DATABASE bankingdb OWNER banking;&quot;\n<\/pre><\/div>\n\n\n<p>Connectez-vous en tant que l'utilisateur bancaire et cr\u00e9ez le sch\u00e9ma :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\npsql -h localhost -U banking -d bankingdb -c &quot;CREATE SCHEMA banking AUTHORIZATION banking;&quot;\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"creating-the-tables\">Cr\u00e9ation des tables<\/h2>\n\n\n\n<p>J'ai cr\u00e9\u00e9 cinq tables repr\u00e9sentant un petit sch\u00e9ma bancaire : branches, employees, customers, accounts et transactions. La cha\u00eene de cl\u00e9s \u00e9trang\u00e8res entre elles exerce les contraintes qui importent dans les sc\u00e9narios de restauration r\u00e9els.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\n-- Connected as banking@bankingdb\nCREATE TABLE banking.branches (\n  branch_id    INTEGER PRIMARY KEY,\n  branch_name  VARCHAR(100) NOT NULL,\n  city         VARCHAR(50),\n  country      VARCHAR(50),\n  opened_date  DATE\n);\n\nCREATE TABLE banking.employees (\n  employee_id  INTEGER PRIMARY KEY,\n  branch_id    INTEGER NOT NULL REFERENCES banking.branches(branch_id),\n  full_name    VARCHAR(100) NOT NULL,\n  role         VARCHAR(50),\n  hire_date    DATE\n);\n\nCREATE TABLE banking.customers (\n  customer_id  INTEGER PRIMARY KEY,\n  full_name    VARCHAR(100) NOT NULL,\n  email        VARCHAR(100),\n  country      VARCHAR(50),\n  created_at   TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE TABLE banking.accounts (\n  account_id    INTEGER PRIMARY KEY,\n  customer_id   INTEGER NOT NULL REFERENCES banking.customers(customer_id),\n  branch_id     INTEGER NOT NULL REFERENCES banking.branches(branch_id),\n  account_type  VARCHAR(20),\n  balance       NUMERIC(15,2) DEFAULT 0,\n  opened_at     TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\nCREATE TABLE banking.transactions (\n  txn_id       INTEGER PRIMARY KEY,\n  account_id   INTEGER NOT NULL REFERENCES banking.accounts(account_id),\n  employee_id  INTEGER REFERENCES banking.employees(employee_id),\n  txn_type     VARCHAR(20),\n  amount       NUMERIC(15,2) NOT NULL,\n  txn_date     TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n  description  VARCHAR(200)\n);\n<\/pre><\/div>\n\n\n<p>J'ai ins\u00e9r\u00e9 18 lignes sur les cinq tables \u2014 trois branches, quatre employ\u00e9s, trois clients, quatre comptes, quatre transactions. C'est l'\u00e9tat de base que chaque sauvegarde en laboratoire doit capturer et que chaque restauration doit reproduire.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"creating-backup-directories\">Cr\u00e9ation de r\u00e9pertoires de sauvegarde<\/h2>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\n# pg_dump output \u2014 runs as the fernando OS user\nmkdir -p \/home\/fernando\/backups\/pg-dump\n\n# pg_basebackup output \u2014 runs as postgres\nsudo mkdir -p \/var\/lib\/postgresql\/backups\/pg-basebackup\nsudo chown -R postgres:postgres \/var\/lib\/postgresql\/backups\nsudo chmod -R 750 \/var\/lib\/postgresql\/backups\n<\/pre><\/div>\n\n\n<p>Le r\u00e9pertoire du d\u00e9p\u00f4t pgBackRest est cr\u00e9\u00e9 s\u00e9par\u00e9ment dans la partie 3.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"part-1-pg-dump\">Partie 1 - pg_dump<\/h2>\n\n\n\n<p><code>pg_dump<\/code> cr\u00e9e une exportation logique d'une base de donn\u00e9es \u2014 des instructions SQL ou un format binaire compress\u00e9 qui peut \u00eatre rejou\u00e9 dans n'importe quelle instance PostgreSQL compatible.<\/p>\n\n\n\n<p>Meilleur pour :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>migrations inter-versions<\/li>\n\n\n\n<li>restauration d'une seule base de donn\u00e9es ou d'une seule table<\/li>\n\n\n\n<li>exportations de sch\u00e9ma uniquement pour la documentation ou la gestion des versions DDL<\/li>\n<\/ul>\n\n\n\n<p>Ne convient pas pour les sauvegardes PITR ou les bases de donn\u00e9es volumineuses o\u00f9 le temps de restauration doit \u00eatre mesur\u00e9 en minutes plut\u00f4t qu'en heures.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"full-database-backup\">Sauvegarde compl\u00e8te de la base de donn\u00e9es<\/h3>\n\n\n\n<p>J'ai utilis\u00e9 le format personnalis\u00e9 (<code>-F c<\/code>) \u2014 binaire comprim\u00e9, restaurable uniquement avec <code>pg_restore<\/code>, prend en charge la restauration parall\u00e8le et les options de s\u00e9lection de table.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nPGPASSWORD=banking pg_dump \\\n  -h localhost \\\n  -U banking \\\n  -F c \\\n  -d bankingdb \\\n  -f \/home\/fernando\/backups\/pg-dump\/bankingdb.dump\n<\/pre><\/div>\n\n\n<p>Inspecter le contenu de la sauvegarde sans restaurer :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\npg_restore -l \/home\/fernando\/backups\/pg-dump\/bankingdb.dump | head -30\n<\/pre><\/div>\n\n\n<p>La table des mati\u00e8res pr\u00e9sentait les sch\u00e9mas, les tables, les s\u00e9quences, les contraintes et les donn\u00e9es de table pour les cinq tables.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"schema-only-backup\">Sauvegarde uniquement du sch\u00e9ma<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nPGPASSWORD=banking pg_dump \\\n  -h localhost \\\n  -U banking \\\n  -F c \\\n  --schema-only \\\n  -d bankingdb \\\n  -f \/home\/fernando\/backups\/pg-dump\/bankingdb-schema.dump\n<\/pre><\/div>\n\n\n<p>Utile pour les migrations, le versionnement DDL et la recr\u00e9ation d'environnements cibles vides avant un chargement de donn\u00e9es.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"single-table-backup\">Sauvegarde d'une seule table<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nPGPASSWORD=banking pg_dump \\\n  -h localhost \\\n  -U banking \\\n  -F c \\\n  -t banking.transactions \\\n  -d bankingdb \\\n  -f \/home\/fernando\/backups\/pg-dump\/transactions.dump\n<\/pre><\/div>\n\n\n<p>La sauvegarde ne contient que la table des transactions et ses contraintes \u2014 pas les tables parentes. Sa restauration n\u00e9cessite que les tables parentes existent d\u00e9j\u00e0 dans la cible.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"full-restore-test\">Test de restauration compl\u00e8te<\/h3>\n\n\n\n<p>J'ai cr\u00e9\u00e9 une nouvelle base de donn\u00e9es vide et l'ai restaur\u00e9e avec la sauvegarde compl\u00e8te :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres psql -c &quot;CREATE DATABASE bankingdb_restore OWNER banking;&quot;\n\nPGPASSWORD=banking pg_restore \\\n  -h localhost \\\n  -U banking \\\n  -d bankingdb_restore \\\n  \/home\/fernando\/backups\/pg-dump\/bankingdb.dump\n<\/pre><\/div>\n\n\n<p>V\u00e9rifier que les d\u00e9comptes de lignes correspondent \u00e0 la source dans les cinq tables\u00a0:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nPGPASSWORD=banking psql -h localhost -U banking -d bankingdb_restore -c &quot;\nSELECT &#039;branches&#039;     AS table_name, COUNT(*) FROM banking.branches\nUNION ALL SELECT &#039;employees&#039;,    COUNT(*) FROM banking.employees\nUNION ALL SELECT &#039;customers&#039;,    COUNT(*) FROM banking.customers\nUNION ALL SELECT &#039;accounts&#039;,     COUNT(*) FROM banking.accounts\nUNION ALL SELECT &#039;transactions&#039;, COUNT(*) FROM banking.transactions;&quot;\n<\/pre><\/div>\n\n\n<p>Ensuite, abandonner la base de donn\u00e9es de test :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres psql -c &quot;DROP DATABASE bankingdb_restore;&quot;\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"disaster-recovery-drill\">Exercice de reprise apr\u00e8s sinistre \u2014 Restauration d'une table<\/h3>\n\n\n\n<p>Simulation d'une suppression accidentelle de table :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nPGPASSWORD=banking psql -h localhost -U banking -d bankingdb -c &quot;\nDROP TABLE banking.transactions CASCADE;&quot; \n<\/pre><\/div>\n\n\n<p>Restaur\u00e9 uniquement cette table du vidage de transactions d\u00e9di\u00e9 :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nPGPASSWORD=banking pg_restore \\\n  -h localhost \\\n  -U banking \\\n  -d bankingdb \\\n  -t transactions \\\n  \/home\/fernando\/backups\/pg-dump\/transactions.dump\n<\/pre><\/div>\n\n\n<p>V\u00e9rifi\u00e9 que les quatre rang\u00e9es \u00e9taient de retour. C'est l\u00e0 que <code>pg_dump<\/code> brille vraiment \u2014 r\u00e9cup\u00e9ration granulaire au niveau de l'objet sans toucher le reste de la base de donn\u00e9es.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"part-2-pg-basebackup\">Partie 2 \u2014 pg_basebackup<\/h2>\n\n\n\n<p><code>pg_basebackup<\/code> effectue une copie binaire au niveau du syst\u00e8me de fichiers de l'ensemble du cluster PostgreSQL. Il ne comprend ni les bases de donn\u00e9es ni les tables \u2014 il copie des fichiers.<\/p>\n\n\n\n<p>Meilleur pour :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>amor\u00e7age des r\u00e9pliques en continu<\/li>\n\n\n\n<li>instantan\u00e9s de r\u00e9cup\u00e9ration d'urgence d'un cluster entier<\/li>\n\n\n\n<li>migration de cluster vers un nouveau serveur<\/li>\n<\/ul>\n\n\n\n<p>Ne convient pas \u00e0 la r\u00e9cup\u00e9ration au niveau de la table ou de la base de donn\u00e9es \u2014 la restauration est tout ou rien au niveau du cluster.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"checking-wal-configuration\">V\u00e9rification de la configuration de WAL<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres psql -c &quot;SHOW wal_level; SHOW max_wal_senders;&quot;\n<\/pre><\/div>\n\n\n<p>R\u00e9sultat attendu :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> wal_level\n-----------\n r\u00e9plication\n\n max_wal_senders\n-----------------\n 10<\/code><\/pre>\n\n\n\n<p>Les deux sont correctement configur\u00e9s par d\u00e9faut sur PostgreSQL 18.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"creating-the-physical-backup\">Cr\u00e9ation de la sauvegarde physique<\/h3>\n\n\n\n<p>J'ai utilis\u00e9 le format tar<code>-F t<\/code>) \u2014 produit compress\u00e9 <code>base.tar.gz<\/code> et <code>pg_wal.tar.gz<\/code> archives plut\u00f4t qu'un arborescence de r\u00e9pertoires non compress\u00e9e.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres pg_basebackup \\\n  -D \/var\/lib\/postgresql\/backups\/pg-basebackup\/cluster \\\n  -F t \\\n  -z \\\n  -P \\\n  -c fast\n<\/pre><\/div>\n\n\n<p><code>-c rapide<\/code> \u00e9met un point de contr\u00f4le au d\u00e9but de la sauvegarde au lieu d'attendre le prochain programm\u00e9 \u2014 cela ajoute une br\u00e8ve pointe d'E\/S mais est le bon choix pour un laboratoire interactif.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"verifying-the-backup\">V\u00e9rification de la sauvegarde<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nls -lh \/var\/lib\/postgresql\/backups\/pg-basebackup\/cluster\/\n<\/pre><\/div>\n\n\n<p>Fichiers attendus :<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Fichier<\/th><th>Objectif<\/th><\/tr><\/thead><tbody><tr><td><code>base.tar.gz<\/code><\/td><td>annuaire de donn\u00e9es de cluster archive<\/td><\/tr><tr><td><code>pg_wal.tar.gz<\/code><\/td><td>WAL captur\u00e9 pendant la sauvegarde<\/td><\/tr><tr><td><code>manifeste_de_sauvegarde<\/code><\/td><td>liste de fichiers avec sommes de contr\u00f4le CRC32C (PostgreSQL 13+)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>V\u00e9rifiez l'int\u00e9grit\u00e9 avant de vous fier \u00e0 la sauvegarde :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres \/usr\/lib\/postgresql\/18\/bin\/pg_verifybackup --no-parse-wal \\\n  \/var\/lib\/postgresql\/backups\/pg-basebackup\/cluster\n<\/pre><\/div>\n\n\n<p>Une sauvegarde que vous n'avez jamais v\u00e9rifi\u00e9e est une sauvegarde \u00e0 laquelle vous ne pouvez pas faire confiance.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"full-physical-restore-drill\">Exercice de restauration physique compl\u00e8te<\/h3>\n\n\n\n<p>Arr\u00eater PostgreSQL :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo systemctl stop postgresql\n<\/pre><\/div>\n\n\n<p>Mettez de c\u00f4t\u00e9 le r\u00e9pertoire de donn\u00e9es existant :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo mv \/var\/lib\/postgresql\/18\/main \/var\/lib\/postgresql\/18\/main.before-restore\nsudo mkdir -p \/var\/lib\/postgresql\/18\/main\nsudo chown postgres:postgres \/var\/lib\/postgresql\/18\/main\nsudo chmod 700 \/var\/lib\/postgresql\/18\/main\n<\/pre><\/div>\n\n\n<p>Extraire l'archive de base :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres tar -xzf \\\n  \/var\/lib\/postgresql\/backups\/pg-basebackup\/cluster\/base.tar.gz \\\n  -C \/var\/lib\/postgresql\/18\/main\n<\/pre><\/div>\n\n\n<p>Extraire l'archive WAL :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres mkdir -p \/var\/lib\/postgresql\/18\/main\/pg_wal\nsudo -u postgres tar -xzf \\\n  \/var\/lib\/postgresql\/backups\/pg-basebackup\/cluster\/pg_wal.tar.gz \\\n  -C \/var\/lib\/postgresql\/18\/main\/pg_wal\n<\/pre><\/div>\n\n\n<p>D\u00e9marrer PostgreSQL<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo systemctl start postgresql\nsudo systemctl status postgresql@18-main\n<\/pre><\/div>\n\n\n<p>V\u00e9rifier que les d\u00e9comptes de lignes correspondent \u00e0 la r\u00e9f\u00e9rence dans les cinq tables.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nPGPASSWORD=banking psql -h localhost -U banking -d bankingdb -c &quot;\nSELECT &#039;branches&#039;     AS table_name, COUNT(*) FROM banking.branches\nUNION ALL SELECT &#039;employees&#039;,    COUNT(*) FROM banking.employees\nUNION ALL SELECT &#039;customers&#039;,    COUNT(*) FROM banking.customers\nUNION ALL SELECT &#039;accounts&#039;,     COUNT(*) FROM banking.accounts\nUNION ALL SELECT &#039;transactions&#039;, COUNT(*) FROM banking.transactions;&quot;\n<\/pre><\/div>\n\n\n<p>Supprimez le r\u00e9pertoire mis de c\u00f4t\u00e9 :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo rm -rf \/var\/lib\/postgresql\/18\/main.before-restore\n<\/pre><\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"part-3-pgbackrest\">Partie 3 \u2014 pgBackRest<\/h2>\n\n\n\n<p>pgBackRest est la solution de sauvegarde de niveau production pour PostgreSQL. Il combine la sauvegarde physique avec l'archivage WAL int\u00e9gr\u00e9, les types de sauvegarde incr\u00e9mentielle et diff\u00e9rentielle, la gestion de la r\u00e9tention, les E\/S parall\u00e8les et la r\u00e9cup\u00e9ration \u00e0 un instant T \u2014 le tout dans un seul outil.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"installing-pgbackrest\">Installation de pgBackRest<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo apt install -y pgbackrest\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"creating-the-repository-directory\">Cr\u00e9er le r\u00e9pertoire du d\u00e9p\u00f4t<\/h3>\n\n\n\n<p>pgBackRest ne cr\u00e9e pas automatiquement le r\u00e9pertoire du d\u00e9p\u00f4t \u2014 il doit exister et \u00eatre la propri\u00e9t\u00e9 de <code>PostgreSQL<\/code> avant que la strophe ne soit cr\u00e9\u00e9e.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo mkdir -p \/var\/lib\/pgbackrest\nsudo chown postgres:postgres \/var\/lib\/pgbackrest\nsudo chmod 750 \/var\/lib\/pgbackrest\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"configuring-pgbackrest\">Configuration de pgBackRest<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo mkdir -p \/etc\/pgbackrest\nsudo tee \/etc\/pgbackrest\/pgbackrest.conf &gt; \/dev\/null &lt;&lt; &#039;EOF&#039;\n&#x5B;global]\nrepo1-path=\/var\/lib\/pgbackrest\nrepo1-retention-full=2\nlog-level-console=info\nlog-level-file=detail\n\n&#x5B;main]\npg1-path=\/var\/lib\/postgresql\/18\/main\nEOF\n<\/pre><\/div>\n\n\n<p>Le nom du strophe <code>principal<\/code> correspond au nom du cluster PostgreSQL d'Ubuntu, celui par d\u00e9faut sur toute installation PostgreSQL d'Ubuntu.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"configuring-wal-archiving\">Configuration de l'archivage WAL<\/h3>\n\n\n\n<p>Trois param\u00e8tres sont n\u00e9cessaires pour <code>\/etc\/postgresql\/18\/main\/postgresql.conf<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\">\nwal_level = replica\narchive_mode = on\narchive_command = &#8216;pgbackrest &#8211;stanza=main archive-push %p'\n<\/div>\n\n\n<p><code>mode d'archivage<\/code> n\u00e9cessite un red\u00e9marrage complet de PostgreSQL \u2014 il ne s'agit pas d'un param\u00e8tre rechargeable.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo systemctl restart postgresql\n<\/pre><\/div>\n\n\n<p>V\u00e9rifier qu'ils ont pris effet :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres psql -c &quot;SHOW archive_mode; SHOW archive_command; SHOW wal_level;&quot;\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"creating-the-stanza-and-running-check\">Cr\u00e9ation de la strophe et ex\u00e9cution de la v\u00e9rification<\/h3>\n\n\n\n<p>Une stanza est la configuration nomm\u00e9e de pgBackRest pour un cluster PostgreSQL. <code>cr\u00e9er-une-strophe<\/code> initialise la structure de r\u00e9pertoire du d\u00e9p\u00f4t \u2014 ex\u00e9cutez-la une seule fois.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres pgbackrest --stanza=main stanza-create\n<\/pre><\/div>\n\n\n<p>Puis ex\u00e9cutez <code>V\u00e9rifier<\/code> \u2014 pgBackRest force un basculement WAL, archive le segment et le relit :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres pgbackrest --stanza=main check\n<\/pre><\/div>\n\n\n<p>C'est l'\u00e9tape de v\u00e9rification pr\u00e9alable \u00e0 la sauvegarde la plus importante. Si <code>V\u00e9rifier<\/code> \u00e9choue, les sauvegardes ne seront pas r\u00e9cup\u00e9rables.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"full-backup\">Sauvegarde compl\u00e8te<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres pgbackrest --stanza=main --type=full backup\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"differential-backup\">Sauvegarde diff\u00e9rentielle<\/h3>\n\n\n\n<p>Apr\u00e8s avoir ins\u00e9r\u00e9 une nouvelle ligne de transaction, j'ai effectu\u00e9 une sauvegarde diff\u00e9rentielle :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres pgbackrest --stanza=main --type=diff backup\n<\/pre><\/div>\n\n\n<p>La taille de la sauvegarde repr\u00e9sentait une petite fraction du total \u2014 seuls les blocs modifi\u00e9s ont \u00e9t\u00e9 stock\u00e9s.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"incremental-backup\">Sauvegarde incr\u00e9mentielle<\/h3>\n\n\n\n<p>Apr\u00e8s avoir ins\u00e9r\u00e9 une autre ligne :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres pgbackrest --stanza=main --type=incr backup\n<\/pre><\/div>\n\n\n<p>La cha\u00eene de sauvegarde est devenue : compl\u00e8te \u2192 diff\u00e9rentielle \u2192 incr\u00e9mentielle.<\/p>\n\n\n\n<p>Inspecter le catalogue complet :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres pgbackrest info\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"point-in-time-recovery\">Restauration \u00e0 un instant T<\/h3>\n\n\n\n<p>C'\u00e9tait la partie la plus importante du laboratoire.<\/p>\n\n\n\n<p>Capture l'horodatage actuel avant la catastrophe :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nRECOVERY_TARGET=$(sudo -u postgres psql -d bankingdb -Atc &quot;SELECT now()::text;&quot;)\necho &quot;Recovery target: $RECOVERY_TARGET&quot;\nsleep 2\n<\/pre><\/div>\n\n\n<p><code>CIBLE_DE_RECUPERATION<\/code> est une variable de shell bash. Elle stocke l'horodatage PostgreSQL exact captur\u00e9 avant la catastrophe. <\/p>\n\n\n\n<p>Toutes les \u00e9tapes PITR s'ex\u00e9cutent dans la m\u00eame session de terminal, de sorte que la variable reste active entre les commandes. <\/p>\n\n\n\n<p>Il est pass\u00e9 directement \u00e0 pgBackRest <code>--objectif<\/code> param\u00e8tre, qui lui indique de rejouer les WAL jusqu'\u00e0 ce moment pr\u00e9cis et de s'arr\u00eater.<\/p>\n\n\n\n<p>Simuler la catastrophe \u2014 supprimer la table des transactions :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nPGPASSWORD=banking psql -h localhost -U banking -d bankingdb -c &quot;\nDROP TABLE banking.transactions CASCADE;&quot; \n<\/pre><\/div>\n\n\n<p>Arr\u00eater PostgreSQL :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo systemctl stop postgresql\n<\/pre><\/div>\n\n\n<p>Restaurer \u00e0 l'horodatage avant la baisse :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo -u postgres pgbackrest --stanza=main \\\n  --type=time \\\n  &quot;--target=$RECOVERY_TARGET&quot; \\\n  --target-action=promote \\\n  --delta \\\n  restore\n<\/pre><\/div>\n\n\n<p><code>--delta<\/code> compare le r\u00e9pertoire de donn\u00e9es existant avec la sauvegarde et remplace uniquement les fichiers modifi\u00e9s \u2014 beaucoup plus rapide qu'une r\u00e9-extraction compl\u00e8te lorsque la plupart des fichiers sont inchang\u00e9s.<\/p>\n\n\n\n<p>D\u00e9marrez PostgreSQL \u2014 il entre en mode de r\u00e9cup\u00e9ration, rejoue les WAL jusqu'\u00e0 l'horodatage cible, puis est promu en lecture\/\u00e9criture :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nsudo systemctl start postgresql\nsudo tail -20 \/var\/log\/postgresql\/postgresql-18-main.log\n<\/pre><\/div>\n\n\n<p>V\u00e9rifiez que la table est de retour :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code\" data-no-translation=\"\"><pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nPGPASSWORD=banking psql -h localhost -U banking -d bankingdb -c &quot;\nSELECT COUNT(*) FROM banking.transactions;&quot; \n<\/pre><\/div>\n\n\n<p>Attendu : 6 lignes \u2014 4 de base plus les 2 ins\u00e9r\u00e9es pendant les \u00e9tapes diff\u00e9rentielle et incr\u00e9mentielle. PITR a fonctionn\u00e9.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"summary\">R\u00e9sum\u00e9<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Propri\u00e9t\u00e9<\/th><th>pg_dump<\/th><th>pg_basebackup<\/th><th>pgBackRest<\/th><\/tr><\/thead><tbody><tr><td>Niveau de sauvegarde<\/td><td>Logique (SQL)<\/td><td>Physique (syst\u00e8me de fichiers)<\/td><td>Physique (syst\u00e8me de fichiers)<\/td><\/tr><tr><td>Granularit\u00e9<\/td><td>Base de donn\u00e9es \/ sch\u00e9ma \/ table<\/td><td>Grappe enti\u00e8re<\/td><td>Grappe enti\u00e8re<\/td><\/tr><tr><td>Restauration multi-versions<\/td><td>Oui<\/td><td>Non<\/td><td>Non<\/td><\/tr><tr><td>Sauvegardes incr\u00e9mentielles<\/td><td>Non<\/td><td>Non (PG17+ limit\u00e9)<\/td><td>Oui<\/td><\/tr><tr><td>PITR<\/td><td>Non<\/td><td>Uniquement avec l'archivage WAL s\u00e9par\u00e9<\/td><td>Oui \u2014 int\u00e9gr\u00e9<\/td><\/tr><tr><td>Adapt\u00e9 \u00e0 la production quotidienne<\/td><td>Non<\/td><td>Non<\/td><td>Oui<\/td><\/tr><tr><td>Adapt\u00e9 \u00e0 la migration multi-versions<\/td><td>Oui<\/td><td>Non<\/td><td>Non<\/td><\/tr><tr><td>Adapt\u00e9 \u00e0 la r\u00e9cup\u00e9ration au niveau de la table<\/td><td>Oui<\/td><td>Non<\/td><td>Non<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>R\u00e8gles de d\u00e9cision pratiques :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Utilisation <code>pg_dump<\/code> pour les migrations inter-versions, les sauvegardes s\u00e9lectives par table et les instantan\u00e9s ad hoc.<\/li>\n\n\n\n<li>Utilisation <code>pg_basebackup<\/code> principalement pour amorcer des r\u00e9pliques en flux.<\/li>\n\n\n\n<li>Utilisez pgBackRest pour tout en production \u2014 incr\u00e9mentiels quotidiens, PITR, r\u00e9tention, archivage WAL, le tout dans un seul outil.<\/li>\n<\/ul>\n\n\n\n<p>Dans des environnements r\u00e9els, vous les combinez : pgBackRest pour la protection continue, <code>pg_dump<\/code> pour les migrations et la r\u00e9cup\u00e9ration au niveau de l'objet.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"final-thoughts\">R\u00e9flexions finales<\/h2>\n\n\n\n<p>Une sauvegarde n'est utile que si la restauration fonctionne r\u00e9ellement.<\/p>\n\n\n\n<p>La discipline la plus importante dans ce laboratoire n'\u00e9tait pas l'ex\u00e9cution des commandes de sauvegarde, mais l'ex\u00e9cution des exercices de restauration et la v\u00e9rification des comptes de lignes ensuite.<\/p>\n\n\n\n<p>La restauration des tests n'est pas facultative.<\/p>\n\n\n\n<p>Si vous pr\u00e9voyez une migration d'Oracle vers PostgreSQL et que vous avez besoin d'aide pour concevoir la strat\u00e9gie de sauvegarde et de restauration de l'environnement cible, <a href=\"https:\/\/rootfan.com\/fr\/services\/\">voir mes services \u2192<\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>If you work with PostgreSQL in production, backups are not optional. In this lab, I built a complete PostgreSQL 18 backup and recovery environment on Ubuntu 24.04 and tested all three major backup approaches: Everything was tested on a real VM with actual recovery drills \u2014 not simulations.<\/p>","protected":false},"author":1,"featured_media":6858,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"rank_math_focus_keyword":"PostgreSQL backup recovery pgBackRest","rank_math_title":"PostgreSQL 18 Backup & Recovery Lab \u2014 pg_dump, pg_basebackup, pgBackRest","rank_math_description":"A complete PostgreSQL 18 backup and recovery lab on Ubuntu 24.04 covering pg_dump, pg_basebackup and pgBackRest \u2014 including PITR and restore drills.","rank_math_robots":"","rank_math_og_title":"","rank_math_og_description":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[126],"tags":[77,78,160,159,158,161,163,110,81,4,29,162],"class_list":["post-6853","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-postgresql","tag-archive","tag-backup","tag-pg_basebackup","tag-pg_dump","tag-pgbackrest","tag-pitr","tag-point-in-time-recovery","tag-restore","tag-step-by-step","tag-tutorial","tag-ubuntu","tag-wal-archiving"],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/rootfan.com\/wp-content\/uploads\/pexels-photo-1753392.jpeg?fit=1716%2C1300&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/rootfan.com\/fr\/wp-json\/wp\/v2\/posts\/6853","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rootfan.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rootfan.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rootfan.com\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rootfan.com\/fr\/wp-json\/wp\/v2\/comments?post=6853"}],"version-history":[{"count":7,"href":"https:\/\/rootfan.com\/fr\/wp-json\/wp\/v2\/posts\/6853\/revisions"}],"predecessor-version":[{"id":6862,"href":"https:\/\/rootfan.com\/fr\/wp-json\/wp\/v2\/posts\/6853\/revisions\/6862"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rootfan.com\/fr\/wp-json\/wp\/v2\/media\/6858"}],"wp:attachment":[{"href":"https:\/\/rootfan.com\/fr\/wp-json\/wp\/v2\/media?parent=6853"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rootfan.com\/fr\/wp-json\/wp\/v2\/categories?post=6853"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rootfan.com\/fr\/wp-json\/wp\/v2\/tags?post=6853"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}