Sincronizar directorios con inotify
Contents
Sincronizar directorios con inotify
Sincronizar directorios entre máquinas con rsync es sencillo, pero puede que requiramos que esto se realice bajo demanda, que cuando se modifique algo en un máquina se vea reflejado inmediatamente en las demás. Con inotify podemos realizar ésto de manera sencilla.
Requerimientos
- Linux kernel 2.6.13 (June 18, 2005) o superior
- inotify-tools
Explicación rápida
La idea es muy sencilla. Monitorizamos un directorio con inotifywait, y cuando se produce alguna acción en el mismo, realizamos un rsync a la máquina remota. Utilizamos rsync en vez de scp o similar para que si montamos esto en varias máquinas que sincronicen entre ellas no se queden bucladas copiando el mismo fichero de manera infinita.
Un ejemplo sencillo, donde miramos el si creamos, modificamos o borramos ficheros en /srv/sync, y lo sincronizamos con el mismo directorio de la máquina blas:
while OUTPUT=`inotifywait --format '%f' -e create -e modify -e delete /srv/sync`;do echo "El fichero ganador es ${OUTPUT}" rsync -a --delete /srv/sync blas:/srv/sync done
Ejemplo práctico
Tenemos dos máquinas (epi y blas) en las que queremos sincronizar el directorio /srv/sync, utilizando para ello el usuario jim.
Generación y copia de las claves ssh
Para realizar la sincronización se requiere la generación de una pareja de claves (pública y privada) para que el usuario jim pueda sincronizar datos entre las dos máquinas. Generaremos las claves de mánera idéntica en las dos máquinas, y no las protegeremos con contraseña:
jim@epi:~$ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/jim/.ssh/id_rsa): Created directory '/home/jim/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/jim/.ssh/id_rsa. Your public key has been saved in /home/jim/.ssh/id_rsa.pub. The key fingerprint is: 59:04:2c:a6:95:df:cb:b1:f3:34:e4:b9:76:2f:2e:b2 jim@epi The key's randomart image is: +--[ RSA 2048]----+ | o... | | = .. | | + o .. | | . .oo . | | S. * . | | = = | | + o | | . = o | | E+ +.o.| +-----------------+
Con ésto conseguimos dos claves dentro del directorio ~jim/.ssh/:
- id_rsa: La clave privada que utiliza ssh. No debe moverse de donde está.
- id_rsa.pub: La clave pública que utiliza ssh. Hay que colocarla en el fichero ~/.ssh/authorized_keys de la máquina y usuario donde queramos conectarnos.
En nuestro caso, copiaremos de epi el fichero ~/.ssh/id_rsa.pub a blas en ~/.ssh/authorized_keys y viceversa :
jim@epi:~$ scp ~/.ssh/id_rsa.pub blas@~/.ssh/authorized_keys
jim@blas:~$ scp ~/.ssh/id_rsa.pub epi@~/.ssh/authorized_keys
También se puede realizar ésta acción utilizando ssh-copy-id
jim@epi:~$ ssh-copy-id blas
jim@blas:~$ ssh-copy-id epi
El script que controla la sincronización
Un ejemplo de script para vigilar y sincronizar los cambios. Utiliza logger para generar algo de log vía syslog. La idea es que el script sea el mismo en todos los nodos donde lo necesitemos.
Un buen sitio para ubicarlo es /usr/local/bin/notity-sync:
#!/bin/sh # Sincroniza un directorio entre dos máquinas utilizando 'inotifywait'. # 'inotifywait' es parte del paquete "inotify-tools". VER='1' USER='jim' MACHINES='epi blas' # Las máquinas afectadas en el proceso. ORIGEN=`hostname -s` DIR_ORIGEN='/srv/sync' DIR_DESTINO='/srv/sync' DESTINOS=`echo ${MACHINES}|sed "s/$ORIGEN//"` # Las máquinas a sincronizar ## Log PRIORITY='local0.notice' LOGTAG='INOTIFY' Main() { while OUTPUT=`inotifywait --format '%f %e' -e create -e modify -e delete ${DIR_ORIGEN}/`;do for DESTINO in ${DESTINOS};do # Log de inotify echo ${DIR_ORIGEN}/${OUTPUT} |logger -p ${PRIORITY} -t ${LOGTAG} su - ${USER} -c "rsync -a --delete ${DIR_ORIGEN}/ ${USER}@${DESTINO}:${DIR_DESTINO}/" # Log de sincronización ERROR=$? if [ ${ERROR} -eq 0 ];then echo "${USER}@${DESTINO}:${DIR_DESTINO} SYNC" |logger -p ${PRIORITY} -t ${LOGTAG} else echo "${USER}@${DESTINO}:${DIR_DESTINO} ERROR ${ERROR}" |logger -p ${PRIORITY} -t ${LOGTAG} fi # / Log de sincronización done done } case ${1} in --daemon) Main > /dev/null 2>&1 & ;; *) Main ;; esac
script de arranque y parada
Un ejemplo del script de arranque y parada realizado para Red Hat. Su sitio es /etc/init.d/notity-sync.
#!/bin/bash # # notify-sync This starts and stops notify-sync. # # description: Sincroniza directorios entre máquinas a base de \ # 'rsync' e 'inotify'. ### BEGIN INIT INFO # Provides: # Required-Start: $network # Required-Stop: # Should-Start: # Should-Stop: # Default-Start: 3 4 5 # Default-Stop: 0 1 2 6 # Short-Description: starts and stops notify-sync # Description: Sincroniza directorios entre máquinas a base de \ # 'rsync' e 'inotify'. ### END INIT INFO PATH=/sbin:/bin:/usr/bin:/usr/sbin # Source function library. . /etc/init.d/functions prog=/usr/local/bin/notity-sync lockfile=/var/lock/subsys/`basename $prog` start() { [ "$EUID" != "0" ] && exit 4 # Start daemons. status $prog > /dev/null CODE=$? if [ $CODE = "0" ];then echo "$prog: funcionando" echo `status $prog` exit 0 fi echo -n $"Starting $prog: " daemon $prog --daemon RETVAL=$? echo [ $RETVAL -eq 0 ] && touch $lockfile return $RETVAL } stop() { [ "$EUID" != "0" ] && exit 4 echo -n $"Shutting down $prog: " killproc $prog -9 RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f $lockfile return $RETVAL } # See how we were called. case "$1" in start) start ;; stop) stop ;; status) status $prog ;; *) echo $"Usage: $0 {start|stop|status}" exit 2 esac
Habilitar y arrancar el proceso
Para que ésto funcione en todos los arranques hemos optado por introducirlo en un runlevel.
ln -s /etc/init.d/notity-sync /etc/rc3.d/S99notity-sync service notity-sync start
Referencias
https://github.com/rvoicilas/inotify-tools/wiki/