Workstation Logo
Produits
Labs IAAgents OpenAIAgents ClaudeGrok BotWorkstation CRM (WSL CRM)MarketingTous les Produits
Solutions IA
Stations de Travail IAAI SME PackagesIA PrivéeClusters GPUIA EdgeLaboratoire IA EntrepriseIA par Industrie
Services
Modernisation de plateformeIngénierie numériqueDonnées et activation IAOpérations autonomesConseil IAAutomatisation DevOpsCybersécuritéDéveloppement logicielCréation d'agentsMise en place MLOps
À Propos
PartenairesTémoignages Clients
Articles
Documentation
WSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7
Blog
Nous ContacterLogin
Workstation

Stations de travail IA, logiciels multi-agents IA, infrastructure GPU et solutions d'agents intelligents pour les entreprises modernes.

Nous Contacter

Solutions IA

Stations de Travail IAAI SME PackagesIA PrivéeClusters GPUIA EdgeLaboratoire IA EntrepriseIA par Industrie

Produits

Tous les ProduitsWSL CRM & ERPMarketingAgents OpenAIWSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7

Entreprise

À ProposPourquoi WorkstationPartenairesTémoignages ClientsTarificationContact

Ressources

ArticlesDocumentationBlogRechercherPlan du Site
Bureau Royaume-Uni
77-79 Marlowes, Hemel Hempstead HP1 1LFItinéraire : prenez la sortie 20 de la M25, Outer LondonN° d'entreprise: 11641870Lun - Ven : 9h00 - 18h00 GMT
+44 7515 356 146
Bureau Belgique
Workstation SRL, Rue Vanderkindere 34, 1180 Uccle, BrusselsBE 0751.518.683Lun - Ven : 9h00 - 18h00 CET
+32 492 45 67 46
Bureau Inde
#159 Sector 9, Pocket 1, DDA Flats, 110077 Dwarka, New Delhi
+91 98881 98841

© 2026 Workstation AI. Tous droits réservés.

ConfidentialitéCookiesConditions d'UtilisationPlan du site web

Loading blog...

Home / Blog
DatabaseDevOpsKubernetesBackend

Stratégies de sauvegarde de base de données de production qui fonctionnent réellement : MySQL et PostgreSQL

Stratégies de sauvegarde et de restauration éprouvées pour MySQL et PostgreSQL en production

Balinder Walia12 avril 202634 min read

La perte de données de production est le genre d'incident qui met fin à des carrières, ferme des entreprises et fait la une de Hacker News pour toutes les mauvaises raisons. Pourtant, la plupart des équipes traitent les sauvegardes de bases de données après coup – une tâche cron mise en place il y a deux ans et que personne n’a vérifiée depuis. Cet article présente des stratégies de sauvegarde éprouvées pour MySQL et PostgreSQL qui ont fait leurs preuves dans des environnements de production allant des clusters k3s à nœud unique aux déploiements cloud multirégionaux traitant quotidiennement des millions de transactions.

Nous couvrirons l'ensemble du spectre : méthodes de sauvegarde logiques et physiques, récupération à un moment précis, planification automatisée, cibles de stockage dans le cloud, chiffrement, vérification, approches natives Kubernetes et planification de reprise après sinistre qui relie le tout. Chaque recommandation est accompagnée d'une configuration concrète et d'un code que vous pouvez adapter à votre environnement.

Comprendre les types de sauvegarde

Avant de plonger dans des outils spécifiques, vous avez besoin d'un modèle mental clair des quatre stratégies de sauvegarde fondamentales et de la manière dont elles interagissent avec les objectifs de récupération. Chaque stratégie établit un compromis différent entre la vitesse de sauvegarde, la consommation de stockage et le temps de récupération.

Une sauvegarde complètecapture l'intégralité de la base de données à un moment donné. C’est le plus simple à raisonner et le plus rapide à restaurer, mais aussi le plus coûteux en stockage et le plus lent à créer. Une sauvegarde incrémentiellecapture uniquement les données modifiées depuis la dernière sauvegarde, quel que soit son type. Il est rapide à créer et à compacter le stockage, mais la restauration nécessite de rejouer la chaîne complète : la dernière sauvegarde complète et chaque sauvegarde incrémentielle ultérieure. Une sauvegarde différentiellecapture tout ce qui a changé depuis la dernière sauvegarde complète. Il occupe un juste milieu – plus grand qu’un incrémentiel mais plus simple à restaurer car vous n’avez besoin que du dernier complet plus le dernier différentiel. Enfin, l'archivage continu(archivage WAL dans PostgreSQL, streaming de journaux binaires dans MySQL) capture chaque transaction individuelle au fur et à mesure qu'elle se produit, permettant une récupération à tout moment entre les sauvegardes.

Présentation de la stratégie de sauvegarde du: complète, incrémentielle, différentielle ou continueJour 0Jour 1Jour 2Jour 3Jour 4Jour 5completAugmenter.Diff.WAL/BinlogCOMPLET (100%)COMPLET (100%)+5%+3%+4%+2%+5%+8%+12%+14%WAL continu/flux de journaux binaires (chaque transaction)Cible de récupérationSauvegarde complèteIncrémentalDifférentielFlux WAL/BinlogPoint de récupération

La stratégie optimale pour la plupart des systèmes de production est une combinaison : sauvegardes complètes hebdomadaires, incrémentielles ou différentielles quotidiennes et archivage continu des WAL/binlog. Cela vous offre à la fois une récupération rapide à partir de sauvegardes complètes récentes et la possibilité de restaurer à tout moment lorsque vous en avez besoin.

MySQL Méthodes de sauvegarde

MySQL propose plusieurs outils de sauvegarde, chacun adapté à différentes tailles de bases de données et exigences de récupération. Le bon choix dépend de votre volume de données, de la fenêtre de sauvegarde acceptable et des objectifs RTO/RPO.

mysqldump — La sauvegarde logique universelle

mysqldumpproduit des instructions SQL qui recréent le schéma et les données. Il fonctionne sur toutes les versions et moteurs de stockage de MySQL, ce qui en fait la solution de repli universelle. Cependant, il verrouille les tables pendant le vidage (sauf si vous utilisez--single-transactionavec InnoDB) et la vitesse de restauration se dégrade considérablement pour les bases de données au-delà de 50 à 100 Go, car il relit les instructions INSERT individuelles.

# Full logical backup with consistent snapshot for InnoDB
mysqldump --single-transaction --routines --triggers --events \
  --set-gtid-purged=ON --all-databases \
  | gzip > /backups/mysql-full-$(date +%Y%m%d-%H%M%S).sql.gz

# Single database backup with compression
mysqldump --single-transaction --routines --triggers \
  --databases production_db \
  | pigz -p4 > /backups/production_db-$(date +%Y%m%d).sql.gz

# Schema-only backup for migration planning
mysqldump --no-data --routines --triggers --events \
  --all-databases > /backups/schema-only-$(date +%Y%m%d).sql

mysqlpump — Sauvegarde logique parallèle

mysqlpumpaméliore lemysqldumpavec le dumping de table parallèle et la compression intégrée. Cela peut réduire considérablement le temps de sauvegarde des bases de données comportant de nombreuses tables indépendantes.

# Parallel logical backup with 4 threads and zstd compression
mysqlpump --default-parallelism=4 --compress-output=ZSTD \
  --include-databases=production_db,analytics_db \
  --set-gtid-purged=ON \
  > /backups/mysql-pump-$(date +%Y%m%d).sql.zst

