====== Hyperviseur Gargantua ====== Cet [[documentations:hyperviseur|hyperviseur]] contient les machines virtuelles (KVM/QEMU) suivantes : ===== Orion : le serveur de sauvegarde n°1 ===== {{ :medias:constellation_orion.jpg?direct&600 |}} \\ \\ \\ Chez ilinux nous faisons les choses ... simplement : la sauvegarde suit ce concept du KISS (Keep It Simple, Stupid). {{ :medias:kiss2.jpg?direct&200 |}} Pour comprendre ce que suit je vous invite à consulter le [[documentations:reseau|schéma réseau de notre infrastructure]].\\ \\ En effet le positionnement du serveur de sauvegarde est primordial pour comprendre : \\ * le mode de fonctionnement adopté (mode pull), * la sécurisation qui en découle (isolation physique et logique du lieu de stockage des sauvegardes), * les possibilités d'évolution pour faire des sauvegardes sans pénaliser les performances de la production et sans interruption de service perceptibles par nos adhérents (snapshot). \\ \\ Voici un schéma synthétique des briques systèmes utilisées pour la sauvegarde (ici le LAN): {{ :medias:schema-sauvegarde-ilinux.png?direct&1000 |}} Le serveur de sauvegarde n°1 (Orion) peut donc accéder aux données de la production en **mode pull** (__il va chercher les données à sauvegarder__), c'est pour cela qu'il est : * **protégé derrière 3 pare-feu matériels et virtuels utilisant des technologies différentes**\\ (1 x pFsense - pfFilter, 2 x GNU/Linux - NetFilter), * **placé dans une zone accessible uniquement aux administrateur systèmes d'iLinux !**\\ Sans dévoiler d'information compromettante pour sa sécurité nous pouvons annoncer que l'accès ne se fait pas par identifiant, ni mot de passe : il faut détenir une clé de cryptage, connaître une phrase assez longue, et passer quelques portes ... **__Note__** : L'accès VPN dispose lui aussi d'un accès par clé avec en plus en mot de passe qui change toutes les 30 secondes ... Pour notre sauvegarde nous utilisons le logiciel libre [[https://www.borgbackup.org/|BorgBackup]].\\ {{ :medias:borgbackup.png?direct&200 |}} Nous n'allons pas nous étaler sur les [[https://www.borgbackup.org/demo.html|caractéristiques techniques]] de l'outil mais sachez seulement qu'il permet, entre autre : * de faire de la sauvegarde complète incrémentale (on ne sauvegarde que ce qui a changé), * de la dé-duplication de données : si vous stockez 100 fois les mêmes données, la sauvegarde de ces dernières ne prendra qu’une fois leur taille sur disque, * d'avoir une rétention de données considérable, * **de crypter la sauvegarde (ce que nous ne faisons pas chez ilinux)**, * ... voir le site officiel : [[https://borgbackup.readthedocs.io/en/stable/|ici]]. Chez ilinux nous appliquons la stratégie de rétention des données suivante pour l'ensemble de nos serveurs: * **une sauvegarde journalière glissante sur 15 jours,** * **une sauvegarde mensuelle, nous conservons les douze derniers mois,** * **une sauvegarde annuelle, nous gardons 5 années.** Nous pouvons donc parfaitement effectuer un **retour vers le passé**, mais comme toute bonne chose il **ne faut pas en abuser** ...\\ **... nom de Zeus !!!** \\ {{:medias:back_to_the_future.jpeg?direct&400|}} ==== Fonctionnement de la sauvegarde ==== Le serveur **Orion est une machine virtuelle** (pas un conteneur, SSHfs ne fonctionne pas avec un [[documentations:conteneur|conteneur]]).\\ Il sauvegarde un à un tous les serveurs de notre infrastructure, mais comme il travaille en sauvegarde incrémentielle , il ne copie que ce qui a changé depuis la sauvegarde précédente.\\ Sur des serveurs où les données ne changent quasiment pas (80 % de nos serveurs) on arrive à un temps de sauvegarde (exemple ci-dessous : 1 minutes 13.38 secondes) qui se compte en quelques minutes et à des tailles de sauvegarde ridicules (hormis pour la toute première sauvegarde). Les **__dépôts Borgbackup__** (les sauvegardes), un dépôt par serveur sauvegardé (physique, vm ou ct), sont placés **//sur un disque en RAID5//** piloté par **__mdadm__** qui nous signale par courriel un dysfonctionnement.\\ De plus grâce à SMART la moindre erreur sur les disques dur physiques nous est aussi remontée instantanément par courriel.\\ [[https://fr.wikipedia.org/wiki/RAID_(informatique)#RAID_5_:_volume_agr%C3%A9g%C3%A9_par_bandes_%C3%A0_parit%C3%A9_r%C3%A9partie|RAID5]] signifie que sur 3 disques dur, la perte d'un disque ne corrompt pas l'ensemble du disque. La sauvegarde fonctionne simplement avec ... 2 scripts écrits en BASH :-) : - un [[documentations:logiciels:gargantua#le_script_principal|script principal]] qui appelle des fonctions (on peut le lire comme du français), - un [[documentations:logiciels:gargantua#Le_script_boite_à_outils|script boite à outils]] dans lequel nous plaçons les fonctionnalités (fonctions) que nous réutilisons souvent (ce script est plus technique que le précédent !). Voici un exemple de rapport de sauvegarde qui est envoyé aux administrateurs systèmes d'ilinux : **__Note__ : A l'aide des filtres de courriel de Thunderbird il est facile de ne voir que les rapports critiques, ceux exigeants une action rapide.** >>>> sav_srv_ilinux.sh sur serveur : "websrv", executé le lundi 14 oct. 05:00:01 lundi 14 oct. 05:00:01 websrv sav_srv_ilinux.sh[2838]: [INFO] DEBUT-SCRIPT lundi 14 oct. 05:00:01 websrv sav_srv_ilinux.sh[2838]: [INFO] Parametres : "websrv" lundi 14 oct. 05:00:01 websrv sav_srv_ilinux.sh[2838]: [INFO] Serveur "websrv" en ligne lundi 14 oct. 05:00:01 websrv sav_srv_ilinux.sh[2838]: [INFO] Serveur "websrv" : "stop" "nginx" lundi 14 oct. 05:00:02 websrv sav_srv_ilinux.sh[2838]: [INFO] Export des bases "mysql" sous "/root/Prod/Sauvegardes/Bases" lundi 14 oct. 05:00:02 websrv sav_srv_ilinux.sh[2838]: [INFO] Compression du fichier "/root/Prod/Sauvegardes/Bases/websrv-mysql---all-databases.sql" sous "/root/Prod/Sauvegardes/Bases" lundi 14 oct. 05:00:03 websrv sav_srv_ilinux.sh[2838]: [INFO] Export des bases "postgresql" sous "/root/Prod/Sauvegardes/Bases" lundi 14 oct. 05:00:04 websrv sav_srv_ilinux.sh[2838]: [INFO] Compression du fichier "/root/Prod/Sauvegardes/Bases/websrv-postgresql---full.sql" sous "/root/Prod/Sauvegardes/Bases" lundi 14 oct. 05:00:04 websrv sav_srv_ilinux.sh[2838]: [INFO] Serveur "websrv" en ligne lundi 14 oct. 05:00:04 websrv sav_srv_ilinux.sh[2838]: [INFO] Montage "/root/Prod/mnt/BorgBackup/websrv" de "websrv" lundi 14 oct. 05:00:04 websrv sav_srv_ilinux.sh[2838]: [INFO] Sauvegarde de "/root/Prod/mnt/BorgBackup/websrv/etc /root/Prod/mnt/BorgBackup/websrv/root /root/Prod/mnt/BorgBackup/websrv/home /root/Prod/mnt/BorgBackup/websrv/var" en cours ------------------------------------------------------------------------------ Archive name: websrv-14_10_2019:00 Archive fingerprint: dae2ce16ahdfh4df9hd4h94dh4h9dd14fc6fcd6fe6ff8573378a55022f5dfd1 Time (start): Mon, 2019-10-14 05:00:05 Time (end): Mon, 2019-10-14 05:01:18 Duration: 1 minutes 13.38 seconds Number of files: 51726 ------------------------------------------------------------------------------ Original size Compressed size Deduplicated size This archive: 1.21 GB 1.21 GB 30.24 MB All archives: 36.33 GB 36.33 GB 2.45 GB Unique chunks Total chunks Chunk index: 42252 1554816 ------------------------------------------------------------------------------ lundi 14 oct. 05:01:22 websrv sav_srv_ilinux.sh[2838]: [INFO] Démontage de "/root/Prod/mnt/BorgBackup/websrv" lundi 14 oct. 05:01:22 websrv sav_srv_ilinux.sh[2838]: [INFO] Serveur "websrv" en ligne lundi 14 oct. 05:01:22 websrv sav_srv_ilinux.sh[2838]: [INFO] Serveur "websrv" : "start" "nginx" >>>> Statistiques du système de fichiers distant de "websrv" ... Sys. de fichiers Taille Utilisé Dispo Uti% Monté sur /dev/mapper/Raid1Data-vm--107--disk--0 270G 2,8G 253G 2% / none 504k 0 504k 0% /dev udev 8,4G 0 8,4G 0% /dev/tty tmpfs 8,4G 4,1k 8,4G 1% /dev/shm tmpfs 8,4G 18M 8,4G 1% /run tmpfs 5,3M 0 5,3M 0% /run/lock tmpfs 8,4G 0 8,4G 0% /sys/fs/cgroup tmpfs 1,7G 0 1,7G 0% /run/user/1000 tmpfs 1,7G 0 1,7G 0% /run/user/0 >>>> Statistiques du système de sauvegarde ... websrv-31_07_2019:00 Wed, 2019-07-31 05:00:02 websrv-31_08_2019:00 Sat, 2019-08-31 05:00:02 websrv-08_09_2019:00 Sun, 2019-09-08 05:00:03 websrv-15_09_2019:00 Sun, 2019-09-15 05:00:03 websrv-22_09_2019:00 Sun, 2019-09-22 05:00:03 websrv-29_09_2019:00 Sun, 2019-09-29 05:00:03 websrv-30_09_2019:00 Mon, 2019-09-30 05:00:02 websrv-01_10_2019:00 Tue, 2019-10-01 05:00:02 websrv-02_10_2019:00 Wed, 2019-10-02 05:00:02 websrv-03_10_2019:00 Thu, 2019-10-03 05:00:03 websrv-04_10_2019:00 Fri, 2019-10-04 05:00:02 websrv-05_10_2019:00 Sat, 2019-10-05 05:00:02 websrv-06_10_2019:00 Sun, 2019-10-06 05:00:03 websrv-06_10_2019:45 Sun, 2019-10-06 16:45:04 websrv-06_10_2019:50 Sun, 2019-10-06 16:50:36 websrv-06_10_2019:52 Sun, 2019-10-06 16:52:29 websrv-06_10_2019:56 Sun, 2019-10-06 16:56:27 websrv-06_10_2019:12 Sun, 2019-10-06 17:12:17 websrv-06_10_2019:15 Sun, 2019-10-06 17:15:59 websrv-06_10_2019:18 Sun, 2019-10-06 17:18:03 websrv-06_10_2019:22 Sun, 2019-10-06 20:22:09 websrv-06_10_2019:16 Sun, 2019-10-06 21:16:29 websrv-07_10_2019:00 Mon, 2019-10-07 05:00:08 websrv-08_10_2019:00 Tue, 2019-10-08 05:00:05 websrv-09_10_2019:00 Wed, 2019-10-09 05:00:05 websrv-10_10_2019:00 Thu, 2019-10-10 05:00:05 websrv-11_10_2019:00 Fri, 2019-10-11 05:00:05 websrv-12_10_2019:00 Sat, 2019-10-12 05:00:05 websrv-13_10_2019:00 Sun, 2019-10-13 05:00:05 websrv-14_10_2019:00 Mon, 2019-10-14 05:00:05 lundi 14 oct. 05:01:23 websrv sav_srv_ilinux.sh[2838]: [INFO] FIN-SCRIPT lundi 14 oct. 05:01:23 websrv sav_srv_ilinux.sh[2838]: [INFO] Courriel de notification ==== Le script principal ==== Tout est commenté ... ;-)\\ Ce script sauvegarde un serveur (type web/base de données) avec les services actifs suivants : * Nginx, * les bases Mysql, * les bases PostgreSQL, * les **fichiers stratégiques pour reconstruire le serveur** rapidement grâce aux modèles Proxmox. \\ - On envoie des informations initiales dans les journaux et le courriel (nom du script, date/heure, serveur sauvegardé, paramètres de lancement), - On commence par stopper le service d'entrée web du serveur : NGINX (on stoppe ce service, cela permettra d'avoir une sauvegarde consistante à tous les niveaux : système de fichiers, bases commitées), - On procède à un export sur le serveur distant de toutes les bases de données (mises à jour figées) présentes sur le serveur, - On procède à la sauvegarde des répertoires stratégiques de ce serveur et par conséquent des exports fait ci-dessus des bases de données, - On redémarre le service web : NGINX ... à ce stade l'exploitation peut reprendre, - On récolte les statistiques du système de fichiers et de l'historique des sauvegardes (borgbackup) de ce serveur, - On envoie le courriel de notification; - On a fini (avec des erreurs ou pas !) \\ **__A VOIR__** : Amélioration possible, faire un cliché instantané du système de fichiers avant ordre de dump/sauvegarde, le but étant de n'avoir aucune indisponibilité du service durant la sauvegarde. Par contre il faudra impérativement être sure que le cliché instantané est libéré.\\ => https://docs.ceph.com/docs/mimic/rbd/rbd-snapshot/\\ \\ #!/bin/bash ############################################################################### # # # PGM : Script de sauvegarde serveur (distant) web & databases # # # # AUTEUR : Stephane (iLinux) # # VERSION : 1.0.0 # # # # DATE : 03/06/2019 # # # # PARAM. : IN < SERVEUR à sauvegarder # # OUT > logger + mail # # # ############################################################################### # EN PREMIER LIEU # On inclus les fonctions et variables communes ( le script boite à outils) . ~/Prod/Scripts/fonctions_variables.sh # Variables de travail ... # ... LOCALES # ... DISTANTES # N/A # Au commencement il n'y a jamais d'erreur ... dans un script G_ERREUR=0 # Serveur à sauvegarder : SERVEUR=$1 # Surcharge var. fichier log (en attendant serveur mail !) #G_FICHIER_LOG="/root/Prod/Journaux/Sauvegardes/$SERVEUR.log" # Script actuellement en cours d'execution echo "SCRIPT : $G_APPLI" echo "" >> $G_FICHIER_LOG echo ">>>> $G_APPLI sur serveur : \"$SERVEUR\", executé le $G_JOUR $G_DATE">> $G_FICHIER_LOG echo "" >> $G_FICHIER_LOG # 1 seul paramétre attendu #if [ $# = 1 ] || [ -z "$1"] #then # G_ERREUR='Donnez 1 nom de serveur svp ...' # # On sort du script avec $G_ERREUR # g_log_message "ERROR" $G_MSG_FIN_SCRIPT # exit $G_ERREUR #fi # DEBUT DU SCRIPT g_log_message "INFO" $G_MSG_DEBUT_SCRIPT g_log_message "INFO" "Parametres : \"$*\"" # Préparation sauvegarde # # On stoppe le serveur web distant ... gestionServiceServeur $SERVEUR "stop" "nginx" # On fait les "dump" Mysql et PostgreSQL des bases sur le serveur distant sous "/root/Prod/Sauvegardes/Bases" ... # Rappel : sauvegardeBasesServeur server dbType dbDumpDir sauvegardeBasesServeur $SERVEUR "mysql" "/root/Prod/Sauvegardes/Bases" sauvegardeBasesServeur $SERVEUR "postgresql" "/root/Prod/Sauvegardes/Bases" # On lance la sauvegarde du système de fichiers ... (localement via le montage sshFS) depotBorgBackup="/Sauvegardes/Prod/$SERVEUR" mountDist="/root/Prod/mnt/BorgBackup/$SERVEUR" repertoiresAsauvegarder="$mountDist/etc $mountDist/root $mountDist/home $mountDist/var" sauvegardeBorgBackupServeur $SERVEUR "$depotBorgBackup" "$repertoiresAsauvegarder" # On relance le serveur Web distant gestionServiceServeur $SERVEUR "start" "nginx" # On audit le système de fichier distant (volumétrie etc) statutSFServeur $SERVEUR # On audit le système de sauvegarde statutBorgBackup "$depotBorgBackup" # On sort du script avec $G_ERREUR g_log_message "INFO" $G_MSG_FIN_SCRIPT exit $G_ERREUR # FIN DU SCRIPT ==== Le script boite à outils ==== Là aussi le code est abondamment commenté ;-)\\ Vous noterez que nous passons 80% du temps à tester les codes retours, dans le but d'avoir une sauvegarde la plus fiable et la plus transparente possible (via envoi de courriels journalier clairs et concis, un par serveur)\\ #!/bin/bash ############################################################################### # # # PGM : Script de fonctions et variables réutilisables # # # # AUTEUR : Stephane # # VERSION : 1.0.0 # # # # DATE : 02/06/2019 # # # # PARAM. : IN < N/A # # OUT > N/A # # # ############################################################################### # Variables de travail ... # ... LOCALES # ... DISTANTES # N/A # Chemin complet des outils utilises A GARDER POUR PORTABILITE MULTI-PLATEFORME etc ... # Ce fichier, amene a evoluer, contient en ensemble de fonctions et variables # globales courament utilisees. ########################### NOMENCLATURE (rajouter ici vos régles de nommage) # # Variable GLOBALE (doit etre reutilisee dans plusieurs script) # Elle est prefixee d'un "G_" comme "G_lobale" # G_ # Variable LOCALE (utilisable dans un script particulier) # a Elle n'est pas prefixee, et n'a donc pas lieu d'etre dans ce fichier # ormis leur présence dans les fonctions # # IDEM pour les fonctions : g_ # Par defaut quand nous definissons un chemin (PATH) nous ne mettrons jamais de "/" # en fin de chemin (cf. code ci-dessous) # Ce fichier contient une section GLOBALE et une section APPLI (specifique a certains scripts) ############################################################################### # # # GLOBALE # # # ############################################################################### # ####### VARIABLES GLOBALES ##################################################### # ELLES SONT OBLIGATOIRES POUR TOUT SCRIPT ECRIT export LANG=fr_FR.UTF-8 # NE PAS MODIFIER => sinon les jours ci-dessous seront en anglais. # MERCI G_DATE=`date +%d\ %b\ %T` G_JOUR=`date "+%A"` #G_NOM_MACHINE=`hostname` G_NOM_MACHINE=$1 G_APPLI=`basename $0` G_PID_APPLI=$$ G_FICHIER_LOG="/root/Prod/Journaux/Sauvegardes/$G_APPLI.log" G_COURRIEL_TXT="/root/Prod/Journaux/Sauvegardes/$G_APPLI-COURRIEL.txt" G_CONTACTS_MAIL="yourMonitoringMail@domain.tld" G_SUJET_MAIL="$G_APPLI sur $G_NOM_MACHINE" # Message de debut et fin de script G_MSG_DEBUT_SCRIPT="DEBUT-SCRIPT" G_MSG_FIN_SCRIPT="FIN-SCRIPT" # Il faudra mettre G_ERREUR=1 en cas de soucis et # bien sure ne jamais remettre a "0" cette variable !!! # Chemin complet des outils utilises A GARDER POUR PORTABILITE MULTI-PLATEFORME etc ... SSH="/usr/bin/ssh" #TAR="/bin/tar" MKDIR="/bin/mkdir" #LN="/bin/ln" #CHOWN="/bin/chown" #CHMOD="/bin/chmod" #CP="/bin/cp" #USERMOD="/usr/sbin/usermod" LOGGER="/usr/bin/logger" #MAIL="/usr/bin/mail" MSMTP="/usr/bin/msmtp" RM="/bin/rm" CAT="/bin/cat" DU="/usr/bin/du" DF="/bin/df" TEE="/usr/bin/tee" SYSTEMCTL='/bin/systemctl' SLEEP='/bin/sleep' SYNC='/bin/sync' UMOUNT='/bin/umount' MOUNT='/bin/mount' GREP='/bin/grep' GZIP='/bin/gzip' HOSTNAME='/bin/hostname' SMARTCTL='/usr/sbin/smartctl' CEPH='/usr/bin/ceph' WHICH='/usr/bin/which' # -> NE PAS ENLEVER MERCI. # Fonction qui permet de loger les messages d'erreurs, d'informations, de warning etc ... # Param IN $1 = TYPE du Message, gravité( INFO ou ERROR)voir doc. facility syslog # $2 = MESSAGE a loger # ex: g_log_message "INFO" "script arrêté" function g_log_message () { local TYPE=$1 local MESSAGE=$2 #Mise à jour de la date et de l'heure G_DATE=`date +%d\ %b\ %T` G_JOUR=`date "+%A"` # On prépare le formatage du type d'erreur pour le systeme SYSLOG (utilisation des priorités de logger : les "facilities" de syslog) case $TYPE in INFO) LOG_FACILITY=local3.info ;; ERROR) LOG_FACILITY=local3.error ;; WARNING) LOG_FACILITY=local3.warning ;; # AUTRE_TYPE) LOG_FACILITY=prefix.type # ;; *) #TODO codage type inconnu : on ne fait rien ;; esac # Mise en forme des informations pour affichage : local INFOS_APPLI="$G_NOM_MACHINE $G_APPLI[$G_PID_APPLI]:" # ... sur sortie standard echo $G_JOUR $G_DATE $INFOS_APPLI [$TYPE] $MESSAGE # ... dans le fichier log echo $G_JOUR $G_DATE $INFOS_APPLI [$TYPE] $MESSAGE >> $G_FICHIER_LOG # ... dans les log du système d'exploitation local DETAIL_APPLI="$G_APPLI[$G_PID_APPLI]" $LOGGER -t $DETAIL_APPLI -p $LOG_FACILITY $MESSAGE # Si c'est la fin du script on envoie un mail avec le fichier de log complet if [ "$MESSAGE" == "$G_MSG_FIN_SCRIPT" ] then if [ $G_ERREUR -eq 0 ] then G_SUJET_MAIL="SUCCES : $G_SUJET_MAIL" else G_SUJET_MAIL="ECHEC : $G_SUJET_MAIL" fi # On log la tache en cours ... echo $G_JOUR $G_DATE $INFOS_APPLI [$TYPE] "Courriel de notification" >> $G_FICHIER_LOG # Puis on prépare le fichier du courriel ($G_COURRIEL_TXT) et on lui ajoute le contenu du log ($G_FICHIER_LOG) echo -e "Subject: "$G_SUJET_MAIL"\r\n""Content-Type: text/plain; charset=UTF-8""\r\n" > $G_COURRIEL_TXT $CAT $G_FICHIER_LOG >> $G_COURRIEL_TXT # On envoie le courriel $CAT $G_COURRIEL_TXT | $MSMTP $G_CONTACTS_MAIL # ... et on les supprime (option -v disparue) $RM -f $G_FICHIER_LOG $RM -f $G_COURRIEL_TXT fi } function statutSF () { # Statistiques diverses echo "" >> $G_FICHIER_LOG echo " >>>> Statistiques du système de fichiers ..." >> $G_FICHIER_LOG echo "" >> $G_FICHIER_LOG $DF -Hl >> $G_FICHIER_LOG echo "" >> $G_FICHIER_LOG } function statutSFServeur () { local server=$1 # Statistiques diverses echo "" >> $G_FICHIER_LOG echo " >>>> Statistiques du système de fichiers distant de \""$server\"" ..." >> $G_FICHIER_LOG echo "" >> $G_FICHIER_LOG local command="$DF -Hl" $SSH $server $command >> $G_FICHIER_LOG echo "" >> $G_FICHIER_LOG } function statusSmartServeur () { local server=$1 shift # On enlève le premier arguments ($SERVEUR), pour traiter les devices (/dev/sdx) while [ $# -ge 1 ]; do #on sort après avoir traiter tous les arguments $#=0) => LOOP pas top a virer !!! ASAP # Récupération état SMART du périphérique passé en paramètre ... echo "" >> $G_FICHIER_LOG echo " >>>> Etat SMART du périphérique \""$1\"" de \""$server\"" ..." >> $G_FICHIER_LOG echo "" >> $G_FICHIER_LOG local command="$SMARTCTL -H -i $1" $SSH $server $command >> $G_FICHIER_LOG echo "" >> $G_FICHIER_LOG shift done } function statusCephServeur () { local server=$1 # Récupération état SMART du périphérique passé en paramètre ... echo "" >> $G_FICHIER_LOG echo " >>>> Etat du système de fichiers distribué CEPH de \""$server\"" ..." >> $G_FICHIER_LOG echo "" >> $G_FICHIER_LOG local command="$CEPH health" $SSH $server $command >> $G_FICHIER_LOG local command2="$CEPH df" $SSH $server $command2 >> $G_FICHIER_LOG echo "" >> $G_FICHIER_LOG } function statusRaidServeur () { local server=$1 # Récupération état système RAID ... echo "" >> $G_FICHIER_LOG echo " >>>> Etat du système RAID de \""$server\"" ..." >> $G_FICHIER_LOG echo "" >> $G_FICHIER_LOG local command="$CAT /proc/mdstat" $SSH $server $command >> $G_FICHIER_LOG echo "" >> $G_FICHIER_LOG } function statutBorgBackup () { local borgBackupRepository=$1 # Chemin complet des outils utilises A GARDER POUR PORTABILITÉ MULTI-PLATEFORME etc ... local BORG='/usr/bin/borg' echo "" >> $G_FICHIER_LOG echo " >>>> Statistiques du système de sauvegarde ..." >> $G_FICHIER_LOG $BORG list $borgBackupRepository >> $G_FICHIER_LOG echo "" >> $G_FICHIER_LOG } function serveurJoignable () { local server=$1 $SSH $server $HOSTNAME > /dev/null ret=$? if [ $ret -ne 0 ];then # ... erreur pour récupérer le nom d'hote du serveur distant G_ERREUR=$ret g_log_message "ERROR" "Serveur \"$server\" injoignable, ssh: \"$G_ERREUR\"" return $G_ERREUR else g_log_message "INFO" "Serveur \"$server\" en ligne" return 0 fi } function gestionService () { local action=$1 local service=$2 $SYSTEMCTL $action $service ret=$? if [ $ret -ne 0 ];then # ... erreur à l'arrêt/démarrage du service G_ERREUR=$ret g_log_message "ERROR" "$action \"$service\" impossible \"$G_ERREUR\"" return $G_ERREUR else g_log_message "INFO" "$action \"$service\"" return 0 fi } function gestionServiceServeur () { local server=$1 local action=$2 local service=$3 # Serveur en ligne ? serveurJoignable $server ret=$? if [ $ret -ne 0 ];then # ... erreur serveur injoignable, on sort avec le code erreur. return $ret fi local command="$SYSTEMCTL $action $service" $SSH $server $command > /dev/null ret=$? if [ $ret -ne 0 ];then # ... erreur à l'arrêt/démarrage du service G_ERREUR=$ret g_log_message "ERROR" "Serveur \"$server\" : \"$action\" \"$service\" impossible \"$G_ERREUR\"" return $G_ERREUR else g_log_message "INFO" "Serveur \"$server\" : \"$action\" \"$service\"" return 0 fi } function demontage () { local pointMontage=$1 $UMOUNT $pointMontage ret=$? if [ $ret -ne 0 ];then # ... erreur au démmontage G_ERREUR=$ret g_log_message "ERROR" "Impossible de démonter \"$pointMontage\" erreur \"$G_ERREUR\"" return $G_ERREUR else g_log_message "INFO" "Démontage de \"$pointMontage\"" return 0 fi } function montageHdd () { local pointMontage=$1 $MOUNT $pointMontage ret=$? if [ $ret -ne 0 ];then # ... erreur au montage G_ERREUR=$ret g_log_message "ERROR" "Impossible de monter \"$pointMontage\" erreur \"$G_ERREUR\"" return $G_ERREUR else g_log_message "INFO" "Montage de \"$pointMontage\"" return 0 fi } function montageSshFS () { local SSHFS='/usr/bin/sshfs' #local SSHFS='/usr/bin/sshfs -oCiphers=arcfour' local server=$1 local pointMontage=$2 $SSHFS $server:/ $pointMontage &>> $G_FICHIER_LOG ret=$? if [ $ret -ne 0 ];then # ... erreur au montage G_ERREUR=$ret g_log_message "ERROR" "Impossible de monter \"$pointMontage\" de \"$server\" erreur \"$G_ERREUR\"" return $G_ERREUR else g_log_message "INFO" "Montage \"$pointMontage\" de \"$server\"" return 0 fi } #function sauvegardeBase () # SI utilisé : CODE à RELIRE !!! #{ # #} function sauvegardeBasesServeur () { local server=$1 #serveur distant local dbType=$2 #mysql ou postgresql local dbDumpDir=$3 #répertoire ou sera placé le dump sur le $server distant # Chemin complet des outils utilises A GARDER POUR PORTABILITÉ MULTI-PLATEFORME etc ... local MYSQLDUMP='/usr/bin/mysqldump' local POSTGRESQLDUMP='/usr/bin/pg_dump' local POSTGRESQLDUMPALL='/usr/bin/pg_dumpall' local SYNC='/bin/sync' local dbUser='' local dbName='' local dbPwd='' # Preparation env. dump sur serveur distant # Note : Il n'y a théoriquement plus de transaction sur la base de données car les services susceptibles de provoquer des update etc sont arrêtés, les FS SYNC local command="$SSH $server [ -d $dbDumpDir]" if [ command ];then # Si le repertoire ou sera déposé le dump n'est pas présent ... local command="$MKDIR -p $dbDumpDir" # ... alors nous le créons. $SSH $server $command > /dev/null ret=$? if [ $ret -ne 0 ];then # ... erreur à la création du répertoire contenant le dump des bases de données G_ERREUR=$ret g_log_message "ERROR" "Impossible d'acceder au repertoire de dump \"$dbDumpDir\" erreur \"$G_ERREUR\"" return $G_ERREUR fi fi case $dbType in mysql) # On test si MySQL est présent ... sinon on sort command="$WHICH mysql" $SSH $server $command > /dev/null ret=$? # On stocke le code retour de la commande if [ $ret -ne 0 ];then # ... erreur g_log_message "WARNING" "\"$dbType\" non disponible" return 0 fi # ... mysql présent , on continue ! dbName='--all-databases' # Toutes les bases (option Mysql, donc ne pas changer SVP!!!!!) dbUser='admin' dbPwd='xxxxxxxxxxxxxxxxxx' # Préparation de la commande pour MySql local command="$MYSQLDUMP -u$dbUser -p$dbPwd -h localhost --single-transaction --opt $dbName > $dbDumpDir/$server-$dbType-$dbName.sql" ;; postgresql) # On test si PostgreSQL est présent ... sinon on sort command="$WHICH psql" $SSH $server $command > /dev/null ret=$? # On stocke le code retour de la commande if [ $ret -ne 0 ];then # ... erreur g_log_message "WARNING" "\"$dbType\" non disponible" return 0 fi # ... postgresql présent , on continue ! dbName='--full' # Toutes les bases (nommage ilinux) dbUser='postgresUser' # fonctionne avec le fichier /root/.pgpass, en chmod 0600, et un password à postgres (psql : \password) # Préparation de la commande pour PostgreSQL local command="$POSTGRESQLDUMPALL -U $dbUser -h localhost > $dbDumpDir/$server-$dbType-$dbName.sql" ;; *) # Base de donnée inconnue : ERREUR G_ERREUR=1 g_log_message "ERROR" "Impossible de sauvegarder le type de base \"$dbType\"" return $G_ERREUR ;; esac # On lance l'export des bases de données : $SSH $server $command > /dev/null ret=$? # On stocke le code retour de la commande # on teste le resultat de l'export des bases de données : if [ $ret -ne 0 ];then # ... erreur durant le dump(export) G_ERREUR=$ret g_log_message "ERROR" "Export impossible des bases \"$dbType\" erreur \"$G_ERREUR\"" return $G_ERREUR else g_log_message "INFO" "Export des bases \"$dbType\" sous \"$dbDumpDir\"" fi # Compression de l'export des bases de données, avec SYNC du systéme de fichiers préalable : command="$SYNC ; $GZIP -f $dbDumpDir/$server-$dbType-$dbName.sql" $SSH $server $command > /dev/null ret=$? # On test le resultat de la compression ... if [ $ret -ne 0 ];then # ... erreur durant la compression de l'export G_ERREUR=$ret g_log_message "ERROR" "Compression impossible du fichier \"$dbDumpDir/$server-$dbType-$dbName.sql\" erreur \"$G_ERREUR\"" return $G_ERREUR else g_log_message "INFO" "Compression du fichier \"$dbDumpDir/$server-$dbType-$dbName.sql\" sous \"$dbDumpDir\"" return 0 fi # On synchronise les I/O (entrée sorties du système de fichiers en vue de la sauvegarde BorgBackup) $SYNC } ######### FONCTION ###################################################### # # Sauvegarde une liste de répertoire vers une destination avec BorgBackup # Param IN $1 = Serveur à sauvegarder # $2 = dépot BorgBackup à utiliser # $3 = Répertoires à sauvegarder # # Ex. appel : sauvegardeBorgBackup $SERVER "$depotBorgBackup" "$repertoiresAsauvegarder" # # Note la politique de rétention de données est : --keep-within=15d --keep-weekly=4 --keep-monthly=12 --keep-yearly=5 # - 5 ans, # - 12 mois, # - 4 semaines, # - 15 jours consécutifs, function sauvegardeBorgBackupServeur () # sauvegarde serveur distant avec sshFS { local server=$1 local borgBackupRepo=$2 local dirsToBackup=$3 local borgMntPoint="/root/Prod/mnt/BorgBackup/$server" # Point de montage du système de fichiers du serveur distant (/, racine) # Chemin complet des outils utilises A GARDER POUR PORTABILITÉ MULTI-PLATEFORME etc ... local BORG='/usr/bin/borg' local SYNC='/bin/sync' # Serveur en ligne ? serveurJoignable $server ret=$? if [ $ret -ne 0 ];then # ... erreur serveur injoignable, on sort avec le code erreur. return $ret fi # Verification du répertoire du point de montage pour sshFS if [ ! -d $borgMntPoint ];then # Si le repertoire pour le pt de montage de sshFS n'est pas présent ... $MKDIR -p $borgMntPoint # ... alors nous le créons. ret=$? if [ $ret -ne 0 ];then # ... erreur à la création du repertoire (sshFS) G_ERREUR=$ret g_log_message "ERROR" "Impossible de creer le repertoire pour sshFS \"$borgMntPoint\" erreur \"$G_ERREUR\"" return $G_ERREUR fi fi # Montage du système de fichier / (root/racine) distant sur $borgMntPoint (répertoire temporaire pour la sauvegarde) montageSshFS $server $borgMntPoint ret=$? if [ $ret -ne 0 ];then # ... erreur pour le montage du systéme de fichiers distant, on sort avec le code erreur. return $ret fi # Verification du dépot BorgBackup $borgBackupRepo if [ ! -d $borgBackupRepo ];then # Si le dépôt BorgBackup n'est pas présent ... $BORG init --encryption=none $borgBackupRepo # ... alors nous le créons, sans cryptage (CPU eater...). ret=$? if [ $ret -ne 0 ];then # ... erreur à la création du dépôt BorgBackup G_ERREUR=$ret g_log_message "ERROR" "Impossible d'initialiser le dépôt BorgBackup \"$borgBackupRepo\" erreur \"$G_ERREUR\"" # ARRET de la sauvegarde (on synchronise les i/O et demonte le système de ficher racine distant) $SYNC #synchro des IO disques (pour laisser un FS distant propre) demontage $borgMntPoint return $G_ERREUR fi fi # On lance la sauvegarde ... g_log_message "INFO" "Sauvegarde de \"$dirsToBackup\" en cours" # ... on corrige le bug export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes $BORG create -v --stats $borgBackupRepo::$server-{now:%d_%m_%Y:%M} $dirsToBackup &>> $G_FICHIER_LOG # On vérifie que la sauvegarde s'est bien déroulée ... ret=$? if [ $ret -eq 2 ];then # ... erreur durant la sauvegarde, on sort en erreur. G_ERREUR=$ret g_log_message "ERROR" "Borg backup erreur \"$G_ERREUR\"" # ARRET de la sauvegarde (on synchronise les i/O et demonte le système de ficher racine distant) $SYNC #synchro des IO disques demontage $borgMntPoint return $G_ERREUR else #Rétention, 15 jours, 4 semaines, 1 par mois, sur 5 ans ... $BORG prune --error --keep-within=15d --keep-weekly=4 --keep-monthly=12 --keep-yearly=5 $borgBackupRepo &>> $G_FICHIER_LOG # On vérifie que la rétention a bien fonctionné ... (nettoyage des anciennes sauvegardes) ret=$? if [ $ret -eq 2 ];then # ... erreur durant la rétention, on sort en erreur. G_ERREUR=$ret g_log_message "ERROR" "Borg prune erreur \"$G_ERREUR\"" # ARRET de la sauvegarde (on synchronise les i/O et demonte le système de ficher racine distant) $SYNC #synchro des IO disques demontage $borgMntPoint return $G_ERREUR fi fi # Fin de la sauvegarde (on synchronise les i/O et demonte le système de ficher racine distant) $SYNC #synchro des IO disques demontage $borgMntPoint } function sauvegardeBorgBackup () # Sauvegarde locale { local server=$1 local borgBackupRepo=$2 local dirsToBackup=$3 # Chemin complet des outils utilises A GARDER POUR PORTABILITÉ MULTI-PLATEFORME etc ... local BORG='/usr/bin/borg' local SYNC='/bin/sync' # Verification du dépot BorgBackup $borgBackupRepo if [ ! -d $borgBackupRepo ];then # Si le dépôt BorgBackup n'est pas présent ... $BORG init --encryption=none $borgBackupRepo # ... alors nous le créons, sans cryptage. ret=$? if [ $ret -ne 0 ];then # ... erreur à la création du dépôt BorgBackup G_ERREUR=$ret g_log_message "ERROR" "Impossible d'initialiser le dépôt BorgBackup \"$borgBackupRepo\" erreur \"$G_ERREUR\"" # ARRET de la sauvegarde $SYNC #synchro des IO disques return $G_ERREUR fi fi # On lance la sauvegarde ... g_log_message "INFO" "Sauvegarde de \"$dirsToBackup\" en cours" # ... on corrige le bug export BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes $BORG create -v --stats $borgBackupRepo::$server-{now:%d_%m_%Y:%M} $dirsToBackup &>> $G_FICHIER_LOG # On vérifie que la sauvegarde s'est bien déroulée ... ret=$? if [ $ret -eq 2 ];then # ... erreur durant la sauvegarde, on sort en erreur. G_ERREUR=$ret g_log_message "ERROR" "Borg backup erreur \"$G_ERREUR\"" # ARRET de la sauvegarde $SYNC #synchro des IO disques return $G_ERREUR else #Rétention, 10 jours, 4 semaines, 1 par mois, sur 5 ans ... $BORG prune --error --keep-within=15d --keep-weekly=4 --keep-monthly=12 --keep-yearly=5 $borgBackupRepo &>> $G_FICHIER_LOG # On vérifie que la rétention a bien fonctionné ... (nettoyage des anciennes sauvegardes) ret=$? if [ $ret -eq 2 ];then # ... erreur durant la rétention, on sort en erreur. G_ERREUR=$ret g_log_message "ERROR" "Borg prune erreur \"$G_ERREUR\"" # ARRET de la sauvegarde (on synchronise les i/O et demonte le système de ficher racine distant) $SYNC #synchro des IO disques demontage $borgMntPoint return $G_ERREUR fi fi # Fin de la sauvegarde (on synchronise les i/O) $SYNC #synchro des IO disques } Ensuite chaque serveur est sauvegardé via la crontab ... ( si certains connaissent un bon **[[documentations:ordonnanceur|ordonnanceur]]** sur GNU/Linux je suis preneur ! ... à l'époque je jouais avec Ortro) 20 0 * * * /root/Prod/Scripts/Sauvegardes/backup_srv_std.sh serveur_001 > /dev/null **Code iLinux: nos codes sources sont également disponibles dans [[https://gitea.ilinux.fr/|notre forge logiciel Gitea (Git)]].**\\ **__TODO__ : Installation et paramétrage du serveur** ** Ensuite ces sauvegardes sont externalisées chaque jour sur un autre site, sur un autre serveur : [[documentations:logiciels:saintbabel#Rigel|rigel]].**