Module K3
Dalibo SCOP
26.09
10 septembre 2026
| Formation | Module K3 |
| Titre | Sauvegardes avec CloudNativePG |
| Révision | 26.09 |
| https://dali.bo/k3_pdf | |
| EPUB | https://dali.bo/k3_epub |
| HTML | https://dali.bo/k3_html |
| Slides | https://dali.bo/k3_slides |
| TP | https://dali.bo/k3_tp |
| TP (solutions) | https://dali.bo/k3_solutions |
Cette formation est sous licence CC-BY-NC-SA. Vous êtes libre de la redistribuer et/ou modifier aux conditions suivantes :
PostgreSQL® Postgres® et le logo Slonik sont des marques déposées par PostgreSQL Community Association of Canada.
Ce document ne couvre que les versions supportées de PostgreSQL au moment de sa rédaction, soit les versions 14 à 18.
ClustersVolumeSnapshotCOMMITEssentiellement :
pg_wal/ : journaux de transactions
archive_status00000002 00000142 000000FFpg_xact/ : état des transactionsChoisir celle qui convient à votre besoin.
pg_dumppg_dumpallLa cohérence est garantie grâce aux WAL
Backup et
ScheduledBackupspec.backup d’un objet
ClusterObjectStore
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: scaleway-store
spec:
configuration:
destinationPath: "s3://<bucket>/<folder>/"
endpointURL: "https://s3.<region>.scw.cloud"
s3Credentials:
accessKeyId:
name: scaleway-api-secret
key: ACCESS_KEY_ID
secretAccessKey:
name: scaleway-api-secret
key: ACCESS_SECRET_KEY
region:
name: scaleway-api-secret
key: ACCESS_REGIONspec.backup.method: volumeSnapshotStorageClassContainer Storage InterfaceCustom Resource DefinitionBackup créée à chaque exécutionarchive_mode à on)archive_command :
/controller/manager wal-archive …isWALArchiver)spec.bootstrap.recovery
barmanObjectStorevolumeSnapshotsN’hésitez pas, c’est le moment !
La version en ligne des solutions de ces TP est disponible sur https://dali.bo/k3_solutions.
But : Mettre en place une sauvegarde PITR sur un stockage S3 (archivage et sauvegarde complète).
Comme vous le savez certainement, il existe le concept de sauvegarde physique PITR comme mécanisme de sauvegarde d’une instance. Pour mettre en place cela, il est d’abord nécessaire de faire une sauvegarde physique de l’arborescence de l’instance. Ceci peut être fait à chaud. Le second élément essentiel est l’archivage des journaux de transactions (WAL) qui seront rejoués après une restauration pour rétablir un état cohérent.
En déployant une instance avec CloudNativePG, la seule solution de
sauvegarde PITR utilisable est Barman Cloud. Très connu
dans l’écosystème PostgreSQL, cet outil nous permet de faire la
sauvegarde physique et l’archivage des WALs. Les commandes passées pour
la mettre en place le seront de manière automatique mais une
configuration doit être rajoutée dans le fichier YAML de définition.
La mise en place d’une solution de sauvegarde nécessite, depuis la version 1.26, l’installation d’un plugin dédié aux sauvegardes. Le projet CloudNativePG met à disposition le plugin Barman Cloud CNPG-I.
Nous allons donc l’installer sur notre cluster Kubernetes. Aussi,
l’outil cert-manager doit être présent dans le cluster
Kubernetes. Il est utilisé pour la génération de certificats pour la
communication entre l’opérateur et le plugin de sauvegarde.
Installer
cert-manageravec la commande suivante.
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.19.2/cert-manager.yaml
Patienter quelques minutes, le temps que
cert-managers’installe, puis installer le plugin avec la commande suivante.
kubectl apply -f https://github.com/cloudnative-pg/plugin-barman-cloud/releases/download/v0.14.0/manifest.yaml
Vérifier que le plugin est bien installé dans le
Namespacecnpg-system.
kubectl get pod -n cnpg-system
NAME READY STATUS RESTARTS AGE
barman-cloud-6858cdc47f-gr2bh 1/1 Running 0 3m32s
cnpg-controller-manager-7b7fcf5cf6-8rmj9 1/1 Running 0 9m18s
Créer le fichier
~/s3-creds.yamlavec le contenu suivant.
Les paramètres ACCESS_* doivent contenir l’information
encodée en BASE64. Si vous utilisez la commande echo,
n’oubliez l’option -n qui empêche la prise en compte du
saut de ligne. Les informations vous seront données par le
formateur.
---
apiVersion: v1
kind: Secret
metadata:
name: s3-creds
type: Opaque
data:
ACCESS_KEY_ID: CHANGEME
ACCESS_REGION: ZnItcGFy
ACCESS_SECRET_KEY: CHANGEMECréer le
Secretdans votre cluster Kubernetes avec la commandekubectl apply -f ~/s3-creds.yaml.
kubectl apply -f s3-creds.yaml
secret/s3-creds created
Ce Secret contient les informations de la clé API qui
permettra de s’authentifier au Bucket S3 et de déposer les
WAL et les sauvegardes.
Pour cette partie du TP, nous allons créer une autre instance PostgreSQL (
postgresql-with-backup-demo), donc un objet de typeClusteret un nouveau nom.
Créer le fichier
~/postgresql-with-backup-demo.yamlavec le contenu suivant.
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: postgresql-with-backup-demo
spec:
imageName: ghcr.io/cloudnative-pg/postgresql:17.5-standard-bookworm
instances: 1
storage:
size: 5Gi
walStorage:
size: 5Gi
postgresql:
parameters:
shared_buffers: '256MB'
max_connections: '10'
work_mem: "8MB"
archive_timeout: "20min"
resources:
requests:
memory: "256Mi"
cpu: "0.5"
limits:
memory: "512Mi"
cpu: "1"
plugins:
- name: barman-cloud.cloudnative-pg.io
isWALArchiver: true
parameters:
barmanObjectName: objectstore-demo La partie backup indique quel plugin de
sauvegarde utilisé, ici Barman Cloud. Il est également
indiqué que c’est ce plugin qui sera en charge de l’archivage
des journaux de transactions grâce au paramètre
isWALArchiver à true.
Créer le fichier
~/objectstore-demo.yamlpour créer l’ObjectStorequi sera utilisé par le nouveauCluster. N’oubliez pas de modifier CHANGEME dans ledestinationPathen gardant bien le dernier/(mettre quelque chose de reconnaissable et unique).
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: objectstore-demo
spec:
configuration:
destinationPath: "s3://demo-cnpg/CHANGEME/"
endpointURL: "https://s3.fr-par.scw.cloud"
s3Credentials:
accessKeyId:
name: s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: s3-creds
key: ACCESS_SECRET_KEY
region:
name: s3-creds
key: ACCESS_REGION
wal:
compression: gzipLa configuration des paramètres endpointURL et
destinationPath devra être adaptée selon votre fournisseur
de stockage S3. Les paramètres ci-dessus fonctionnent bien avec
Scaleway. Faites vraiment attention, vous risquerez de perdre beaucoup
de temps… vraiment :-).
Créer l’
ObjectStoreavec la commande :
kubectl apply -f ~/objectstore-demo.yaml
Créer le nouveau
ClusterPostgreSQL avec la commande :
kubectl apply -f ~/postgresql-with-backup-demo.yaml
Vérifier que l’archivage se passe correctement directement dans la vue
pg_stat_archiver.
kubectl cnpg psql postgresql-with-backup-demo
postgres=# \x
Expanded display is on.
postgres=# SELECT * FROM pg_stat_archiver ;
-[ RECORD 1 ]------+------------------------------
archived_count | 2
last_archived_wal | 000000010000000000000002
last_archived_time | 2025-12-12 10:22:11.071834+00
failed_count | 0
last_failed_wal |
last_failed_time |
stats_reset | 2025-12-12 10:20:09.349145+00
Nous demander de vous montrer, sur l’interface Scaleway, le
Bucketet le dossier que vous avez utilisé.
Pour ce TP, nous sommes passés par la solution
Object Storage de Scaleway compatible S3. Voici un exemple
de ce qu’il sera créé dans le Bucket.
Le dossier pierrick est bien créé dans le
Bucket.
On y retrouve dedans un dossier avec le nom du cluster PostgreSQL…
…qui contient lui-même un dossier wals.
Les journaux (WAL) sont enregistrés dans des dossiers qui reprennent
la timeline de l’instance.
Et enfin, dans ce dernier dossier, se trouvent les journaux de transaction compressés.
C’est un super point de départ. Mais pour le moment, il n’est pas possible de faire quelconque restauration comme il nous manque une sauvegarde complète de l’instance.
Créer le fichier
~/letsbackup.yamlavec le contenu suivant :
apiVersion: postgresql.cnpg.io/v1
kind: Backup
metadata:
name: first-backup
spec:
cluster:
name: postgresql-with-backup-demo
method: plugin
pluginConfiguration:
name: barman-cloud.cloudnative-pg.ioIl faut donner un nom à cet objet Backup et le nom du
cluster PostgreSQL que l’on souhaite sauvegarder ainsi qu’avec quelle
méthode de sauvegarde cela va être fait, ici via le plugin
Barman Cloud.
Créer cette ressource avec avec
kubectl.
kubectl apply -f ~/letsbackup.yaml
backup.postgresql.cnpg.io/first-backup created
Vérifier le statut de l’objet
Backup:
kubectl get backup
NAME AGE CLUSTER METHOD PHASE ERROR
first-backup 14s postgresql-with-backup-demo plugin started
Chercher dans les traces du
Podune preuve que la sauvegarde complète s’est bien déroulée.
kubectl logs postgresql-with-backup-demo-1 | grep completed | jq
{
"level": "info",
"ts": "2025-12-12T10:29:49.602829931Z",
"msg": "Backup completed",
"pluginConfiguration": {
"name": "barman-cloud.cloudnative-pg.io"
},
"backupName": "first-backup",
"backupNamespace": "default",
"logging_pod": "postgresql-with-backup-demo-1"
}Au niveau de l’interface Scaleway, un nouveau dossier
base est apparu à côté de wals.
Il contient toutes les sauvegardes faites jusqu’à présent.
La sauvegarde physique se trouve dans ce dossier et comporte un
fichier d’informations et une archive tar.
Incroyable ! Nous avons une sauvegarde et un archivage des WALs qui semblent se dérouler correctement. Mais, qu’est ce qu’il se cache derrière cela ?
La première chose que nous pouvons chercher à savoir par exemple, est
quel outil est utilisé pour archiver les journaux. Le paramètre
archive_command nous donne un début de réponse.
kubectl exec -it postgresql-with-backup-demo-1 -- psql -c "SHOW archive_command"
archive_command
------------------------------------------------------------------------------------
/controller/manager wal-archive --log-destination /controller/log/postgres.json %p
(1 row)
Un outil appelé manager présent dans le conteneur est
utilisé avec l’option wal-archive suivie de plusieurs
paramètres. %p est un placeholders qui permet
d’indiquer le WAL courant.
Se connecter à l’instance. Créer une table et insérer quelques données.
kubectl exec -it postgresql-with-backup-demo-1 -- psql
ou, via le plugin :
kubectl cnpg psql postgresql-with-backup-demo
Ne pas oublier d’exécuter l’ordre CHECKPOINT qui
permettra de forcer la synchronisation des données sur disque et la
création d’un point de cohérence sans attendre l’expiration de
checkpoint_timeout.
Forcer la création d’un nouveau journal de transactions avec
SELECT pg_switch_wal();.
postgres=# SELECT pg_switch_wal();
pg_switch_wal
---------------
1/FFCFCAA8
(1 row)
Il devrait apparaitre dans votre Bucket S3.
But : Restaurer notre instance depuis la sauvegarde PITR existante.
Les restaurations se font obligatoirement dans une nouvelle instance
PostgreSQL. Le principe de restauration in-place n’est donc pas
possible. Attention donc si vous souhaitez conserver le nom du
Cluster vous devrez détruire le précédent
Cluster qui porterait ce nom.
Maintenant qu’une instance est déployée et qu’une sauvegarde a été faite, attardons-nous sur les manières qui existent pour restaurer une instance.
Aussi, c’est l’occasion de faire un petit rappel ! N’oubliez pas de tester vos procédures de restauration fréquemment !
Simuler un crash. Détruire l’instance
postgresql-with-backup-demo(Nous sommes bien évidemment ici dans un exercice de destruction maîtrisé par des professionnels).
kubectl delete -f ~/postgresql-with-backup-demo.yaml
Créer un nouveau fichier
~/postgresql-restored-demo.yamlavec le contenu suivant. L’idée est de créer une nouvelle instancepostgresql-restored-demoet d’indiquer avec la sectionbootstrapqu’elle doit démarrer à partir d’une sauvegarde.
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: postgresql-restored-demo
spec:
imageName: ghcr.io/cloudnative-pg/postgresql:17.5-standard-bookworm
instances: 1
storage:
size: 5Gi
walStorage:
size: 5Gi
postgresql:
parameters:
shared_buffers: '256MB'
max_connections: '10'
work_mem: '8MB'
archive_timeout: '20min'
resources:
requests:
memory: "256Mi"
cpu: "0.5"
limits:
memory: "512Mi"
cpu: "1"
bootstrap:
recovery:
source: source
externalClusters:
- name: source
plugin:
name: barman-cloud.cloudnative-pg.io
parameters:
barmanObjectName: objectstore-demo
serverName: postgresql-with-backup-demo
plugins:
- name: barman-cloud.cloudnative-pg.io
isWALArchiver: true
parameters:
barmanObjectName: objectstore-demo # réutilisation du bucket S3L’emplacement de la sauvegarde est indiqué dans l’attribut
source de la section bootstrap.recovery. Il
fait référence à un externalClusters qui contient les
informations de l’ObjectStore utilisé et présent dans le
cluster Kuberetes.
Créer votre nouvelle instance avec
kubectl apply -f ~/postgresql-restored-demo.yaml.
kubectl apply -f ~/postgresql-restored-demo.yaml
Lorsque l’instance est prête, s’y connecter et vérifier que les données s’y trouvent bien.
kubectl exec -it postgresql-restored-demo-1 -c postgres -- psql -c "select count(*) from t1;"
count
-------
100
(1 row)
La méthode que nous venons de suivre, suppose que vous ayez accès à
l’objet ObjectStore créé dans le cluster
Kubernetes. Mais qu’en est-il si c’est tout le cluster
Kubernetes qui est en panne et doit être recréé ?
Dans ce cas-là, l’objet ObjectStore n’existe plus. Soit
vous le recréez, soit vous renseignez directement les informations de
connexion au stockage S3.
Du côté du Bucket S3, un nouveau dossier est
automatiquement créé avec le nom du nouvel objet Cluster.
Cela est dû à la partie plugins dans laquelle nous avons
indiqué de réutiliser l’ObjectStore précédent.
Dans cet exemple, la restauration s’est faite sur le même
cluster Kubernetes. Dans le cas où vous devez la faire
ailleurs, n’oubliez pas de recréer le Secret qui contient
les informations de l’API Key nécessaire à l’accès au stockage S3.
Supprimer les instances
postgresql-demoqui ne vont plus nous servir par la suite.
kubectl delete -f postgresql-demo.yaml
Il ne doit rester que le cluster PostgreSQL
postgresql-restored-demo.
kubectl get pod
NAME READY STATUS RESTARTS AGE
postgresql-restored-demo-1 1/1 Running 2 (26m ago) 2d15h
But : Découvrir des fonctionnalités plus complexes.
Il est possible de programmer des sauvegardes régulières avec la
ressource ScheduledBackup.
Voici un exemple de définition qui permet de déclencher une
sauvegarde appelée backup-every-day tous les jours à 16h00
pour le cluster postgresql-restored-demo :
apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
name: backup-every-day
spec:
schedule: "0 42 18 * * *"
backupOwnerReference: self
cluster:
name: postgresql-restored-demo
method: plugin
pluginConfiguration:
name: barman-cloud.cloudnative-pg.ioAttention, l’option schedule prend bien six paramètres
(le premier étant les secondes), contrairement au CronJob
dans Kubernetes ou aux lignes de /etc/crontab qui en prenne
que cinq.
Créer le fichier
~/backup-every-day.yamlavec le contenu ci-dessus en modifiant l’heure d’exécution pour que la sauvegarde s’exécute dans 5 à 10 minutes.
Créer l’objet
ScheduledBackupaveckubectl.
kubectl apply -f ~/backup-every-day.yaml
scheduledbackup.postgresql.cnpg.io/backup-every-day created
Suivez les traces de l’opérateur avec
kubectl logs -n cnpg-system cnpg-controller-manager-6b9f78f594-hd5qq | grep backup | jq. Vous devriez voir le déclenchement de la sauvegarde.
kubectl logs -n cnpg-system cnpg-controller-manager-6b9f78f594-hd5qq | grep backup | jq
{
"level": "info",
"ts": "2025-12-15T18:42:00.095050921Z",
"msg": "Starting backup",
"controller": "backup",
"controllerGroup": "postgresql.cnpg.io",
"controllerKind": "Backup",
"Backup": {
"name": "backup-every-day-20251215184200",
"namespace": "default"
},
"namespace": "default",
"name": "backup-every-day-20251215184200",
"reconcileID": "65490b4b-415b-41d2-be86-b1bab33de9b4",
"cluster": "postgresql-restored-demo",
"pod": "postgresql-restored-demo-1"
}Vous verrez alors la sauvegarde sur votre emplacement de stockage S3.