Percona XtraBackup — Sauvegardes physiques pour InnoDB

Pour les bases de données de plus de 50 Go, les sauvegardes logiques deviennent peu pratiques : la fenêtre de sauvegarde et le temps de restauration augmentent de manière linéaire avec la taille des données. Percona XtraBackup effectue des copies au niveau physique des fichiers de données InnoDB sans verrouiller la base de données, ce qui le rend adapté aux déploiements de plusieurs téraoctets.

# Full physical backup with streaming to compressed archive
xtrabackup --backup --target-dir=/backups/full-$(date +%Y%m%d) \
  --user=backup_user --password=secure_pass \
  --parallel=4 --compress --compress-threads=4

# Incremental backup based on last full
xtrabackup --backup --target-dir=/backups/incr-$(date +%Y%m%d) \
  --incremental-basedir=/backups/full-20260412 \
  --user=backup_user --password=secure_pass \
  --parallel=4

# Stream full backup directly to S3 via xbstream
xtrabackup --backup --stream=xbstream --compress \
  --user=backup_user --password=secure_pass | \
  aws s3 cp - s3://db-backups/mysql/full-$(date +%Y%m%d).xbstream

# Prepare for restore (apply redo log)
xtrabackup --prepare --target-dir=/backups/full-20260412

# Prepare incremental on top of full
xtrabackup --prepare --apply-log-only --target-dir=/backups/full-20260412
xtrabackup --prepare --target-dir=/backups/full-20260412 \
  --incremental-dir=/backups/incr-20260412

# Restore
systemctl stop mysqld
xtrabackup --copy-back --target-dir=/backups/full-20260412
chown -R mysql:mysql /var/lib/mysql
systemctl start mysqld

Journal binaire MySQL — Récupération ponctuelle

Les journaux binaires

MySQL enregistrent chaque instruction de modification de données ou changement de ligne. Lorsqu'ils sont combinés à une sauvegarde complète ou physique, ils permettent une récupération à tout moment après la sauvegarde.

# Enable binary logging in my.cnf
[mysqld]
server-id = 1
log-bin = /var/log/mysql/mysql-bin
binlog_format = ROW
binlog_expire_logs_seconds = 604800   # 7 days
sync_binlog = 1
gtid_mode = ON
enforce_gtid_consistency = ON

# Flush and archive binary logs
mysqladmin flush-logs
mysqlbinlog --read-from-remote-server --host=db-primary \
  --raw --stop-never --result-file=/backup/binlogs/ \
  mysql-bin.000042

# Point-in-time recovery: replay binlog up to specific timestamp
mysqlbinlog --stop-datetime="2026-04-12 14:30:00" \
  /backup/binlogs/mysql-bin.000042 \
  /backup/binlogs/mysql-bin.000043 | mysql -u root

PostgreSQL Méthodes de sauvegarde

L'écosystème de sauvegarde du PostgreSQL est sans doute plus riche que celui du MySQL, avec des outils propriétaires et un ensemble mature de solutions communautaires spécialement conçues pour les environnements de production à grande échelle.

pg_dump et pg_dumpall — Sauvegardes logiques

Commemysqldump,pg_dumpproduit des sauvegardes logiques. Le format personnalisé (-Fc) est le format par défaut recommandé car il prend en charge la restauration parallèle, la restauration sélective de tables et la compression intégrée.

# Custom format with parallel dump (4 worker jobs)
pg_dump -Fc -j4 -f /backups/production-$(date +%Y%m%d).dump production_db

# Directory format for maximum parallelism on large databases
pg_dump -Fd -j8 -f /backups/production-$(date +%Y%m%d)/ production_db

# All databases including globals (roles, tablespaces)
pg_dumpall > /backups/pg-all-$(date +%Y%m%d).sql

# Parallel restore from custom format
pg_restore -j4 -d production_db_restored /backups/production-20260412.dump

# Selective restore: single table
pg_restore -j4 -d production_db -t orders /backups/production-20260412.dump

pg_basebackup — Fondation de sauvegarde physique

pg_basebackupprend une copie physique de l'intégralité du répertoire de données PostgreSQL. Il constitue la base de la configuration de la récupération autonome et de la réplication en streaming. Combiné à l'archivage WAL, il permet une récupération à un moment précis.

# Physical backup with WAL files included
pg_basebackup -D /backups/base-$(date +%Y%m%d) \
  -Ft -z -Xs -P -c fast \
  -U replication_user -h db-primary

# Stream backup directly to a tar archive with checksums
pg_basebackup -D - -Ft -Xs -c fast \
  -U replication_user -h db-primary | \
  gzip > /backups/pg-base-$(date +%Y%m%d).tar.gz

pgBackRest — Gestion des sauvegardes de niveau entreprise

pgBackRest est la référence en matière de gestion des sauvegardes PostgreSQL. Il prend en charge les sauvegardes complètes, incrémentielles et différentielles, la sauvegarde et la restauration parallèles, le chiffrement, les cibles multi-dépôts (disque local, S3, GCS, Azure Blob) et l'archivage WAL automatisé, le tout via une configuration unique et cohérente.

# /etc/pgbackrest/pgbackrest.conf
[global]
repo1-type=s3
repo1-s3-bucket=pg-backups-production
repo1-s3-endpoint=s3.eu-west-1.amazonaws.com
repo1-s3-region=eu-west-1
repo1-s3-key=AKIAIOSFODNN7EXAMPLE
repo1-s3-key-secret=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
repo1-path=/pgbackrest
repo1-retention-full=4
repo1-retention-diff=14
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=a_very_secure_encryption_passphrase

# Second repository for geographic redundancy
repo2-type=azure
repo2-azure-container=pg-backups-dr
repo2-azure-account=prodbackupstorage
repo2-azure-key=base64encodedkeyhere
repo2-path=/pgbackrest
repo2-retention-full=2

process-max=4
compress-type=zst
compress-level=6
log-level-console=info
log-level-file=detail
start-fast=y

[production]
pg1-path=/var/lib/postgresql/16/main
pg1-port=5432

# PostgreSQL WAL archive configuration (postgresql.conf)
# archive_mode = on
# archive_command = 'pgbackrest --stanza=production archive-push %p'

# Create the stanza
pgbackrest --stanza=production stanza-create

# Verify the stanza configuration
pgbackrest --stanza=production check

# Full backup
pgbackrest --stanza=production --type=full backup

# Differential backup
pgbackrest --stanza=production --type=diff backup

# Incremental backup
pgbackrest --stanza=production --type=incr backup

# List backups
pgbackrest --stanza=production info

WAL-G — Archivage WAL léger vers le stockage cloud

WAL-G est une alternative plus simple à pgBackRest qui se concentre sur le streaming de segments WAL et les sauvegardes de base vers le stockage d'objets cloud. Il est populaire dans les environnements conteneurisés où vous souhaitez un seul binaire avec une configuration minimale.

# Environment variables for WAL-G with S3
export WALG_S3_PREFIX=s3://pg-wal-archive/production
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
export AWS_REGION=eu-west-1
export WALG_COMPRESSION_METHOD=lz4
export PGHOST=/var/run/postgresql

# Configure WAL archiving in postgresql.conf
# archive_mode = on
# archive_command = 'wal-g wal-push %p'
# restore_command = 'wal-g wal-fetch %f %p'

