Archives par mot-clé : sauvegarde

Sauvegarde de mon serveur web

Le serveur hébergeant entre autres Moodle et GLPI est une machine virtuelle située dans notre établissement.

Voici notre politique de sauvegarde et les scripts associés.

Principe de la sauvegarde

Chaque nuit, les BDD et les répertoires critiques de mon serveur sont copiés sur un espace disque partagé et sécurisé. Il en résulte donc un répertoire par jour d'environ 200 Go avec une navigation rapide dans l'arborescence si nécessaire.

Chaque semaine, ces même sauvegardes (mais pas seulement) sont copiées sur un disque externe, puis mise dans un coffre fort situé dans un autre bâtiment. Deux disques jouent ce rôle l'un après l'autre.

Il en résulte donc 3 semaines de sauvegarde facilement accessibles et relativement bien protégées.

J'ai hérité de scripts de sauvegarde que j'ai adapté à mes besoins pour gagner en efficacité et rapidité de traitement.

Prérequis

Un répertoire réseau partagé

Les copies seront dans un premier temps placées dans un répertoire réseau  partagé avec accès par un utilisateur en écriture correspondant à la machine qui crée la sauvegarde.

Un utilisateur MySQL dédié

Par sécurité, chaque base de donnée à un accès en écriture par un utilisateur différent (je n'utilise pas l'utilisateur root...). Je crée donc un utilisateur « dump » dédié à la tache de copier la base et qui n'a besoin que d'un accès en lecture à chacune des base.

mysql -u root -p -e "CREATE USER 'dump'@'localhost' IDENTIFIED BY 'LEMOTDEPASSE';"
mysql -u root -p -e "GRANT SELECT , SHOW DATABASES , LOCK TABLES , SHOW VIEW ON * . * TO 'dump'@'localhost' IDENTIFIED BY 'LEMOTDEPASSE' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;"

Les fichiers qui vont bien

Script de sauvegarde

Petite explication des étapes :

  1. D'abord, on déclare les variables de travail.
  2. Je demande que les erreurs soient logguées dans un fichier error.log.
  3. D'un autre coté, je logue chaque étape dans un fichier backup.log avec les horaires correspondants.
  4. Je baisse la priorité de l'action de manière à ce que si des utilisateurs veulent accéder au serveur, il puisse répondre convenablement.
  5. Pour le dump des bases de données, la seule particularité réside dans le fait que je dump en local pour en faire une copie des fichiers ensuite : charge le serveur moins longtemps.
  6. Je monte ensuite le disque de manière faire mes copies.
  7. Pour la copie des fichiers, j'utilise rsync qui fait une copie « simple » lors de la première sauvegarde (4h30 pour 200 Go, soit les 7 premiers jours) mais qui ensuite ne fera qu'une synchronisation (durée ramenée à 30 minutes environ). Dans les options de rsync, j'utilise selon les cas :
    • --stats : affiche les statistiques de l'opération
    • --progress : affiche la progression de l'opération
    • --copy-links : copie les fichiers cibles des liens symbolique en tant que fichiers
    • --delete-after : qui supprime sur la destination les fichiers ayant été supprimés dans la source, en fin d'opération.
    • --exclude-from : qui indique un fichier texte dans lequel j'écris les répertoires et fichiers à ne pas synchroniser.
  8. Je copie les fichiers de log sur le répertoire distant.
  9. Je démonte le disque réseau.
  10. J'envoie un rapport par mail.

sauvegarde.sh

#!/bin/bash

# Création des variables
# Globales
MAIL='mail@domaine.fr'
HOSTNAME='computer name'
SAVE_DIR='//192.168.1.1/backup'
MOUNTED_DIR='/mnt/sauvegarde'
LOCAL_SQL_DIR='/home/scripts/dump_sql'
LOG_FILE='/home/scripts/backup.log'
ERROR_LOG_FILE='/home/scripts/error.log'
# User for external disk usage
EXT_USER='user'
EXT_PASS='password'
EXT_DOMAIN='domain'
# SQL user informations
SQL_USER='dump'
SQL_PASS='pass_sql'
SQL_EXCLUSION='(information_schema|performance_schema)'

# Dates
NOW=$(date +"%Y-%m-%d")
DAY=$(date +"%A")
MOUNTH=$(date +"%m")
WEEK=$(date +"%V")
YEAR=$(date +"%Y")

# Destination directory
DEST_DIR=$MOUNTED_DIR/$DAY 

# Error log
echo "Error log for $NOW :">$ERROR_LOG_FILE
exec 2>> $ERROR_LOG_FILE

# Low priority
ionice -c3 -p$$ &>/dev/null
renice -n 19 -p $$ &>/dev/null

## Let's go
echo "Backup for $NOW on $HOSTNAME :">$LOG_FILE
echo " ">>$LOG_FILE

# Local MySQL dump
echo "Local MySQL dump">>$LOG_FILE

# Make local directory if not exist
 mkdir -p $LOCAL_SQL_DIR;
 
 # Get bases name
 databases="$(mysql -u$SQL_USER -p$SQL_PASS -Bse 'show databases' | grep -v -E $SQL_EXCLUSION)"
 
 # Dump
 for database in ${databases} 
 do
 echo "$(date +"%H:%M:%S") : dump $database">>$LOG_FILE
 mysqldump -u$SQL_USER -p$SQL_PASS $database > $LOCAL_SQL_DIR/${database}.sql
 done

# End local MySQL dump
echo "$(date +"%H:%M:%S") : dump finished">>$LOG_FILE
echo "------------------------------------">>$LOG_FILE

# Directory sync 
echo "Files sync">>$LOG_FILE

# Make mounted directory if not exist
 mkdir -p $MOUNTED_DIR;

