«

»

août 25

Sauvegarde distante avec rsync entre windows et linux

Introduction

Dans cet article je vais tenter de vous expliquer comment mettre en place une sauvegarde distante entre un serveur de fichiers sous Windows 2008 R2 et un serveur sous linux.

Périmètre de ce tuto

Les explications qui vont suivre s’appliquent à la distribution Linux CentOS 6.4. Comme d’habitude elle devraient faire l’affaire sur une autre distrib, mais il est possible que quelques détails doivent être modifier pour que cela fonctionne. De plus, il existe plusieurs solutions pour mettre en place une sauvegarde de ce type avec rsync. Je n’en traiterai que deux. Les voici :

  1. Un Linux sur un site A attaquant un serveur de fichiers Windows 2008 R2 sur un site B au travers d’une liaison VPN.
  2. Un Linux sur un site A attaquant un Linux sur un site B au travers d’une liaison VPN, qui lui-même accède au serveur de fichiers Windows 2008 R2 du site B

Notez que je ne traiterai absolument pas des questions de VPN, de routage, etc… uniquement de rsync. Nous verrons aussi comment profiter des possibilités de versionning offertes par rsync.

Pourquoi ces deux approches ?

Simplement parce qu’en fonction du choix que vous ferez, vous pourrez ou non profiter de certaines fonctionnalités de rsync, comme :

  • La synchro en mode bloc, qui vous permet de ne transférer que la partie modifiée d’un fichier déjà présent. Sympa lorsque vous sauvegardez des fichiers de plusieurs centaines de mégas qui font l’objet de fréquentes modifications d’à peine quelques kilos.
  • La compression des données durant leur transfert. Sympa également pour des fichiers de base de données par exemple. Oubliez les films ou les mp3 par contre, ces données sont déjà compressées et ne le seront pas plus.

Donc hormis le cas où vous ne pouvez pas rajouter de machine sur le site B, vous auriez tort de vous priver de ces deux superbes fonctionnalités.

Première approche : Linux + Windows

Une fois votre CentOS installée, vérifiez qu’elle communique correctement avec votre serveur Windows. Si ce n’est pas le cas inutile d’aller plus loin, réglez d’abord ce problème ;-) Assurez-vous également qu’elle puisse accéder à Internet, vous en aurez besoin pour vous servir du gestionnaire de paquets.

Installer rsync

Première chose à faire, installer rsync. Voici comment faire à l’aide du gestionnaire de paquets yum :

yum -y install rsync

Construire l’arborescence de la solution

Voici l’arborescence que je vous propose :

/opt/synchro                                               Répertoire de base de la solution
/opt/synchro/current/                                      Répertoire accueillant vos différentes synchro
/opt/synchro/current/nom_de_la_synchro1                    Ce répertoire sera crée automatiquement à la première synchro
/opt/synchro/current/nom_de_la_synchro2                    Ce répertoire sera crée automatiquement à la première synchro
/opt/synchro/logs                                          Répertoire accueillant vos logs
/opt/synchro/scripts                                       Répertoire accueillant vos différents scripts de synchro
/opt/synchro/versions                                      Répertoire accueillant les fichiers modifiés au fil des synchro
/opt/synchro/versions/nom_de_la_synchro1/AAAA-MM-JJ-HHMMSS Ce répertoire sera crée automatiquement
/opt/synchro/versions/nom_de_la_synchro2/AAAA-MM-JJ-HHMMSS Ce répertoire sera crée automatiquement

Pour la crée c’est facile :

cd /opt
mkdir synchro
cd synchro
mkdir current logs scripts versions

Le script de synchro

Il va falloir mettre en place des scripts pour la synchro. En effet, rsync seul ne sait pas le faire, il n’est que l’outils de base. Je vous demanderai d’être indulgent quant à la rédaction du code, je développe plus depuis longtemps ;-) Je vais vous le présenter par section.

La déclaration des variables

task_name="nom_de_la_tache"                                      #Nom de la tache
                                                                 #de synchro (arbitraire)
remote_mount_point="/mnt/synchro-"$task_name"/"                  #Chemin où sera monté
                                                                 #le partage (automatique)

remote_peer="adresse_de_la_cible"                                #Adresse IP ou nom DNS 
                                                                 #du serveur Windows