# Take a base backup
wal-g backup-push /var/lib/postgresql/16/main

# List backups
wal-g backup-list

# Restore from latest backup
wal-g backup-fetch /var/lib/postgresql/16/main LATEST

# Delete old backups (retain last 4)
wal-g delete retain FULL 4 --confirm

Barman — Serveur de sauvegarde centralisé

Barman (Backup and Recovery Manager) est conçu pour les environnements dans lesquels un serveur de sauvegarde dédié gère les sauvegardes de plusieurs instances PostgreSQL. Il prend en charge les protocoles de réplication rsync/SSH et streaming pour le transport de sauvegarde.

# /etc/barman.d/production.conf
[production]
description = "Production PostgreSQL 16"
ssh_command = ssh postgres@db-primary
conninfo = host=db-primary user=barman dbname=postgres
streaming_conninfo = host=db-primary user=streaming_barman
backup_method = postgres
streaming_archiver = on
slot_name = barman
retention_policy = RECOVERY WINDOW OF 14 DAYS

# Create replication slot and start streaming
barman receive-wal --create-slot production
barman switch-wal --force --archive production

# Take a backup
barman backup production

# List backups
barman list-backup production

# Restore to point in time
barman recover --target-time "2026-04-12 14:30:00" \
  production 20260412T120000 /var/lib/postgresql/16/main

Récupération ponctuelle (PITR)

La récupération ponctuelle est la fonctionnalité la plus importante de votre boîte à outils de sauvegarde. Il vous permet de restaurer une base de données dans l'état exact dans lequel elle se trouvait à un moment donné, pas seulement au moment où les sauvegardes ont été effectuées, mais à chaque seconde entre les sauvegardes. Ceci est essentiel pour récupérer après une suppression accidentelle de données, des bogues d’application qui corrompent les données et des incidents de sécurité pour lesquels vous devez identifier le moment exact de la compromission.

Chronologie de la récupération ponctuelle (PITR)00:00Soleil06:0012:0018:0000:00LunSauvegarde complètepg_basebackupà 00h00WAL/Segments de journaux binaires (continu)✖TABLE DE DÉPÔTà 16:42:31Cible de récupérationà 16:42:301. Restaurer lecomplet2. Rejouer WAL pour cibler3. Base de données récupérée !PITR = Restaurer la dernière sauvegarde complète + Relire les segments WAL/binlog jusqu'à 1 seconde avant le sinistreGranularité de récupération: par transaction (PostgreSQL WAL) ou par seconde (binlog MySQL)

PITR pour PostgreSQL

PostgreSQL PITR fonctionne en restaurant une sauvegarde de base et en rejouant les segments WAL jusqu'à l'horodatage cible. Avec pgBackRest, l'ensemble du processus est une seule commande.

# Restore to specific point in time with pgBackRest
pgbackrest --stanza=production \
  --type=time --target="2026-04-12 16:42:30" \
  --target-action=promote \
  restore

# Manual PITR using pg_basebackup + WAL archive
# 1. Stop PostgreSQL
systemctl stop postgresql

