rbackup (rsync backup)

21 enero 2009 Publicado por cLimbo
Nombre: rbackup (rsync backup)
Autor: Patricio Silva (Pato Silva)
Lenguaje: bash
Licencia: GPL
Dependencias: rsync, openssh-server, mysql
Propósito: Realizar un backup incremental de un servidor web en un host remoto y genera un archivo de log de sucesos, también funciona para local en el caso en que se hiciera el backup en otro disco del mismo equipo (mala idea).

#!/bin/sh

# Realiza un respaldo de las bases de datos
# y los archivos de las paginas web ya sea en local o remoto
# Para backup remoto se asumira que localhost es el origen de los datos
#
#
# Variables de rutas, ubicacion de las bases de datos, paginas
# y comandos necesarios para la ejecucion

# Nombre o direccion IP del host remoto, en blanco si el backup se hara en local
HOST_REMOTO=servbackup.dominio.com

# Nombre de usuario remoto, en blanco si el backup se ará en local
USUARIO_REMOTO=rbackup

# Puerto remoto a la escucha de ssh
PUERTO_REMOTO=222

# Nombre de los directorios que contienen las paginas web
# Cada directoro se actualizará mediante una nueva conexion rsync
PAGINAS="/var/www/pagina1 /var/www/pagina2 /var/www/paginax"

# Bases de datos de las que se realizara el backup
# Si se omite se ejecutará mysqldump con la opcion --all-databases
MYSQL_DATABASES="una_base_de_datos otra_base_de_datos y_otra_mas"

# Otros archivos a sincronizar
OTROS="/etc/apache2 /var/log/rbackup"

# Directorio temporal al cual se realizara el dump de la base de datos para luego ser transferida
TMP=/tmp

# Directorio donde se almacenaran los registros de log (en local)
DIR_LOG=/var/log/rbackup

# Nombre del archivo de log
ARCH_LOG=rbackup.log

# Nombre del archivo de debug, el archivo solo se conservará si
# Se lo indica en la variable CONSERVAR_DEBUG o si ocurrieran errores
ARCH_DEBUG=`date +rbackup-%d-%m-%Y-%H:%M.debug`

# Coservar el archivo de debug, cero por NO, cualquier otro valor por SI
CONSERVAR_DEBUG=1

# Directorio destino del backup
RUTA_DESTINO=/var/rbackup

# Nombre de usuario valido y con suficientes privilegios para realizar dump de las bases de datos.
# Puede omitirse si no se requiere de ninguno
MYSQL_USER=usuario

# Password del usuario, puede omitirse
MYSQL_PASSWORD=clave

# Otras opciones a agregar al guión de ejecucion de mysqldump
# --verbose y --force son buena idea
# --default-character-set=latin1 es recomendable para
# base de datos mysql 4.0 o anteriores
OPCIONES_MYSQLDUMP='--default-character-set=latin1 --verbose --force'

################################################################################################################

# Agrega un registro al archivo de log
# Si se especifica la opcion -p tambien lo muestra por pantalla
log(){
echo `date "+%d %b %r"`" "$1 >> $ARCH_LOG
test +$2 == '+-p' && echo `date "+%d %b %r"`" "$1
}

# Coloca ruta absoluta a los archivos de log
ARCH_LOG=${DIR_LOG}/$ARCH_LOG
ARCH_DEBUG=${DIR_LOG}/$ARCH_DEBUG

# Comprueba que existe el directorio de log y el archivo de log, lo crea si no existiera
# El script termina con error si no se pudiera lograr esto con exito
! test -d $DIR_LOG && mkdir --parent $DIR_LOG
! test -d $DIR_LOG && echo "Error fatal: El directorio de destino de los archivos de log y debug no existe y no puede crearse" && exit 1

! test -e $ARCH_LOG && echo "Creando archivo de log" && touch $ARCH_LOG
! test -w $ARCH_LOG && echo "Error fatal: El archivo de log $ARCH_LOG no existe y no puede crearse y/o modificarse" && exit 1

! test -e $ARCH_DEBUG && touch $ARCH_DEBUG
! test -w $ARCH_DEBUG && log "Error fatal: El archivo de debug $ARCH_DEBUG no pudo crearse y/o modificarse" -p && exit 1

log 'Iniciando backup'
logger -t $0 'Iniciando backup'
echo -- DEBUG FILE -- [ `date "+%d %b %r"` ] >> $ARCH_DEBUG

# Da el formato adecuado a las variables referentes a las bases de datos
# Le asigna a la variable MYSQL_USER el formato --user=nombre pero deja la cadena vacia si no se ha especificado usuario.
test -z $MYSQL_USER || MYSQL_USER="--user=$MYSQL_USER"

# Le asigna a la variable MYSQL_PASSWORD el formato "--password=password" pero deja la cadena vacia si no se ha especificado password.
test -z $MYSQL_PASSWORD || MYSQL_PASSWORD="--password=$MYSQL_PASSWORD"

