====== 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]].**