# 2. Clear the data directory and restore base backup
rm -rf /var/lib/postgresql/16/main/*
tar xzf /backups/pg-base-20260412.tar.gz -C /var/lib/postgresql/16/main/

# 3. Create recovery signal and configure restore
cat > /var/lib/postgresql/16/main/postgresql.auto.conf << 'CONF'
restore_command = 'cp /backup/wal_archive/%f %p'
recovery_target_time = '2026-04-12 16:42:30'
recovery_target_action = 'promote'
CONF
touch /var/lib/postgresql/16/main/recovery.signal

# 4. Start PostgreSQL — it will replay WAL and stop at target
systemctl start postgresql

PITR pour MySQL

MySQL PITR combine une restauration physique XtraBackup avec une relecture des journaux binaires.

# 1. Restore the XtraBackup
systemctl stop mysqld
rm -rf /var/lib/mysql/*
xtrabackup --prepare --target-dir=/backups/full-20260412
xtrabackup --copy-back --target-dir=/backups/full-20260412
chown -R mysql:mysql /var/lib/mysql
systemctl start mysqld

# 2. Identify the binlog position from XtraBackup metadata
cat /backups/full-20260412/xtrabackup_binlog_info
# Output: mysql-bin.000042  154  3E11FA47-1111-1111-1111-AAAAAAAAAAAA:1-1234

# 3. Replay binlogs up to target time
mysqlbinlog --start-position=154 \
  --stop-datetime="2026-04-12 16:42:30" \
  /backup/binlogs/mysql-bin.000042 \
  /backup/binlogs/mysql-bin.000043 | mysql -u root
Architecture de sauvegarde multi-cloud

Les stratégies de sauvegarde de production

doivent tenir compte de la défaillance d’un seul fournisseur de cloud ou d’une seule région. Le stockage des sauvegardes exclusivement dans le même compte cloud et la même région que votre base de données de production signifie qu'une seule compromission de compte, un problème de facturation ou une panne régionale peut supprimer simultanément vos données et vos sauvegardes. Une architecture robuste envoie des sauvegardes à au moins deux cibles de stockage indépendantes avec réplication entre régions.

Architecture de sauvegarde multi-cloudPostgreSQLprimaire + répliquesMySQLPrimaire + RépliquesCouche de chiffrementAES-256-CBCTLS en transitSSE-S3 / SSE-KMSau reposChiffrement côté clientvia pgBackRest/ WAL-GAWS S3eu-west-1 (primaire)Cycle de vie du: IA → GlacierAzure BlobEurope de l'Ouest (primaire)Politiques d'immuabilitéStockage Google Cloudeurope-west1 (primaire)Nearline → Ligne froideS3 inter-régionsus-east-1 (DR)Azure GRSEurope du Nord (DR)GCS multirégionMultirégion UE (DR)Surveillance et surveillance des sauvegardesAlerteMétriques Prometheus • Tableaux de bord Grafana • Alertes PagerDuty/Slack en cas d'échec de sauvegarde ou de seuil d'âgeFlèches pleines = flux de secoursFlèches pointillées = réplication inter-régionsZone pointillée = limite de chiffrementConfiguration du stockage cloud

avec politiques de cycle de vie

# AWS S3 lifecycle policy (Terraform)
resource "aws_s3_bucket_lifecycle_configuration" "backup_lifecycle" {
  bucket = aws_s3_bucket.db_backups.id

  rule {
    id     = "backup-tiering"
    status = "Enabled"

    transition {
      days          = 30
      storage_class = "STANDARD_IA"
    }
    transition {
      days          = 90
      storage_class = "GLACIER"
    }
    transition {
      days          = 365
      storage_class = "DEEP_ARCHIVE"
    }
    expiration {
      days = 2555  # 7 years for compliance
    }
  }

  rule {
    id     = "wal-segments"
    status = "Enabled"
    filter {
      prefix = "wal-archive/"
    }
    expiration {
      days = 30
    }
  }
}

# Enable cross-region replication
resource "aws_s3_bucket_replication_configuration" "backup_replication" {
  bucket = aws_s3_bucket.db_backups.id
  role   = aws_iam_role.replication.arn

  rule {
    id     = "cross-region-dr"
    status = "Enabled"
    destination {
      bucket        = aws_s3_bucket.db_backups_dr.arn
      storage_class = "STANDARD_IA"
      encryption_configuration {
        replica_kms_key_id = aws_kms_key.dr_key.arn
      }
    }
    source_selection_criteria {
      sse_kms_encrypted_objects {
        status = "Enabled"
      }
    }
  }
}
# Azure Blob immutability policy (Azure CLI)
az storage container immutability-policy create \
  --account-name prodbackupstorage \
  --container-name pg-backups \
  --period 365 \
  --allow-protected-append-writes true

# GCS lifecycle with nearline transition
gsutil lifecycle set /dev/stdin gs://pg-backups-production << 'JSON'
{
  "rule": [
    {"action": {"type": "SetStorageClass", "storageClass": "NEARLINE"}, "condition": {"age": 30}},
    {"action": {"type": "SetStorageClass", "storageClass": "COLDLINE"}, "condition": {"age": 90}},
    {"action": {"type": "Delete"}, "condition": {"age": 2555}}
  ]
}
JSON

Cryptage et sécurité des sauvegardes

Les sauvegardes

constituent une cible de grande valeur pour les attaquants. Une sauvegarde non cryptée volée donne à un attaquant une copie complète de vos données de production sans avoir besoin de violer vos systèmes en cours d'exécution. Chaque sauvegarde, en transit et au repos, doit être chiffrée.

Chiffrement en transitsignifie utiliser TLS pour toutes les connexions entre le serveur de base de données et la destination de sauvegarde. PgBackRest et XtraBackup diffusent tous deux sur des canaux cryptés lorsqu'ils sont configurés avec TLS. Lors de l'expédition vers S3, Azure Blob ou GCS, les SDK clients utilisent HTTPS par défaut.

Chiffrement au reposcomporte deux couches. Le chiffrement côté serveur (SSE) chiffre les données une fois qu'elles arrivent à la cible de stockage : S3 SSE-KMS, Azure Storage Service Encryption ou chiffrement par défaut GCS. Le chiffrement côté client chiffre les données avant qu'elles ne quittent le serveur de base de données, garantissant ainsi que le fournisseur de cloud ne voit jamais les données en texte brut. pgBackRest et WAL-G prennent tous deux en charge le chiffrement côté client de manière native.

# pgBackRest client-side encryption config
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=long_random_passphrase_stored_in_vault

# WAL-G client-side encryption
export WALG_LIBSODIUM_KEY=$(cat /etc/wal-g/encryption.key)
# Or GPG-based
export WALG_GPG_KEY_ID=backup@example.com

# MySQL XtraBackup with encryption
xtrabackup --backup --encrypt=AES256 \
  --encrypt-key-file=/etc/mysql/backup-encryption.key \
  --target-dir=/backups/full-encrypted-$(date +%Y%m%d)

Stockez les clés de chiffrement séparément des sauvegardes elles-mêmes. Un gestionnaire de secrets comme HashiCorp Vault, AWS Secrets Manager ou Azure Key Vault est l'approche recommandée. Si vous stockez la clé avec la sauvegarde, un attaquant qui accède à votre stockage de sauvegarde dispose de tout ce dont il a besoin.

Planification automatisée des sauvegardes

Les sauvegardes manuelles

ne sont pas des sauvegardes, ce sont des aspirations. Les planifications de sauvegarde doivent être automatisées, surveillées et alerter en cas d'échec.

Système Cron pour Bare Metal et VM

# /etc/cron.d/database-backups

# PostgreSQL — pgBackRest
# Full backup every Sunday at 01:00
0 1 * * 0 postgres pgbackrest --stanza=production --type=full backup 2>&1 | logger -t pgbackrest-full

# Differential backup every day at 01:00 (except Sunday)
0 1 * * 1-6 postgres pgbackrest --stanza=production --type=diff backup 2>&1 | logger -t pgbackrest-diff

# MySQL — XtraBackup
# Full backup every Sunday at 02:00
0 2 * * 0 root /usr/local/bin/mysql-backup.sh full 2>&1 | logger -t xtrabackup-full

# Incremental backup every day at 02:00 (except Sunday)
0 2 * * 1-6 root /usr/local/bin/mysql-backup.sh incremental 2>&1 | logger -t xtrabackup-incr

# Backup verification — restore test every Wednesday at 04:00
0 4 * * 3 root /usr/local/bin/verify-backup.sh 2>&1 | logger -t backup-verify

Kubernetes Travaux Cron

Dans les environnements Kubernetes, les CronJobs remplacent le cron du système. Ils offrent une logique de nouvelle tentative intégrée, un contrôle de concurrence et une intégration avec RBAC et la gestion des secrets du cluster.

apiVersion: batch/v1
kind: CronJob
metadata:
  name: pg-backup-full
  namespace: database
spec:
  schedule: "0 1 * * 0"  # Sunday 01:00 UTC
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 4
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      backoffLimit: 2
      activeDeadlineSeconds: 7200  # 2 hour timeout
      template:
        spec:
          serviceAccountName: db-backup
          restartPolicy: OnFailure
          containers:
            - name: pgbackrest
              image: pgbackrest/pgbackrest:2.50
              command:
                - /bin/bash
                - -c
                - |
                  pgbackrest --stanza=production --type=full backup
                  RESULT=$?
                  if [ $RESULT -eq 0 ]; then
                    curl -s -X POST "$SLACK_WEBHOOK" \
                      -d '{"text":"PostgreSQL full backup completed successfully"}'
                  else
                    curl -s -X POST "$SLACK_WEBHOOK" \
                      -d '{"text":"ALERT: PostgreSQL full backup FAILED"}'
                  fi
                  exit $RESULT
              envFrom:
                - secretRef:
                    name: pgbackrest-credentials
                - secretRef:
                    name: slack-webhook
              resources:
                requests:
                  memory: 512Mi
                  cpu: 500m
                limits:
                  memory: 2Gi
                  cpu: "2"
              volumeMounts:
                - name: pgbackrest-config
                  mountPath: /etc/pgbackrest
          volumes:
            - name: pgbackrest-config
              configMap:
                name: pgbackrest-conf
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: pg-backup-diff
  namespace: database
spec:
  schedule: "0 1 * * 1-6"  # Mon-Sat 01:00 UTC
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 7
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      backoffLimit: 2
      activeDeadlineSeconds: 3600
      template:
        spec:
          serviceAccountName: db-backup
          restartPolicy: OnFailure
          containers:
            - name: pgbackrest
              image: pgbackrest/pgbackrest:2.50
              command:
                - /bin/bash
                - -c
                - |
                  pgbackrest --stanza=production --type=diff backup
              envFrom:
                - secretRef:
                    name: pgbackrest-credentials
              resources:
                requests:
                  memory: 256Mi
                  cpu: 250m
                limits:
                  memory: 1Gi
                  cpu: "1"
              volumeMounts:
                - name: pgbackrest-config
                  mountPath: /etc/pgbackrest
          volumes:
            - name: pgbackrest-config
              configMap:
                name: pgbackrest-conf
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: mysql-backup-full
  namespace: database
spec:
  schedule: "0 2 * * 0"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      backoffLimit: 2
      activeDeadlineSeconds: 7200
      template:
        spec:
          serviceAccountName: db-backup
          restartPolicy: OnFailure
          containers:
            - name: xtrabackup
              image: percona/percona-xtrabackup:8.0
              command:
                - /bin/bash
                - -c
                - |
                  xtrabackup --backup --stream=xbstream --compress \
                    --user=$MYSQL_BACKUP_USER \
                    --password=$MYSQL_BACKUP_PASS \
                    --host=mysql-primary.database.svc | \
                    aws s3 cp - s3://$S3_BUCKET/mysql/full-$(date +%Y%m%d).xbstream
              envFrom:
                - secretRef:
                    name: mysql-backup-credentials
                - secretRef:
                    name: aws-credentials
              resources:
                requests:
                  memory: 512Mi
                  cpu: 500m
                limits:
                  memory: 2Gi
                  cpu: "2"

Kubernetes-La sauvegarde native s'approche du

L'exécution de bases de données dans Kubernetes introduit une nouvelle dimension dans la stratégie de sauvegarde. Outre les sauvegardes de base de données au niveau de l'application, vous devez envisager la sauvegarde au niveau du cluster (etcd), les instantanés de volumes persistants et les sauvegardes gérées par l'opérateur.

Pipeline de sauvegarde KubernetesGroupe Kubernetes (k3s / RKE2)Tâche CronCalendrier: 0 1 * * *Module de sauvegardepgDossier /Conteneur XtraBackupPod PostgreSQLRéplique StatefulSet 0PVC : données pgMySQL PodRéplique StatefulSet0PVC : données MySQLLonghorn CSIInstantanés PV + RépliquesVolumeSnapshot CRDVeleroSauvegarde au niveau du clusteretcd + espaces de noms + PVStockage d'objetsS3/GCS/Azure Blob/MinIOChiffré et amp;versionnéHiérarchisation du cycle de vie activéeSauvegardes de base de données+ WALVeleroCible Longhorn S3Prometheus + GrafanaMétriques des tâches de sauvegarde + alertesTaux de réussite/échec des tâches CronChemin de restauration1. Restauration Velero (cluster)2. pgBackRest/XtraBackup (données)3. Restauration de l'instantané LonghornPlanificateurAgent de sauvegardePostgreSQLMySQLVeleroLongue corneStockage d'objets

Velero pour la sauvegarde au niveau du cluster

Velero sauvegarde les ressources Kubernetes (déploiements, services, cartes de configuration, secrets) et les volumes persistants. Il ne remplace pas les sauvegardes de bases de données au niveau des applications : il capture un instantané des PV cohérent en cas de panne, qui peut ne pas être cohérent sur le plan transactionnel pour les bases de données. Utilisez Velero pour la récupération de cluster et les outils au niveau de l'application (pgBackRest, XtraBackup) pour la récupération de base de données.

# Install Velero with S3 backend
velero install \
  --provider aws \
  --bucket velero-backups \
  --secret-file ./credentials-velero \
  --backup-location-config region=eu-west-1 \
  --snapshot-location-config region=eu-west-1 \
  --use-volume-snapshots=true \
  --plugins velero/velero-plugin-for-aws:v1.9.0

# Create a scheduled backup of the database namespace
velero schedule create db-namespace-backup \
  --schedule="0 3 * * *" \
  --include-namespaces database \
  --ttl 720h \
  --storage-location default \
  --volume-snapshot-locations default

# On-demand backup before maintenance
velero backup create pre-maintenance-$(date +%Y%m%d) \
  --include-namespaces database,monitoring \
  --wait

# Restore a namespace from backup
velero restore create --from-backup pre-maintenance-20260412 \
  --include-namespaces database

Longhorn Instantanés sur k3s

Les déploiements

k3s utilisent généralement Longhorn comme fournisseur de stockage CSI. Longhorn fournit des instantanés au niveau du volume et la possibilité de répliquer des instantanés vers un stockage d'objets compatible S3. Pour les bases de données, combinez des instantanés Longhorn avec des sauvegardes au niveau des applications pour une défense en profondeur.

# Longhorn recurring snapshot job via CRD
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
  name: pg-data-snapshot
  namespace: longhorn-system
spec:
  cron: "0 */4 * * *"  # every 4 hours
  task: snapshot
  retain: 6
  concurrency: 1
  groups:
    - pg-data
  labels:
    app: postgresql