remote_share_name="nom_du_partage_windows"                       #Nom du partage Windows

remote_share="//"$remote_peer"/"$remote_share_name               #URL du partage Windows

remote_user="compte_pour_accéder_au_partage"                     #Compte Windows pour
                                                                 #accéder au partage
remote_password="mot_de_passe_du_compte"                         #Mot de passe du compte Windows

local_current_dir="/opt/synchro/current/"$task_name              #Chemin local où stocker
                                                                 #la synchro (automatique)

local_versions_dir="/opt/synchro/versions/"$task_name            #Chemin local où stocker les
                                                                 #versions de synchro (automatique)

pid=$$                                                           #PID du process (automatique)

pid_file="/var/run/"$task_name".pid"                             #Fichier où l'on va
                                                                 #stocker le PID (automatique)

log_file="/opt/synchro/logs/"$task_name                          #Fichier de log du
                                                                 #script (automatique)

xfer_log_file="/opt/synchro/logs/"$task_name"_"`date +%F-%H%M%S` #Fichier de log de
                                                                 #rsync (automatique)

delta_copy=1                                                     #Utilisation du
                                                                 #mode block (0=non 1=oui)

compress=1                                                       #Compression durant
                                                                 #les transferts (0=non 1=oui)

bw_limit=1                                                       #Limiter l'utilisation de
                                                                 #la bande passante (0=non 1=oui)

bw_limit_rate=500                                                #Limite d'utilisation de
                                                                 #la bande passante en kbps
if [ $delta_copy -eq 1 ]
then
        delta_opts="--no-whole-file"
else
        delta_opts="--whole-file"
fi
if [ $compress -eq 1 ]
then
        compress_opts="--compress"
else
        compress_opts="--no-compress"
fi
if [ $bw_limit -eq 1 ]
then
        bw_limit_opts="--bwlimit="$bw_limit_rate
else
        bw_limit_opts=""
fi

La partie synchro

# On vérifie qu'une synchro n'est pas déjà en cours
if [ -e $pid_file ]
then
        echo `date +%F-%T`" # "$task_name" already running ! (pid="$pid")" >> $log_file
        exit 0
else
        echo $pid > $pid_file
        echo `date +%F-%T`" # Task "$task_name" started with pid "$pid >> $log_file
fi
#On écrit la liste des paramètres de synchro dans le fichier de log pour en garder une trace
echo "Parameters list" >> $log_file
echo "Task name "$task_name >> $log_file
echo "Remote share mount point "$remote_mount_point >> $log_file
echo "Remote peer "$remote_peer >> $log_file
echo "Remote share "$remote_share >> $log_file
echo "Remote user "$remote_user >> $log_file
echo "Local sync directory "$local_current_dir >> $log_file
echo "Local versionning directory "$local_versions_dir >> $log_file
echo "Block mode sync "$delta_copy >> $log_file
echo "Compress transfer "$compress >> $log_file
echo "Bandwidth limiting "$bw_limit >> $log_file
if [ $bw_limit -eq 1 ]
then
        echo "Bandwidth limit rate "$bw_limit_rate >> $log_file
fi
echo "Transfer logfile "$xfer_log_file >> $log_file
# On crée le point de montage, puis on monte le partage
/bin/mkdir $remote_mount_point
/bin/mount -t cifs $remote_share $remote_mount_point -o user=$remote_user,password=$remote_password,ro
mount_error_code=$?
# On vérifie que tout s'est déroulé correctement puis on lance la synchro
if [ $mount_error_code -eq 0 ]
then
        /usr/bin/rsync --archive \
        --stats \
        --delete \
        --delete-before \
        --backup \
        --backup-dir=$local_versions_dir/`date +%F-%H%M%S`/ \
        --log-file-format="%f %b %l %o %p %t %i" \
        --log-file=$xfer_log_file $delta_opts \
        --partial $compress_opts \
        --ipv4 \
        $bw_limit_opts \
        $remote_mount_point \
        $local_current_dir
        rsync_error_code=$?
else
        # Ca a foiré ? On le dit et on essaye de donner une piste pour le debug
        echo "# Transfer FAILED !!!" >> $log_file
        echo "# Mount error code "$mount_error_code" !!!" >> $log_file
        echo "# Task aborted !!!" >> $log_file