# Mount
 echo "$(date +"%H:%M:%S") : mount $MOUNTED_DIR">>$LOG_FILE
 mount -t cifs -o username=$EXT_USER,pass=$EXT_PASS,domain=$EXT_DOMAIN $SAVE_DIR $MOUNTED_DIR

# Make destination directory if not exist
 mkdir -p $DEST_DIR;

# Sync files
 echo "$(date +"%H:%M:%S") : sync $LOCAL_SQL_DIR">>$LOG_FILE
 rsync -a --stats --progress --delete-after $LOCAL_SQL_DIR $DEST_DIR

echo "$(date +"%H:%M:%S") : sync /var/www/html">>$LOG_FILE
 rsync -a --stats --progress --exclude-from=/home/scripts/excludes_html.txt --delete-after /var/www/html $DEST_DIR

echo "$(date +"%H:%M:%S") : sync /root">>$LOG_FILE
 rsync -a --stats --progress --copy-links --delete-after /root $DEST_DIR

echo "$(date +"%H:%M:%S") : sync /etc">>$LOG_FILE
 rsync -a --stats --progress --copy-links --delete-after /etc $DEST_DIR

echo "$(date +"%H:%M:%S") : sync /home/moodledata">>$LOG_FILE
 rsync -a --stats --progress --exclude-from=/home/scripts/excludes_moodledata.txt --delete-after /home/moodledata $DEST_DIR

# End directory sync
echo "$(date +"%H:%M:%S") : sync finished">>$LOG_FILE
echo "------------------------------------">>$LOG_FILE

# Synchronisation des buffers des disques 
sync

# Log file copy
echo "$(date +"%H:%M:%S") : copy log file">>$LOG_FILE
cp $LOG_FILE $DEST_DIR/
echo "$(date +"%H:%M:%S") : copy error file">>$LOG_FILE
cp $ERROR_LOG_FILE $DEST_DIR/

# Umount 
echo "$(date +"%H:%M:%S") : unmount $MOUNTED_DIR">>$LOG_FILE
umount $MOUNTED_DIR

# Ended
echo "$(date +"%H:%M:%S") : -- Backup done ! --">>$LOG_FILE

# Send mail report
mail -s "$HOSTNAME : $NOW backup report" $MAIL < $LOG_FILE
mail -s "$HOSTNAME : $NOW error log" $MAIL < $ERROR_LOG_FILE

 

Fichier d'exclusion pour le répertoire Moodledata

J'enlève les fichiers bak et log, les fichiers de sessions et temporaires de moodle (peut être un héritage des anciennes versions d'ailleurs).

excludes_moodledata.txt

*.bak
*.log
/moodledata/sessions
/moodledata/temp

Fichier d'exclusion pour le répertoire html

J'enlève les fichiers bak et log, les fichiers de sessions de GLPI, et quelques répertoires situés dans /var/www/html commençant par _.

excludes_html.txt

*.bak
*.log
/html/glpi/files/_sessions
/html/_*

Automatisation

Après essais et ajustement, et surtout vérification que les fichiers de la sauvegarde soient bien présents et utilisables, je demande à un cron d’exécuter ce script chaque nuit à 23h00.

00 23 * * * sh /home/scripts/sauvegarde.sh

Édition :

  • Edit suite à la remarque de Cascador : mkdir -p

Sources d'inspiration :

  • http://david.mercereau.info/script-de-sauvegarde-mysql-par-base-mysql_dump-sh/
  • http://linuxfocus.org/Francais/March2004/article326.shtml

Mise à jour Moodle 2.3 vers Moodle 2.5 par GIT

Résumé des opérations effectuées.

Sauvegarde

tar -czf /home/moodle/save_rep_moodle_data.tar.gz /home/moodle/upload
tar -czf /home/moodle/save_rep_moodle.tar.gz /var/www/html/moodle
mysqldump -uUSERNAME -pPASSWORD -e -q -Q --add-drop-table moodle | gzip > /home/moodle/save_bdd_moodle.sql.gz

Optimisation de la base de données

mysqlcheck --auto-repair --database moodle
mysqlcheck --optimize --database moodle

Mise à jour par GIT

cd /var/www/html/moodle
/usr/bin/php admin/cli/maintenance.php --enable
git pull
/usr/bin/php admin/cli/upgrade.php
git branch -a
git checkout -b local_25_STABLE origin/MOODLE_25_STABLE
/usr/bin/php admin/cli/upgrade.php
/usr/bin/php admin/cli/maintenance.php --disable

En savoir plus...

Sauvegarder Moodle

Dans Moodle, il existe 3 objets à sauvegarder régulièrement :

  • le répertoire qui contient Moodle (et ses éventuelles modifications)
  • le répertoire qui contient les données utilisateurs / fichiers des cours...
  • la base de donnée
Perso, je compresse ce données dans un répertoire et je copie le répertoire résultant sur un disque extérieur par sécurité. En cas de soucis, j'ai toutes les infos nécessaires pour rétablir mon Moodle tel qu'il était à une date donnée.

Étapes

Moodle : copie du répertoire
tar -czf /home/moodle/save/rep_moodle.tar.gz /var/www/html/moodle
Moodledata : copie du répertoire
tar -czf /home/moodle/save/rep_moodle_data.tar.gz /home/moodle/upload
MySql : dump de la base SQL
mysqldump -uUSERNAME -pPASSWORD -e -q -Q --add-drop-table moodle | gzip > /home/moodle/save/bdd_moodle.sql.gz

Optimisation

N'hésitez pas à scripter ces commandes et à les lancer par cron régulièrement... avec la date du jour en plus dans le nom du répertoire par exemple.