---
# Longhorn recurring backup to S3
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
  name: pg-data-s3-backup
  namespace: longhorn-system
spec:
  cron: "0 2 * * *"  # daily at 02:00
  task: backup
  retain: 14
  concurrency: 1
  groups:
    - pg-data
  labels:
    app: postgresql
---
# VolumeSnapshot using Longhorn CSI
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: pg-data-snap-$(date +%Y%m%d)
  namespace: database
spec:
  volumeSnapshotClassName: longhorn-snapshot-vsc
  source:
    persistentVolumeClaimName: pg-data-postgresql-0

Sauvegardes gérées par l'opérateur

Les opérateurs de bases de données

comme CloudNativePG (pour PostgreSQL) et Percona Operator (pour MySQL) intègrent la gestion des sauvegardes directement dans le cycle de vie de la base de données. L'opérateur gère automatiquement la planification, l'archivage des WAL et la conservation via des ressources personnalisées.

# CloudNativePG cluster with integrated backup
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: production-pg
  namespace: database
spec:
  instances: 3
  storage:
    size: 100Gi
    storageClass: longhorn
  backup:
    barmanObjectStore:
      destinationPath: s3://pg-backups/cnpg/
      endpointURL: https://s3.eu-west-1.amazonaws.com
      s3Credentials:
        accessKeyId:
          name: aws-creds
          key: ACCESS_KEY_ID
        secretAccessKey:
          name: aws-creds
          key: SECRET_ACCESS_KEY
      wal:
        compression: gzip
        maxParallel: 4
      data:
        compression: gzip
    retentionPolicy: "30d"
---
apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
  name: production-pg-weekly
  namespace: database
spec:
  schedule: "0 1 * * 0"
  backupOwnerReference: self
  cluster:
    name: production-pg

Stratégies spécifiques au fournisseur de cloud

AWS — RDS et Aurora

