607 - Bash, Docker, Borg y jq

607 - Bash, Docker, Borg y jq

Como crear scripts en #bash en #docker para hacer copias de seguridad en #linux de bases de datos #mariadb y #wordpress

1:25
-3:15

Después de contarte, en el último episodio, como había implementado las copias de seguridad de las distintas no me quedé nada satisfecho. Pero fue el comentario de Germán en el grupo de atareao con Linux, el que sin lugar a dudas, dio la puntilla final. Ya en el episodio del podcast, te dije que no era la mejor solución, y que además la había dejado incompleta en el sentido de que las copias se quedaba en local, lo cual era un craso error. Así, que en estos últimos días me he dedicado a crear una imagen docker que se encargara de hacer todo el trabajo, tanto el backup de la base de datos como la copia de seguridad de los archivos. Y, para ello, he utilizado Borg, sobre el que te hablé en el episodio 173 que titulé Hice un rm -rf. Salvado por Borg, pero además he necesitado de otras herramientas como jq y un poquito de Bash, para completar todo el proceso. Así, en este episodio, quiero hablarte sobre esta combinación de herramientas y como he solucionado finalmente el asunto de las copias de seguridad.

Bash, Docker, Borg y jq

De nuevo Bash

En un momento pensé en implementar una aplicación en Rust para gestionar todo el proceso, pero en seguida caí en que realmente no era necesario, con Bash podía resolverlo muy fácilmente.

Si visitas el repositorio de atbackup en GitHub, verás que el script backup.sh es realmente sencillo. Simplemente se trata de recuperar la configuración y realizar un par de bucles while, uno para el volcado de las bases de datos y otro para realizar las copias de seguridad con Borg. Tan sencillo como eso.

jq y un archivo de configuración

Hasta el momento todo era mas o menos sencillo, y por tanto el archivo de configuración eran unas pocas líneas clave-valor. Sin embargo, cuando me puse con esta nueva versión, me di cuenta que la cosa se estaba complicando excesivamente. Era necesario darle una vuelta a como resolver una configuración mas compleja.

Fue justo, ese preciso momento en el que pensé en pasarle un archivo json y procesarlo con jq. Si no conoces jq, indicarte que se trata de una herramienta que te permite trabajar con este tipo de archivos. Tal y como lo define los propios desarrolladores de la aplicación, es un filtro que toma una entrada y produce una salida.

Siempre me ha gustado la configuración en archivos json, porque son muy claros y dejan poco espacio a la interpretación. Aunque te tengo que confesar que últimamente los tipo yaml también me atraen mucho.

La cuestión es que en este caso, son distintos aspectos los que quería resolver, como,

  • Tener distintos repositorios donde guardar las copias de seguridad, al menos uno local y otro remoto.
  • La posibilidad de incluir varios directorios.
  • Tener opción para excluir determinados tipos de archivos.
  • La configuración de las distintas bases de datos
  • La gestión de las copias de seguridad. Cuantas copias mantener.

Todo esto, en un archivo de configuración es bastante complejo, sin embargo, en un sencillo archivo json, es realmente sencillo. Por ejemplo, para hacer el volcado de las bases de datos lo puedo hacer de la siguiente forma,

cat "$CONFIG_FILE" | jq -r '.mariadb[] | .host + "|" + .port + "|" + .password' | while IFS="|" read -r MARIADB_HOST MARIADB_PORT MARIADB_PASSWORD
do
    echo "=== Backup Mariadb ${MARIADB_HOST} ==="
    mariadb-dump --all-databases \
                 --host=$MARIADB_HOST \
                 --port=$MARIADB_PORT \
                 --password=$MARIADB_PASSWORD > /backup/${MARIADB_HOST}_dump.sql
done

De la misma forma, recuperar una determinada configuración es igual de sencillo, por ejemplo,

WEEKLY=$(cat "$CONFIG_FILE" | jq -r '.prune.weekly')