fi
# On vérifie que la synchro s'est bien passée
if [ $rsync_error_code -ne 0 ]
then
        # Ca a foiré ? On le dit et on essaye de donner une piste pour le debug
        echo "# Rsync ERROR - Please check transfer log file !!!" >> $log_file
        echo "# Rsync error code "$rsync_error_code" !!!" >> $log_file
fi
# C'est fini, on démonte le partage et on nettoie dérrière soi
/bin/umount $remote_mount_point
/bin/rmdir $remote_mount_point
/bin/rm $pid_file
echo "# Task "$task_name" finished at "`date +%F-%T` >> $log_file

Schéma

Le fonctionnement en image :

Schema 1Seconde approche : Linux + Linux + Windows

Une fois vos deux CentOS installées, vérifiez que celle du site A communique bien avec le serveur de fichier Windows, et que celle du site B communique bien avec celle du site A. Là encore si ce n’est pas le cas inutile d’aller plus loin, réglez d’abord ce problème ;-) Assurez-vous également qu’elles puissent accéder à Internet, vous en aurez besoin pour vous servir du gestionnaire de paquets.

Installer rsync, le client ssh et xinetd

Première chose à faire, installer rsync sur les deux serveurs. Voici comment faire à l’aide du gestionnaire de paquets yum :

yum -y install rsync openssh-client xinetd

Construire l’arborescence de la solution sur le serveur du site B

Voici l’arborescence que je vous propose :

/opt/synchro                                               Répertoire de base de la solution
/opt/synchro/current/                                      Répertoire accueillant vos différentes synchro
/opt/synchro/current/nom_de_la_synchro1                    Ce répertoire sera crée automatiquement à la première synchro
/opt/synchro/current/nom_de_la_synchro2                    Ce répertoire sera crée automatiquement à la première synchro
/opt/synchro/logs                                          Répertoire accueillant vos logs
/opt/synchro/scripts                                       Répertoire accueillant vos différents scripts de synchro
/opt/synchro/versions                                      Répertoire accueillant les fichiers modifiés au fil des synchro
/opt/synchro/versions/nom_de_la_synchro1/AAAA-MM-JJ-HHMMSS Ce répertoire sera crée automatiquement
/opt/synchro/versions/nom_de_la_synchro2/AAAA-MM-JJ-HHMMSS Ce répertoire sera crée automatiquement

Pour la crée c’est facile :

cd /opt
mkdir synchro
cd synchro
mkdir current logs scripts versions

La configuration des démons rsyncd et xinetd (Serveur du site A)

Dans cette approche nous allons avoir besoin du démon rsyncd, c’est entre autre grâce à lui qui nous allons pouvoir réellement faire une synchro en mode bloc, et également profiter de la compression durant les transferts. Voici la marche à suivre :

  • Activez le démon xinetd
chkconfig --add xinetd
  • Éditez le fichier de configuration de rsync pour xinetd (/etc/xinetd.d/rsync) pour qu’il ressemble à ceci :
service rsync
{
disable = no
 flags = IPv6
 socket_type = stream
 wait = no
 user = root
 server = /usr/bin/rsync
 server_args = --daemon
 log_on_failure += USERID
}
  • Editez le fichier de configuration du démon rsyncd (/etc/rsyncd.conf) comme ceci :
pid file=/var/run/rsyncd.pid
syslog facility=daemon
[nom_de_la_tache_utilisée_dans_le_script]
comment = synchro1
path = /mnt/synchro-nom_de_la_tache_utilisée_dans_le_script
use chroot = yes
lock file = /var/lock/rsyncd
read only = yes
list = yes
uid = root
gid = root
auth users = utilisateur_du_fichier_rsyncd.secrets
secrets file = /etc/rsyncd.secrets
strict modes = false
hosts allow = ip_du_serveur_du_site_B
transfer logging = yes
log format = %t: host %h (%a) %o %f (%l bytes). Total %b bytes.
timeout = 120
dont compress = *.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz *.avi *.mp3 *.mp4 *.wmv *.mov
  • Editez le fichier de compte de rsyncd (/etc/rsyncd.secrets), qui n’existe peut-être pas, comme ceci :