AWS RDS fournit des instantanés quotidiens automatisés avec une conservation configurable (jusqu'à 35 jours) et une sauvegarde continue via l'archivage du journal des transactions pour une récupération à un moment précis. Aurora ajoute Backtrack, qui peut rembobiner le cluster à n'importe quel point de la fenêtre de retour en arrière sans nécessiter de restauration : il inverse simplement l'état interne de la base de données.

# Enable automated backups with maximum retention (Terraform)
resource "aws_db_instance" "production" {
  identifier             = "production-pg"
  engine                 = "postgres"
  engine_version         = "16.2"
  instance_class         = "db.r6g.xlarge"
  allocated_storage      = 500
  backup_retention_period = 35  # maximum
  backup_window          = "03:00-04:00"
  copy_tags_to_snapshot  = true
  deletion_protection    = true
  storage_encrypted      = true
  kms_key_id             = aws_kms_key.rds.arn

  # Enable PITR
  enabled_cloudwatch_logs_exports = ["postgresql", "upgrade"]
}

# Cross-region automated backup replication
resource "aws_db_instance_automated_backups_replication" "dr" {
  source_db_instance_arn = aws_db_instance.production.arn
  kms_key_id             = aws_kms_key.dr_rds.arn
  retention_period       = 14
}

# Aurora Backtrack (MySQL-compatible Aurora only)
resource "aws_rds_cluster" "aurora_production" {
  cluster_identifier      = "aurora-production"
  engine                  = "aurora-mysql"
  engine_version          = "8.0.mysql_aurora.3.05.2"
  backtrack_window        = 86400  # 24 hours of backtrack
  backup_retention_period = 35
  preferred_backup_window = "03:00-04:00"
  storage_encrypted       = true
}

# Manual snapshot with cross-region copy
aws rds create-db-snapshot \
  --db-instance-identifier production-pg \
  --db-snapshot-identifier pre-migration-$(date +%Y%m%d)

aws rds copy-db-snapshot \
  --source-db-snapshot-identifier arn:aws:rds:eu-west-1:123456789:snapshot:pre-migration-20260412 \
  --target-db-snapshot-identifier pre-migration-20260412-dr \
  --source-region eu-west-1 \
  --region us-east-1 \
  --kms-key-id arn:aws:kms:us-east-1:123456789:key/dr-key-id

Azure — Serveur flexible

La base de données

Azure pour serveur flexible PostgreSQL et MySQL comprend des sauvegardes automatiques avec un stockage localement redondant ou géoredondant. La sauvegarde géoredondante permet une restauration inter-régions pour la reprise après sinistre.

# Azure Flexible Server with geo-redundant backup (Terraform)
resource "azurerm_postgresql_flexible_server" "production" {
  name                = "production-pg"
  location            = "westeurope"
  resource_group_name = azurerm_resource_group.db.name
  sku_name            = "GP_Standard_D4s_v3"
  version             = "16"
  storage_mb          = 524288  # 512 GB

  backup_retention_days        = 35
  geo_redundant_backup_enabled = true

  authentication {
    active_directory_auth_enabled = true
    password_auth_enabled         = false
  }
}

# Azure Blob immutability for self-managed backups
resource "azurerm_storage_management_policy" "backup_lifecycle" {
  storage_account_id = azurerm_storage_account.backups.id

  rule {
    name    = "backup-tiering"
    enabled = true
    filters {
      blob_types   = ["blockBlob"]
      prefix_match = ["pg-backups/"]
    }
    actions {
      base_blob {
        tier_to_cool_after_days_since_modification_greater_than    = 30
        tier_to_archive_after_days_since_modification_greater_than = 90
        delete_after_days_since_modification_greater_than          = 2555
      }
    }
  }
}

GCP — Cloud SQL

Cloud SQL fournit des sauvegardes automatisées et une récupération ponctuelle prêtes à l'emploi. Pour les bases de données autogérées sur GCE ou GKE, GCS avec classes de stockage Nearline et Coldline fournit un stockage de sauvegarde à long terme rentable.

# Cloud SQL with automated backups and PITR (Terraform)
resource "google_sql_database_instance" "production" {
  name             = "production-pg"
  database_version = "POSTGRES_16"
  region           = "europe-west1"

  settings {
    tier = "db-custom-4-16384"

    backup_configuration {
      enabled                        = true
      start_time                     = "03:00"
      point_in_time_recovery_enabled = true
      transaction_log_retention_days = 7
      backup_retention_settings {
        retained_backups = 30
        retention_unit   = "COUNT"
      }
    }

    ip_configuration {
      ssl_mode = "ENCRYPTED_ONLY"
    }
  }
}

# Export to GCS for long-term retention
gcloud sql export sql production-pg \
  gs://pg-backups-longterm/export-$(date +%Y%m%d).sql.gz \
  --database=production_db \
  --offload

Vérification des sauvegardes et tests de restauration

Une sauvegarde qui n'a jamais été testée n'est pas une sauvegarde, c'est un espoir. Les tests de restauration automatisés doivent être exécutés selon un calendrier régulier, idéalement une fois par semaine, dans un environnement isolé. Le test doit valider non seulement que la restauration s'effectue sans erreur, mais aussi que les données restaurées sont cohérentes et que l'application peut se connecter et les interroger.

#!/bin/bash
# verify-backup.sh — Automated backup verification script
set -euo pipefail

RESTORE_DIR="/tmp/backup-verify-$(date +%Y%m%d-%H%M%S)"
LOG_FILE="/var/log/backup-verify.log"
SLACK_WEBHOOK="${SLACK_WEBHOOK_URL}"
DB_TYPE="${1:-postgresql}"  # postgresql or mysql

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }
alert() {
  log "ALERT: $*"
  curl -s -X POST "$SLACK_WEBHOOK" \
    -H 'Content-Type: application/json' \
    -d "{\"text\":\"BACKUP VERIFY FAILED: $*\"}"
}

cleanup() {
  log "Cleaning up $RESTORE_DIR"
  rm -rf "$RESTORE_DIR"
  if [ "$DB_TYPE" = "postgresql" ]; then
    pg_ctlcluster 16 verify stop 2>/dev/null || true
  else
    mysqladmin -S /tmp/mysql-verify.sock shutdown 2>/dev/null || true
  fi
}
trap cleanup EXIT

mkdir -p "$RESTORE_DIR"

if [ "$DB_TYPE" = "postgresql" ]; then
  log "Starting PostgreSQL backup verification"

  # Restore latest pgBackRest backup to temporary directory
  pgbackrest --stanza=production \
    --pg1-path="$RESTORE_DIR/pgdata" \
    --type=immediate \
    --target-action=promote \
    restore 2>&1 | tee -a "$LOG_FILE"

  if [ ${PIPESTATUS[0]} -ne 0 ]; then
    alert "pgBackRest restore failed"
    exit 1
  fi

  # Start PostgreSQL on a different port
  pg_ctlcluster 16 verify start -- \
    -D "$RESTORE_DIR/pgdata" \
    -o "-p 5433" \
    -o "-c listen_addresses=127.0.0.1"

  sleep 5

  # Verify data integrity
  TABLES=$(psql -p 5433 -d production_db -t -c \
    "SELECT count(*) FROM information_schema.tables WHERE table_schema='public';")
  log "Verified $TABLES tables exist"

  ROW_CHECK=$(psql -p 5433 -d production_db -t -c \
    "SELECT count(*) FROM orders WHERE created_at > now() - interval '7 days';")
  log "Recent orders count: $ROW_CHECK"

  if [ "$ROW_CHECK" -lt 1 ]; then
    alert "PostgreSQL restore has no recent data — possible stale backup"
    exit 1
  fi

  # Run pg_amcheck for corruption detection (PostgreSQL 14+)
  pg_amcheck -p 5433 -d production_db --heapallindexed 2>&1 | tee -a "$LOG_FILE"

  log "PostgreSQL backup verification PASSED"

else
  log "Starting MySQL backup verification"

  # Prepare and restore latest XtraBackup
  LATEST_FULL=$(ls -td /backups/full-* | head -1)
  cp -r "$LATEST_FULL" "$RESTORE_DIR/mysql-data"
  xtrabackup --prepare --target-dir="$RESTORE_DIR/mysql-data"

  # Start MySQL on a different socket and port
  mysqld --datadir="$RESTORE_DIR/mysql-data" \
    --socket=/tmp/mysql-verify.sock \
    --port=3307 \
    --skip-networking=0 \
    --bind-address=127.0.0.1 &

  sleep 10

  # Verify data
  TABLES=$(mysql -S /tmp/mysql-verify.sock -e \
    "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='production_db';" -sN)
  log "Verified $TABLES tables exist"

  mysqlcheck -S /tmp/mysql-verify.sock --all-databases --check 2>&1 | tee -a "$LOG_FILE"

  log "MySQL backup verification PASSED"
fi

curl -s -X POST "$SLACK_WEBHOOK" \
  -H 'Content-Type: application/json' \
  -d "{\"text\":\"Backup verification PASSED for $DB_TYPE at $(date)\"}"