# Si se han especificado bases de datos se le da el formato "--databases lista de las bases de datos"
# Se le asigna el valor "-all-databases" en caso contrario
test -z "$MYSQL_DATABASES" || MYSQL_DATABASES="--databases $MYSQL_DATABASES"
test -z "$MYSQL_DATABASES" && MYSQL_DATABASES="--all-databases"

# Da el formato adecuado al destino segun sea local o remoto
! test -z $USUARIO_REMOTO && ! test -z $HOST_REMOTO && RUTA_DESTINO=${USUARIO_REMOTO}@${HOST_REMOTO}:${RUTA_DESTINO}

# Realiza el respaldo de la base de datos en local $TMP
log "Creando archivo de dump de las bases de datos en \"${TMP}/databases.sql\""
mysqldump $OPCIONES_MYSQLDUMP $MYSQL_USER $MYSQL_PASSWORD $MYSQL_DATABASES --result-file ${TMP}/databases.sql 2> $ARCH_DEBUG

# Si el proceso mysqldump no finalizo correctamente se registra una alerta en el archivo de log y se conserva
# el archivo debug, de lo contrario el archivo debug es eliminado y la base de datos se transfiere al host remoto
ERROR=$?
if [ $ERROR -ne 0 ];
then
log "ATENCION: El proceso mysqldump ha finalizado con código de salida $ERROR, para evitar reemplazar el archivo de backup de la base de datos anterior por un archivo corrupto se ha omitido la sincronizacion. Vea el archivo $ARCH_DEBUG para obtener información detallada del error."
else
log "Inicio del backup de la base de datos; destino: \"${RUTA_DESTINO}/database/databases.sql\""
echo `date "+%d %b %r"`" -- MARK --" >> $ARCH_DEBUG
rsync -e "ssh -p $PUERTO_REMOTO" -avz ${TMP}/databases.sql $RUTA_DESTINO/database/ 2>&1 >> $ARCH_DEBUG
ERROR=$?
if [ $ERROR -ne 0 ];
then
log "ATENCION: La transferencia del archivo de dump de la base de datos ha finalizado con código de salida $ERROR. Vea el archivo $ARCH_DEBUG para obtener información detallada del error."
test +$CONSERVAR_DEBUG == '+0' && rm $ARCH_DEBUG
fi
fi

log "Inicio del backup de archivos, destino: \"${RUTA_DESTINO}/paginas/\""

# Realiza el respaldo de los archivos de paginas
# Si ocurre algun error se loguea
for ARCHIVOS in $PAGINAS
do
log "Actualizando \"${ARCHIVOS}\" en \"${RUTA_DESTINO}/paginas/\""
RS_OUTPUT=`rsync -e "ssh -p $PUERTO_REMOTO" -avz --delete $ARCHIVOS ${RUTA_DESTINO}/paginas/ 2>&1`
test $? -ne 0 && ERROR=1 && log "ATENCION: $RS_OUTPUT" -p
echo `date "+%d %b %r"`" -- MARK --" >> $ARCH_DEBUG
echo ${ARCHIVOS}: $RS_OUTPUT >> $ARCH_DEBUG
done

# Realiza el respaldo de "otros" archivos
# Si ocurre algun error se loguea
for ARCHIVOS in $OTROS
do
log "Actualizando \"${ARCHIVOS}\" en \"${RUTA_DESTINO}/OTROS/\""
RS_OUTPUT=`rsync -e "ssh -p $PUERTO_REMOTO" -avz --delete $ARCHIVOS ${RUTA_DESTINO}/OTROS/ 2>&1`
test $? -ne 0 && ERROR=1 && log "ATENCION: $RS_OUTPUT" -p
echo `date "+%d %b %r"`" -- MARK --" >> $ARCH_DEBUG
echo ${ARCHIVOS}: $RS_OUTPUT >> $ARCH_DEBUG
done

if [ $ERROR -eq 0 ];
then
if [ +$CONSERVAR_DEBUG == '+0' ];
then
rm $ARCH_DEBUG
else
log "El archivo de debug es \"${ARCH_DEBUG}\""
fi
fi

log "Backup finalizado"
logger -t $0 'Backup finalizado'
exit 0

Ejemplo de uso:

./rbackup
Para el funcionamiento automático se asume que puede establecerse una conexión ssh entre ambos host mediante certificados sin frase.

La idea es que la ejecución se haga desde cron, el código esta lo suficientemente explicado para entenderse su funcionamiento.

Tiene muy buena tolerancia a fallos, lo utilizo actualmente y nunca tube problemas, rsync funciona realmente muy rápido. Personalmente lo ejecuto desde cron dos veces al dia, con una base de datos de casi un giga y unos 3 gigas en archivos la sincronización dura menos de dos minutos.