nom_d_utilisateur:mot_de_passe
  • Attribuez les bons droits aux fichiers de configuration :
chown root.root /etc/rsyncd.*
chmod 600 /etc/rsyncd.*
  • Redémarrez le démon xinetd :
service xinetd restart

Générer les clefs SSH sur le serveur du site B et les copier sur le serveur du site A

Tout d’abord vous devez générer une paire de clefs ssh sur le serveur du site B :

ssh-keygen -v -f /root/.ssh/id_rsa

Puis vous devez les copier sur le serveur du site A :

ssh-copy-id -i /root/.ssh/id_rsa.pub root@ip_du_serveur_du_site_A

Le script de synchro sur le serveur du site B

Comme précédemment il va nous falloir un script pour effectuer la synchro à l’aide de rsync. Cette fois encore je vous demanderai d’être indulgent sur l’esthétique du code ;-)

La déclaration des variables

Je ne redétaillerai pas tout une seconde fois les noms parlent d’eux-même. Au pire postez vos questions ;-)

task_name="nom_de_la_tache"
remote_mount_point="/mnt/synchro-"$task_name"/"
remote_cifs_peer="adresse_du_serveur_windows"
remote_rsync_peer="adress_du_serveur_du_site_A"
remote_share_name="nom_du_partage_windows"
remote_share="//"$remote_cifs_peer"/"$remote_share_name
remote_rsync_module=$task_name
remote_rsync_user="utilisateur_du_fichier_rsyncd.secrets"
remote_rsync_password="mot_de_passe_du_fichier_rsyncd.secrets"
export RSYNC_PASSWORD=$remote_rsync_password
remote_cifs_user="compte_pour_accéder_au_partage_windows"
remote_cifs_password="mot_de_passe_du_compte"
remote_ssh_user="root"
remote_ssh_ident="/root/.ssh/id_rsa"
local_current_dir="/opt/synchro/current/"$task_name
local_versions_dir="/opt/synchro/versions/"$task_name
pid=$$
pid_file="/var/run/"$task_name".pid"
log_file="/opt/synchro/logs/"$task_name
xfer_log_file="/opt/synchro/logs/"$task_name"_"`date +%F-%H%M%S`
delta_copy=1
compress=1
bw_limit=1
bw_limit_rate=500
if [ $delta_copy -eq 1 ]
then
 delta_opts="--no-whole-file"
else
 delta_opts="--whole-file"
fi
if [ $compress -eq 1 ]
then
 compress_opts="--compress"
else
 compress_opts="--no-compress"
fi
if [ $bw_limit -eq 1 ]
then
 bw_limit_opts="--bwlimit="$bw_limit_rate
else
 bw_limit_opts=""
fi

La déclaration des fonctions

Cette fois-ci j’ai découpé le script en fonctions, de cette manière il sera plus facile de le faire évoluer.