log "Verification complete"
Planification de reprise après sinistre du

: RTO et RPO

Chaque stratégie de sauvegarde doit être conçue autour de deux mesures :Objectif de temps de récupération (RTO)– combien de temps vous pouvez vous permettre d'être en panne – etObjectif de point de récupération (RPO)– quantité de données que vous pouvez vous permettre de perdre. Ces chiffres déterminent chaque décision concernant la fréquence, la méthode et l’architecture des sauvegardes.

ScénarioRTORPOStratégie
Paiement du commerce électronique< 5 min0 (aucune perte de données)Réplication synchrone + archivage WAL continu + basculement en veille chaude
Application SaaS< 30 minutes< 1 minRéplication streaming + archivage continu WAL-G + basculement automatisé
Outils internes< 4 heures< 1 heureDifférentiel journalier + incrémental horaire + archivage WAL
Analyses/entrepôt de données< 24 heures< 24 heuresSauvegarde complète quotidienne sur le stockage cloud
Développement/mise en scène< 48 heures< 1 semaineSauvegarde complète hebdomadaire

Pour un RPO nul, vous avez besoin d'une réplication synchrone vers au moins un serveur de secours. Cela ajoute de la latence à chaque transaction d'écriture mais garantit qu'aucune transaction validée n'est perdue. La plupart des systèmes de production acceptent un RPO (secondes de perte potentielle) proche de zéro en utilisant une réplication en streaming asynchrone avec un archivage continu des WAL/binlog, ce qui évite la pénalité de latence en écriture.

Modèle de runbook de récupération après sinistre

# DR Runbook: Database Recovery

## Severity Levels
- P1: Complete data loss / corruption — all hands, CEO notified
- P2: Partial data loss / single region down — on-call team + escalation
- P3: Replica failure / backup failure — on-call investigation

## Recovery Procedures

### Scenario A: Primary DB failure, replicas healthy
1. Promote replica to primary (automated via Patroni / orchestrator)
2. Verify application connectivity
3. Re-establish replication from new primary
4. Investigate root cause

### Scenario B: Complete cluster failure, backups intact
1. Provision new database infrastructure
2. Restore latest full backup
3. Apply WAL/binlog to reach latest consistent point
4. Verify data integrity with checksums
5. Update DNS / connection strings
6. Resume application traffic
7. Re-establish backup schedule immediately

### Scenario C: Data corruption (bad migration / SQL injection)
1. Identify exact timestamp of corruption
2. Restore to point-in-time just before corruption
3. Export affected tables from restored copy
4. Merge clean data into production
5. OR: full PITR restore if corruption is widespread

## Contacts
- DBA on-call: [PagerDuty rotation]
- Infrastructure: [PagerDuty rotation]
- VP Engineering: [phone number]

## Validation Checklist
- [ ] Application health checks pass
- [ ] Row counts match expected ranges
- [ ] Recent transactions are present
- [ ] Replication re-established
- [ ] Backup schedule resumed
- [ ] Post-incident review scheduled

Surveillance des sauvegardes et alertes

Les systèmes de sauvegarde

échouent silencieusement. La base de données continue de fonctionner, l'application continue de gérer le trafic et personne ne remarque que les sauvegardes ont cessé de fonctionner il y a trois semaines, jusqu'à ce qu'ils en aient besoin. Une surveillance proactive est essentielle.

# Prometheus alerting rules for backup monitoring
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: backup-alerts
  namespace: monitoring
spec:
  groups:
    - name: database-backups
      rules:
        - alert: BackupTooOld
          expr: |
            (time() - backup_last_successful_timestamp_seconds) > 90000
          for: 10m
          labels:
            severity: critical
          annotations:
            summary: "Database backup is older than 25 hours"
            description: "Last successful backup for {{ $labels.database }} was {{ $value | humanizeDuration }} ago"

        - alert: BackupJobFailed
          expr: |
            kube_job_status_failed{job_name=~".*backup.*"} > 0
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "Backup CronJob failed: {{ $labels.job_name }}"

        - alert: WALArchivingLagging
          expr: |
            pg_stat_archiver_failed_count > 0
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "PostgreSQL WAL archiving has failures"

        - alert: BackupStorageQuotaNearing
          expr: |
            (backup_storage_used_bytes / backup_storage_quota_bytes) > 0.85
          for: 30m
          labels:
            severity: warning
          annotations:
            summary: "Backup storage at {{ $value | humanizePercentage }} capacity"

        - alert: BinlogSpaceCritical
          expr: |
            mysql_binlog_size_bytes > 53687091200
          for: 10m
          labels:
            severity: warning
          annotations:
            summary: "MySQL binlog space exceeds 50GB — check archiving"
# Custom Prometheus exporter for pgBackRest metrics
#!/usr/bin/env python3
"""pgBackRest Prometheus exporter — exposes backup age and size metrics."""
import json
import subprocess
import time
from prometheus_client import start_http_server, Gauge

BACKUP_AGE = Gauge('pgbackrest_last_backup_age_seconds', 'Seconds since last backup', ['stanza', 'type'])
BACKUP_SIZE = Gauge('pgbackrest_last_backup_size_bytes', 'Size of last backup', ['stanza', 'type'])
BACKUP_REPO_SIZE = Gauge('pgbackrest_repo_size_bytes', 'Total repository size', ['stanza'])

def collect():
    result = subprocess.run(
        ['pgbackrest', '--output=json', 'info'],
        capture_output=True, text=True
    )
    info = json.loads(result.stdout)
    for stanza_info in info:
        stanza = stanza_info['name']
        for backup in stanza_info.get('backup', []):
            backup_type = backup['type']
            stop_time = backup['timestamp']['stop']
            age = time.time() - stop_time
            BACKUP_AGE.labels(stanza=stanza, type=backup_type).set(age)
            size = backup['info']['size']
            BACKUP_SIZE.labels(stanza=stanza, type=backup_type).set(size)

if __name__ == '__main__':
    start_http_server(9854)
    while True:
        collect()
        time.sleep(300)

Erreurs courantes et anti-modèles

Après avoir géré les sauvegardes de bases de données dans des dizaines d'environnements de production, ce sont les erreurs qui causent le plus de dégâts.

1. Sauvegarde sur le même disque que la base de données.Si le disque tombe en panne, vous perdez à la fois la base de données et la sauvegarde. Écrivez toujours les sauvegardes sur une cible de stockage distincte, idéalement hors hôte et hors région.

2. Ne testez jamais les restaurations.Une sauvegarde qui ne peut pas être restaurée n'est pas une sauvegarde. Planifiez des tests de restauration automatisés chaque semaine et demandez aux ingénieurs d'effectuer des exercices de restauration manuelle tous les trimestres.

3. S'appuyer uniquement sur la réplication comme sauvegarde. La réplicationn'est pas une sauvegarde. UnDROP TABLEsur le serveur principal est instantanément répliqué sur toutes les répliques. La réplication protège contre les pannes matérielles et non contre les erreurs logiques.

4. Ne pas surveiller les tâches de sauvegarde. Les tâches Cronéchouent silencieusement. Les CronJobs Kubernetes sont suspendus. Les informations d'identification S3 expirent. Chaque tâche de sauvegarde doit signaler le succès ou l'échec à un système de surveillance et alerter si la sauvegarde réussie la plus récente est plus ancienne que votre RPO.

