Code source wiki de Sauvegarde
Afficher les derniers auteurs
| author | version | line-number | content |
|---|---|---|---|
| 1 | Sauvegarde quotidienne du serveur principal vers le Raspberry Pi avec [[Plakar>>https://plakar.io]] : dépôt chiffré et dédupliqué, transport SFTP. | ||
| 2 | |||
| 3 | == Fonctionnement == | ||
| 4 | |||
| 5 | |=Élément|=Valeur | ||
| 6 | |Machine sauvegardée|[[Serveur principal>>Wiki Batcave John.Infrastructure.ServeurPrincipal.WebHome]] | ||
| 7 | |Dépôt|SSD USB du [[Raspberry Pi>>Wiki Batcave John.Infrastructure.RaspberryPi.WebHome]] | ||
| 8 | |Transport|SFTP | ||
| 9 | |Déclenchement|Cron, chaque nuit à 3 h 30 | ||
| 10 | |Rétention|30 jours glissants | ||
| 11 | |Script|##/root/backup-plakar.sh## | ||
| 12 | |Journal|##/var/log/backup-plakar.log##, avec rotation par logrotate | ||
| 13 | |||
| 14 | Chaque exécution : | ||
| 15 | |||
| 16 | * exporte toutes les bases en SQL dans ##<APPDATA>/dumps## ; | ||
| 17 | * sauvegarde les données des conteneurs et la bibliothèque Immich, en excluant les fichiers bruts des bases ; | ||
| 18 | * supprime les instantanés de plus de 30 jours. | ||
| 19 | |||
| 20 | {{info}} | ||
| 21 | Les fichiers bruts d'une base en fonctionnement ne sont pas fiables pour une restauration. Ce sont les dumps SQL qui font foi. | ||
| 22 | {{/info}} | ||
| 23 | |||
| 24 | == Script == | ||
| 25 | |||
| 26 | {{code language="bash"}} | ||
| 27 | #!/bin/bash | ||
| 28 | set -euo pipefail | ||
| 29 | umask 077 # Ajout : dumps lisibles par root seul | ||
| 30 | |||
| 31 | REPO="sftp://<UTILISATEUR>@<HOTE_DEPOT>:<CHEMIN_DEPOT>" | ||
| 32 | KEYFILE="<FICHIER_PHRASE_SECRETE>" | ||
| 33 | DUMPS="<APPDATA>/dumps" | ||
| 34 | mkdir -p "$DUMPS" | ||
| 35 | |||
| 36 | # Dumps MariaDB/MySQL | ||
| 37 | for c in xwiki-mariadb-db passbolt-db castopod-test-db; do | ||
| 38 | docker exec "$c" sh -c 'exec mysqldump -uroot -p"${MYSQL_ROOT_PASSWORD:-$MARIADB_ROOT_PASSWORD}" --all-databases' \ | ||
| 39 | > "$DUMPS/$c.sql" 2>/dev/null \ | ||
| 40 | || docker exec "$c" sh -c 'exec mariadb-dump -uroot -p"${MYSQL_ROOT_PASSWORD:-$MARIADB_ROOT_PASSWORD}" --all-databases' \ | ||
| 41 | > "$DUMPS/$c.sql" 2>/dev/null \ | ||
| 42 | || echo "ATTENTION: dump $c échoué" >&2 | ||
| 43 | done | ||
| 44 | |||
| 45 | # Nextcloud : dump via l'utilisateur applicatif | ||
| 46 | docker exec "$(docker ps -q -f name=nextcloud_db)" sh -c 'exec mariadb-dump -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' \ | ||
| 47 | > "$DUMPS/nextcloud.sql" 2>/dev/null \ | ||
| 48 | || echo "ATTENTION: dump nextcloud échoué" >&2 | ||
| 49 | |||
| 50 | # Dumps PostgreSQL | ||
| 51 | for c in joplin-db flus-db wallabag-db immich_postgres vikunja-db jellystat-db n8n-postgres dawarich_db; do # Ajout : dawarich_db | ||
| 52 | docker exec "$c" sh -c 'exec pg_dumpall -U "$POSTGRES_USER"' \ | ||
| 53 | > "$DUMPS/$c.sql" 2>/dev/null \ | ||
| 54 | || echo "ATTENTION: dump $c échoué" >&2 | ||
| 55 | done | ||
| 56 | |||
| 57 | # Sauvegarde, sans core dumps, binlogs ni fichiers bruts des bases | ||
| 58 | plakar --concurrency 2 -keyfile "$KEYFILE" at "$REPO" backup \ | ||
| 59 | -ignore "**/joplin-app/core.*" \ | ||
| 60 | -ignore "**/Nextcloud/DB/**" \ | ||
| 61 | -ignore "**/log/mysql/**" \ | ||
| 62 | -ignore "**/xwiki/mariadb/**" \ | ||
| 63 | -ignore "**/store.bak.*/**" \ | ||
| 64 | <APPDATA> \ | ||
| 65 | <BIBLIOTHEQUE_IMMICH> | ||
| 66 | |||
| 67 | # Rétention : 30 jours glissants | ||
| 68 | plakar -keyfile "$KEYFILE" at "$REPO" rm -before 30d -apply | ||
| 69 | {{/code}} | ||
| 70 | |||
| 71 | Tâche cron, ##/etc/cron.d/backup-plakar## : | ||
| 72 | |||
| 73 | {{code}} | ||
| 74 | 30 3 * * * root /root/backup-plakar.sh >> /var/log/backup-plakar.log 2>&1 | ||
| 75 | {{/code}} | ||
| 76 | |||
| 77 | == Ajouter une base == | ||
| 78 | |||
| 79 | Ajouter le nom du conteneur dans la boucle MariaDB ou PostgreSQL du script, puis exclure ses fichiers bruts avec un ##-ignore## s'ils se trouvent dans ##<APPDATA>##. | ||
| 80 | |||
| 81 | == Vérifier == | ||
| 82 | |||
| 83 | {{code language="bash"}} | ||
| 84 | tail -n 50 /var/log/backup-plakar.log | ||
| 85 | grep ATTENTION /var/log/backup-plakar.log | ||
| 86 | sudo plakar -keyfile <FICHIER_PHRASE_SECRETE> at <REPO> ls | ||
| 87 | {{/code}} | ||
| 88 | |||
| 89 | == Restaurer == | ||
| 90 | |||
| 91 | Restaurer un instantané complet dans un dossier temporaire : | ||
| 92 | |||
| 93 | {{code language="bash"}} | ||
| 94 | sudo plakar -keyfile <FICHIER_PHRASE_SECRETE> at <REPO> restore -to /tmp/restore <ID_INSTANTANE> | ||
| 95 | {{/code}} | ||
| 96 | |||
| 97 | Réinjecter une base MariaDB : | ||
| 98 | |||
| 99 | {{code language="bash"}} | ||
| 100 | docker exec -i <CONTENEUR> sh -c 'exec mariadb -uroot -p"$MARIADB_ROOT_PASSWORD"' < /tmp/restore/<CHEMIN>/dumps/<CONTENEUR>.sql | ||
| 101 | {{/code}} | ||
| 102 | |||
| 103 | Réinjecter une base PostgreSQL (dump complet de l'instance) : | ||
| 104 | |||
| 105 | {{code language="bash"}} | ||
| 106 | docker exec -i <CONTENEUR> sh -c 'exec psql -U "$POSTGRES_USER" -d postgres' < /tmp/restore/<CHEMIN>/dumps/<CONTENEUR>.sql | ||
| 107 | {{/code}} | ||
| 108 | |||
| 109 | {{warning}} | ||
| 110 | Une sauvegarde qui n'a jamais été restaurée n'est pas une sauvegarde vérifiée. Faire un essai de restauration de temps en temps, dans un dossier temporaire. | ||
| 111 | {{/warning}} | ||
| 112 | |||
| 113 | == Incidents connus == | ||
| 114 | |||
| 115 | |=Symptôme|=Cause|=Solution | ||
| 116 | |Verrou restant après une exécution interrompue|Le processus a été coupé en cours|Supprimer le verrou orphelin avant de relancer | ||
| 117 | |Avertissements VFS|Cache local incohérent|Vider ##~~/.cache/plakar## de root | ||
| 118 | |Transfert coupé (EOF SFTP) sur de gros fichiers|Lien Wi-Fi du dépôt instable|Économie d'énergie Wi-Fi désactivée sur le Pi ; passer à ##~-~-concurrency 1## pour une première sauvegarde volumineuse | ||
| 119 | |Déconnexion du SSD pendant la sauvegarde|Pont USB en mode UAS|Voir la configuration SSD sur la page [[Raspberry Pi>>Wiki Batcave John.Infrastructure.RaspberryPi.WebHome]] |