function _log_to_file () {
 echo $* >> $log_file
 echo $*
}
function _log_parameters {
 _log_to_file "Parameters list"
 _log_to_file "Task name "$task_name
 _log_to_file "Remote share mount point "$remote_mount_point
 _log_to_file "Remote cifs peer "$remote_cifs_peer
 _log_to_file "Remote rsync peer "$remote_rsync_peer
 _log_to_file "Remote cifs share "$remote_share
 _log_to_file "Remote cifs user "$remote_cifs_user
 _log_to_file "Remote ssh user "$remote_ssh_user
 _log_to_file "Remote ssh key file "$remote_ssh_ident
 _log_to_file "Remote rsync user "$remote_rsync_user
 _log_to_file "Remote rsync module "$remote_rsync_module
 _log_to_file "Local sync directory "$local_current_dir
 _log_to_file "Local versionning directory "$local_versions_dir
 _log_to_file "Block mode sync "$delta_copy
 _log_to_file "Compress transfer "$compress
 _log_to_file "Bandwidth limiting "$bw_limit
 if [ $bw_limit -eq 1 ]
 then
 _log_to_file "Bandwidth limit rate "$bw_limit_rate
 fi
 _log_to_file "Transfer logfile "$xfer_log_file
}
function _check_instance {
 if [ -e $pid_file ]
 then
 _log_to_file `date +%F-%T`" # "$task_name" already running !!! (pid="$pid")"
 exit 1
 else
 echo $pid > $pid_file
 _log_to_file `date +%F-%T`" # Task "$task_name" started with pid "$pid
 fi
 return 0
}
function _init_remote_env {
 /usr/bin/ssh -2 -4 -i $remote_ssh_ident $remote_ssh_user@$remote_rsync_peer \
 "/bin/mkdir "$remote_mount_point
 local error_code=$?
 if [ $error_code -ne 0 ]
 then
 _log_to_file
 _log_to_file "# Remote environment initialization FAILED !!!"
 _log_to_file "# Directory creation error code "$error_code" !!!"
 _log_to_file "# Task aborted !!!"
 _delete_pid_file
 exit 1
 fi
 /usr/bin/ssh -2 -4 -i $remote_ssh_ident $remote_ssh_user@$remote_rsync_peer \
 "/bin/mount -t cifs "$remote_share $remote_mount_point" \
 -o user="$remote_cifs_user",password="$remote_cifs_password",ro"
 local error_code=$?
 if [ $error_code -ne 0 ]
 then
 _log_to_file
 _log_to_file "# Remote environment initialization FAILED !!!"
 _log_to_file "# Mount error code "$error_code" !!!"
 _log_to_file "# Task aborted !!!"
 /usr/bin/ssh -2 -4 -i $remote_ssh_ident $remote_ssh_user@$remote_rsync_peer \
 "/bin/rmdir "$remote_mount_point
 _delete_pid_file
 exit 1
 fi
 return 0
}
function _start_sync {
 local result=0
 /usr/bin/rsync --archive \
 --stats \
 --delete-before \
 --backup \
 --backup-dir=$local_versions_dir/`date +%F-%H%M%S`/ \
 --log-file-format="%f %b %l %o %p %t %i" \
 --log-file=$xfer_log_file $delta_opts \
 --partial \
 $compress_opts \
 --ipv4 \
 $bw_limit_opts \
 $remote_rsync_user@$remote_rsync_peer::$remote_rsync_module $local_current_dir
 local error_code=$?
 if [ $error_code -ne 0 ]
 then
 _log_to_file
 _log_to_file "# Rsync ERROR - Please check transfer log file !!!"
 _log_to_file "# Rsync error code "$error_code" !!!"
 local result=1
 fi
 return $result
}
function _rollback_remote_env {
 local result=0
 /usr/bin/ssh -2 -4 -i $remote_ssh_ident $remote_ssh_user@$remote_rsync_peer \
 "/bin/umount "$remote_mount_point
 local error_code=$?
 if [ $error_code -ne 0 ]
 then
 _log_to_file "# Remote environment rollback FAILED !!!"
 _log_to_file "# Unmount error code "$error_code" !!!"
 local result=1
 fi
 /usr/bin/ssh -2 -4 -i $remote_ssh_ident $remote_ssh_user@$remote_rsync_peer \
 "/bin/rmdir "$remote_mount_point
 local error_code=$?
 if [ $error_code -ne 0 ]
 then
 _log_to_file "# Remote environment rollback FAILED !!!"
 _log_to_file "# Directory destruction error code "$error_code" !!!"
 local result=1
 fi
 return $result
}
function _delete_pid_file {
 /bin/rm $pid_file
}

Le corps du script

_check_instance
_log_parameters
_init_remote_env
_start_sync
_rollback_remote_env
_delete_pid_file
_log_to_file "###### Task "$task_name" finished at "`date +%F-%T`

Schéma

Le fonctionnement en image : Schéma 2

1 commentaire

1 ping

  1. Cixy35

    Merci bien pour ce script, ca marche parfaitement pour ce que j’ai à faire, c’est à dire dans mon cas le 1 ! J’essaierai peut etre le 2 un des 4.
    Merci encore

  1. Sauvegarde | Pearltrees

    […] Sauvegarde distante avec rsync entre windows et linux » Tutos Pour Les Nuls. Dans cet article je vais tenter de vous expliquer comment mettre en place une sauvegarde distante entre un serveur de fichiers sous Windows 2008 R2 et un serveur sous linux. […]

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *


+ 6 = dix

Vous pouvez utiliser les balises HTML suivantes : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>