5. Stockage des clés de cryptage avec les sauvegardes.Si un attaquant accède à votre stockage de sauvegarde, il ne devrait pas également disposer de la clé de déchiffrement. Stockez les clés dans un gestionnaire de secrets dédié.

6. Aucune politique de rétention.Sans politiques de cycle de vie, le stockage de sauvegarde croît sans limite. Définissez des fenêtres de conservation claires : 7 jours pour les segments WAL, 30 jours pour les sauvegardes quotidiennes, 12 mois pour les sauvegardes mensuelles et automatisez leur suppression.

7. Ignorer l'impact sur les performances de sauvegarde.L'exécution d'une sauvegarde complète sur une base de données principale pendant les heures de pointe dégrade les performances de l'application. Planifiez des sauvegardes pendant les fenêtres à faible trafic ou sauvegardez à partir d'une réplique dédiée.

8. Utilisation demysqldumppour les grandes bases de données sans--single-transaction.Sans cet indicateur,mysqldumpverrouille les tables, bloquant les écritures pendant la durée du dump. Pour les bases de données volumineuses, cela peut signifier des minutes ou des heures d’indisponibilité.

9. Oubli de sauvegarder la configuration de la base de données.La restauration des données ne représente que la moitié de la bataille. Si vous perdezpostgresql.conf,pg_hba.conf,my.cnf, les paramètres de réplication et les autorisations utilisateur, vous ne pouvez pas remettre la base de données dans un état utilisable. Incluez les fichiers de configuration dans votre processus de sauvegarde.

10. Ne pas documenter la procédure de restauration.Lors d'une panne, la personne qui restaure la base de données peut ne pas être celle qui a configuré les sauvegardes. Un runbook écrit et testé est essentiel.

Optimisation des coûts pour le stockage de sauvegarde

Les coûts de stockage de sauvegarde du

peuvent augmenter rapidement, en particulier avec des sauvegardes complètes fréquentes de bases de données volumineuses. Ces stratégies permettent de maîtriser les coûts sans compromettre la recouvrabilité.

Utiliser des sauvegardes incrémentielles/différentielles.Une sauvegarde complète hebdomadaire plus différentielle quotidienne utilise une fraction du stockage par rapport aux sauvegardes complètes quotidiennes. La capacité de restauration delta de pgBackRest signifie que les sauvegardes incrémentielles sont restaurées presque aussi rapidement que les sauvegardes complètes.

Activer la compression.Les algorithmes de compression modernes comme zstd offrent d'excellents taux de compression (5:1 à 10:1 pour les données de base de données typiques) avec une surcharge CPU minimale. pgBackRest et XtraBackup prennent en charge zstd de manière native.

Implémentez la hiérarchisation du stockage.Déplacez les sauvegardes vers des niveaux de stockage de moins en moins chers à mesure qu'elles vieillissent. Les politiques de cycle de vie présentées précédemment (S3 Standard → IA → Glacier, GCS Standard → Nearline → Coldline) peuvent réduire les coûts de stockage à long terme de 70 à 90 %.

Dédupliquer si possible.pgBackRest utilise la déduplication au niveau des blocs dans son référentiel, stockant uniquement les blocs modifiés dans les sauvegardes. Cela réduit considérablement le stockage des bases de données où la majorité des données sont statiques.

Fenêtres de rétention de bonne taille.De nombreuses équipes conservent par défaut les sauvegardes pour toujours, par prudence. Analysez vos modèles de récupération réels et vos exigences de conformité, puis définissez une rétention adaptée. Une exigence de conservation de 7 ans permet d'utiliser un stockage d'archives approfondi à moins de 1 $/To/mois sur la plupart des fournisseurs de cloud.

# Cost comparison: Full vs Incremental backup storage
# Assuming 500 GB database, 5% daily change rate, 30-day retention

# Strategy A: Daily full backups
# 500 GB × 30 days = 15,000 GB = 15 TB
# S3 Standard: 15 TB × $0.023/GB = $345/month

# Strategy B: Weekly full + daily incremental
# 4 full × 500 GB = 2,000 GB
# 26 incremental × 25 GB = 650 GB
# Total: 2,650 GB ≈ 2.6 TB
# S3 Standard: 2.6 TB × $0.023/GB = $59.80/month

# Strategy C: Strategy B + lifecycle tiering
# Current week: 525 GB Standard = $12.08
# Weeks 2-4: 2,125 GB Standard-IA = $26.56
# Total: $38.64/month

# Savings: Strategy C is 89% cheaper than Strategy A

Rassembler le tout : une architecture de sauvegarde complète

Voici l'architecture de sauvegarde recommandée pour un environnement de production exécutant à la fois MySQL et PostgreSQL, déployée sur Kubernetes avec reprise après sinistre multi-cloud.

Pour PostgreSQL :

  • pgBackRest comme outil de sauvegarde principal avec deux référentiels (S3 + Azure Blob)
  • Archivage WAL continu dans les deux référentiels
  • Sauvegarde complète hebdomadaire + différentiel quotidien (via K8s CronJob)
  • Instantanés de volume Longhorn toutes les 4 heures pour une restauration rapide
  • Vérification automatisée de la restauration tous les mercredis
  • Surveillance Prometheus avec alertes sur l'âge des sauvegardes, les pannes et le stockage

Pour MySQL :

  • Percona XtraBackup pour les sauvegardes physiques diffusées sur S3
  • Envoi continu de journaux binaires vers un stockage séparé
  • Hebdomadaire complet + incrémentiel quotidien (via K8s CronJob)
  • mysqldumpquotidien des schémas critiques pour les sauvegardes logiques portables
  • Instantanés de volume Longhorn toutes les 4 heures
  • Vérification automatisée de la restauration tous les jeudis

Pour le cluster Kubernetes :

  • Sauvegarde quotidienne Velero des espaces de noms de base de données avec instantanés PV
  • RKE2/k3s etcd instantanés toutes les 6 heures vers le stockage hors cluster
  • Dépôt
  • GitOps comme source de vérité pour tous les manifestes

Pour la reprise après sinistre :

    Réplication inter-région
  • S3 vers la région DR
  • Azure GRS pour copies de sauvegarde géoredondantes
  • Exercice DR mensuel : reconstruction complète du cluster à partir des sauvegardes dans la région DR
  • Runbook documenté avec arbre de décision pour chaque scénario de défaillance

Conclusion

Les sauvegardes de bases de données

constituent la dernière ligne de défense entre votre entreprise et une perte de données catastrophique. Les stratégies décrites dans cet article — sauvegardes physiques et logiques, archivage continu des WAL et des binlogs, stockage multi-cloud avec politiques de cycle de vie, chiffrement à chaque couche, planification automatisée via Kubernetes CronJobs et vérification systématique des restaurations — représentent l'état actuel de l'art pour les environnements de production MySQL et PostgreSQL.

Le point à retenir le plus important est le suivant : une stratégie de sauvegarde pourest aussi efficace que son dernier test de restauration réussi. Chaque outil, script et modèle d'architecture présenté dans cet article existe dans un seul but : garantir que, lorsque le pire se produit, vous puissiez récupérer vos données, respecter vos engagements RTO et RPO et maintenir votre entreprise en activité. Créez votre système de sauvegarde, automatisez-le, surveillez-le, testez-le, puis testez-le à nouveau. Votre futur moi vous remerciera.