lunes, 18 de noviembre de 2013

Backup MySQL a través de tunel SSH

Voy a describir acá los pasos necesarios para conseguir lo siguiente: Hacer un script que se conecte a un servidor, desde ese servidor conectarse a otro donde está hosteado un servicio de MySQL y poder hacer un backup de una base de datos.

Esto fue algo que tuve que hacer en el laburo. Esta sería la lista de computadoras involucradas:


  • My compu (localhost)
  • Web server (webserver)
  • MySQL server (mysqlserver)
El servidor mysqlserver solo es visible desde webserver. Desde localhost tengo acceso a través de SSH a webserver.

Necesitaba un script para que traerme un dump de la base de datos hacia mi localhost. Mi primer idea fue la de ejecutar el backup remotamente y después traermelo con scp, pero, al ejecutar el primer paso me topé con un error grave:

$ ssh user@webserver "mysqldump --host mysqlserver --user dbuser -ppassword dbname > /tmp/dump.sql"

El problema era el siguiente: En webserver había una versión vieja del cliente de MySQL (5.1) y en mysqlserver estaba la última versión estable 5.6, lo que impedía ejecutar el comando:

mysqldump: Couldn't execute 'SET OPTION SQL_QUOTE_SHOW_CREATE=1': You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'OPTION SQL_QUOTE_SHOW_CREATE=1' at line 1 (1064)

Al encontrarme con esto tenía dos opciones: O instalaba una versión nueva del cliente en webserver o hacía un túnel. Elegí el túnel :)

$ ssh -L 8181:mysqlserver:3306 user@webserver

Al ejecutar esto, podemos ejecutar mysqldump localmente de la siguiente forma:

$ mysqldump --user dbuser -ppassword --host 127.0.0.1 --port 8181 dbname > dump.sql



El único problema es que el túnel no te devuelve el control, por lo que el comando de backup hay que ejecutarlo en una ventana diferente, y eso dificulta el hecho de que esté todo en un simple script.

Agregando algunos parámetros, el túnel queda corriendo de fondo:

$ ssh -Nn -L 8181:mysqlserver:3306 user@webserver & PID=$!

Al ejecutarlo de esa manera, el túnel queda corriendo de fondo y el ID del proceso queda guardado en la variable $PID, por lo que al terminar el dump, se puede matar el proceso y cortar la conexión:

$ kill $PID

El script recibe como parámetro el archivo donde se quiere guardar el dump, así queda de la siguiente forma:

#!/bin/bash

FILE=$1
if [ -z "$FILE" ]; then
    echo "Dump file location not specified. Using default."
    FILE=$HOME/dump.sql
fi

echo "Creating SSH tunnel"
ssh -Nn -L 8181:mysqlserver:3306 user@webserver & PID=$!

echo "Executing backup"
mysqldump --user dbuser -ppassword --host 127.0.0.1 --port 8181 dbname > $FILE


echo "Dump saved to $FILE"
kill $PID