run-parts

Otra de las cuestiones que me quedaban pendientes y que no resolví con la versión anterior eran las notificaciones, o mejor dicho, las acciones pre y post backup. Pero esto tiene fácil solución con run-parts.

run-parts es una herramienta que ejecuta todos los archivos con permisos de ejecución que se encuentren en un determinado directorio. Esto es ideal para mi siguiente objetivo, las notificaciones.

Como he contado en otras ocasiones, para mi es necesario, o mejor dicho, es imprescindible estar informado de cuando se realiza un backup, ya sea que este se realice correctamente o que falle por cualquier tipo de razón.

Así, con esta solución he implementado otro script que me envía un mensaje a matrix indicando si la copia se ha realizado o ha dado un error. Otro problema solucionado fácilmente con Bash,

function send_message(){
    MESSAGE="$@"
    TS=$(date +%s%3N)
    ENDPOINT="https://${MATRIX_HOST}/_matrix/client/v3/rooms/${MATRIX_ROOM}:${MATRIX_HOST}/send/m.room.message/${TS}"
    echo $ENDPOINT
    curl --request PUT \
         --url "$ENDPOINT" \
         --header "Authorization: Bearer ${MATRIX_TOKEN}" \
         --data "{\"msgtype\": \"m.text\", \"body\": \"${MESSAGE}\"}" \
         --max-time 10 \
         --retry 5
}

Borg

Como te decía en la introducción, sobre BorgBackup, o Borg, ya te hablé hace algunos cientos de episodios, pero si no lo conoces todavía, indicarte que se trata de un programa de copias de seguridad, con deduplicación, compresión y cifrado.

Tal y como indican los propios desarrolladores de la aplicación, el objetivo principal de Borg, es proporcionar una forma eficiente y segurar de realizar copias de seguridad. Sobre la deduplicación, indicar que es una técnica que facilita que solo se guarden los cambios.

Además Borg se encarga de limpiar los archivos obsoletos en base a la política de retención que hayas definido, que actualmente en mi caso es de 5 días, 2 semanas y dos meses.

crond

La última pieza de este rompecabezas es crond, que es la encargada de programar las ejecuciones. Realmente podía haber puesto directamente un sleep, sin embargo, esto de poder establecer claramente cuando queremos hacer nuestras copias de seguridad me parece mucho mas acertado. De esta manera se que todos los días a las 3 de la mañana se tiene que realizar esa copia de seguridad.

Copia local y remota

Actualmente he implementado dos copias, una local y otra remota. Para la remota, en otro VPS, he creado un usuario backupuser, en cuyo directorio se realizan las copias. D esta forma está aislado del resto.

ctop

Por último indicarte que esta solución apenas consume recursos cuando no está haciendo nada. Me refiero a que entre copia y copia de seguridad, realmente es como si no existiera.

Para ver el consumo de recursos he utilizado ctop. Se trata de una herramienta implementada en Golang, que te permite tener información puntual de todos los contenedores que tienes corriendo en tu máquina.

Así, En este caso, el consumo de memoria es de 20K. Algo completamente ridículo.

Pendientes

Me queda pendiente un justfile con comandos para trabajar con las copias de seguridad. Es decir, listar las copias, extraer algún archivo concreto o en su caso, borrar alguna copia. Sin embargo, esto es algo que realmente no me preocupa en exceso. Cuando lo necesite lo haré.

Conclusión

Ahora si que si. Como he indicado en la introducción, ya cuando terminé la solución anterior, no me quedé nada satisfecho, pero fue el comentario de Germán el que hizo decidirme a resolver de forma definitiva esto de las copias de seguridad.

Finalmente he adoptado una solución muy similar a la que tengo implementada en mi equipo personal y que lleva funcionando tantos años. En ocasiones me pregunto ¿Para que inventas Lorenzo?, pero la respuesta es sencilla, me gusta cacharrear.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *