Duply es una interfaz de línea de comandos que simplifica el uso de otro comando llamado duplicity, escrito en python, que usa librsync , y que sirve para realizar copias de seguridad incrementales y encriptadas en un repositorio externo. Entre las muchas opciones soportadas como almacenamiento podemos destacar algunas, como son un servidor ftp o servicios como azure, dropbox, mega, onedrive, o aws s3, siendo este último el que nos ocupa en esta ocasión.
¿Por qué es tan interesante AWS S3?
Cuando hablamos de AWS S3 hablamos de un servicio de almacenamiento de objetos, como pueden ser Azure Blob Storage , Google Cloud Storage o Spaces en Digital Ocean.
El object based storage llega para ofrecer mayor escalabilidad, a cambio de dejar de trabajar con datos estructurados e incluir mayores latencias que las opciones basadas en bloques o ficheros. Sus diferencias principales son:
- Se basa en una API http, lo que significa que puede integrarse fácilmente con otras aplicaciones, como es el caso de duplicity. Además es independiente del sistema operativo.
- Se desprende de las restricciones que supone un sistema de ficheros, como son la jerarquía de directorios y subdirectorios. Y esto se sustituye por un contenedores de objetos con un identificador único, unos metadatos asociados y el fichero propiamente dicho.
- Permite que cada objeto se encuentre almacenado en ubicaciones diferentes y no necesita conocerse por el cliente. Lo que permite reducir costes y permite una escalabilidad casi ilimitada.
- El propio sistema garantiza la redundancia de los datos, de modo que nosotros no tenemos montar un RAID ni nada parecido.
- Contratar un sistema de bloques implica pagar también el que espacio sin usar, mientras que con aws s3 únicamente pagaremos lo que usemos.
- Funciona muy bien con datos no estructurados. Por el contrario, montar un sistema de objetos como sistema de ficheros (como hace s3fs, goofys o riofs entre otros) tiene un gran impacto negativo en el rendimiento.
- En un sistema de ficheros podemos modificar una porción de un archivo pero en los sistemas de objetos no es recomendable, ya que si hacemos un cambio en un objeto deberemos borrar el existente y subir un objeto nuevo con la modificación. Aumentando por tanto el tráfico de datos ante pequeñas modificaciones.
En resumen, tenemos un almacenamiento más lento pero muchísimo más barato. Por ello es interesante para guardar gran cantidad de datos que no requieren rápido acceso, perfecto para hacer backups.
Configuración AWS S3
Supondremos que ya estás dado de alta en AWS, datos de pago, has configurado la doble autenticación, etc.
El primer paso es crear una clave de acceso para usar la API de S3, que será la que indicaremos en el fichero de configuración de duply. Para ello vamos a IAM Management Console > Usuarios > Claves de acceso > Crear una clave de acceso.
El siguiente paso será crear una política para dar permisos de acceso a S3 para nuestro usuario en AWS. Para no complicarnos la vida creando una política personalizada, seleccionaremos una ya existente: AmazonS3FullAccess. Vamos a la sección Usuarios > pestaña Permisos > botón Añadir permisos.
Un bucket es una forma de organización de objetos. Podríamos por ejemplo tener un bucket para clientes y otro para uso privado, o un bucket por cliente. Aunque sin duda yo prefiero tener un solo bucket y crear una política personalizada para gestionar el acceso de los diferentes usuarios a determinadas carpetas.
Lo importante que debemos saber de un bucket es que tiene ciertas limitaciones, como que no se puede cambiar de nombre, que este debe ser único de forma global (entre todos los usuarios de Aws) o que existe un límite de 100 buckets por cuenta aws.
El último paso es crear el bucket, en este ejemplo un solo bucket con acceso total para nuestro usuario. Para ello accedemos a la consola de administración de S3: https://s3.console.aws.amazon.com/s3/home y pulsamos el botón Crear bucket. Simplemente le damos un nombre único y la región donde vamos a alojar los datos (a mí me gusta que sea Europa por latencia y porque nos beneficia la ley de protección de datos).
AWS S3 posee infinidad de opciones, como el sistema de versiones o el cifrado, pero para este ejemplo lo mantendremos todo sencillo, el resto de opciones no es necesario rellenarlas.
Instalación de duply
add-apt-repository ppa:duplicity-team/ppa
apt-get update
apt-get install duplicity duply python-boto
pip install boto
Configuración de duply
Para este artículo voy a estar usando Duply 2.1 y duplicity 0.7.18.2 en un Ubuntu 16.04.
Duply permite tener varios perfiles de backup, asi que lo primero es crear uno nuevo. Simplemente tecleamos duply nombre_perfil create
y se nos creará un fichero en ~/.duply/nombre_perfil/conf
.
Es muy recomendable tener una copia del directorio de perfil fuera de la propia copia de duply.
Fichero conf
# no vamos a encriptar las copias
GPG_KEY='disabled'
#GPG_PW='_GPG_PASSWORD_'
TARGET='s3://s3-eu-west-1.amazonaws.com/BUCKET/CARPETABUCKET'
export AWS_ACCESS_KEY_ID='AKIAJNJUCXBGW63USBAQ'
export AWS_SECRET_ACCESS_KEY='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'
# signature v4 es requerido para algunas zonas como paris o frankfurt
export S3_USE_SIGV4="True"
# la carpeta base de donde vamos a realizar nuestras copias
SOURCE='/'
# Mantendremos nuestras copias antiguas un máximo de tres meses
# Esta variable se usa cuando se hace un purge
MAX_AGE=3M
# Mantendremos dos copias completas en todo momentos, por si una se corrompiese. Esta variable se usa cuando se hace un purgeFull
MAX_FULL_BACKUPS=2
# Tiempo máximo en generar un nuevo backup full
# MAX_FULLBKP_AGE no es un parámetro de duply.
# Para ello llamaremos a duplicity con el parámetro --full-if-older-than
MAX_FULLBKP_AGE=1M
# VOLSIZE no es un parámetro de duply.
# Para evitar tener demasiados ficheros de volumen por backup.
# Para ello llamamos a duplicity con el parámetro --volsize
VOLSIZE=1024
# Podemos personalizar la llamada a duplicity
# verbosity info para incluir el listado de ficheros copiados en el log.
DUPL_PARAMS="$DUPL_PARAMS --volsize $VOLSIZE --full-if-older-than $MAX_FULLBKP_AGE --verbosity info --s3-use-new-style --s3-european-buckets"
Podemos encontrar el listado de urls de los endpoints de aws s3 aquí
El fichero conf del ejemplo plantea la siguiente planificación:
Cifrado de la copia
Puede ser muy interesante cifrar la copia, para lo cual usaremos GnuPG, del que ya he hablado aquí.
Para ello simplemente tendremos que establecer las siguientes opciones en el fichero conf.
GPG_KEY='XXXXXXXX' # el id de tu clave pública gpg
GPG_PW='Passphrase' # Passphrase de tu clave, para poder firmar
Como resultado del cifrado si acudimos a ver los ficheros de volúmenes, manifest y signatures, ahora tendrán extensión gpg para indicar que están encriptados.
Necesitaremos el passphrase para hacer restauración y también para los comandos list y status.
-rw------- 1 root root 797 Dec 28 10:57 duplicity-full.20181228T095724Z.manifest.gpg
-rw------- 1 root root 12009790 Dec 28 10:57 duplicity-full.20181228T095724Z.vol1.difftar.gpg
-rw------- 1 root root 761868 Dec 28 10:57 duplicity-full-signatures.20181228T095724Z.sigtar.gpg
Fichero exclude
Para configurar los directorios que queremos incluir o excluir tendremos que editar el fichero ~/.duply/nombre_perfil/exclude
. Usando el símbolo + incluimos y con el símbolo - excluimos. Por ejemplo para realizar un backup completo de la máquina hemos usado SOURCE="/" en el conf y la siguiente lista de exclusiones:
- /proc
- /sys
- /run
- /dev
- /tmp
- /boot
- /media
- /mnt
- /lost+found
- /var/lib/lxcfs
Podemos excluir todo usando comodínes: - **
Ejecutar un backup
Para ejecutar una copia solo tenemos que lanzar el siguiente comando:
duply nombre_perfil backup
Si estamos probando un nuevo perfil y queremos realizar solo una prueba sin copiar realmente los ficheros, tenemos el flag preview
duply nombre_perfil backup --preview
Habitualmente se incluye en el cron la llamada para realizar el backup:
0 2 * * * env HOME=/root /usr/bin/duply nombre_perfil backup
Ejecutar secuencias personalizadas
Lanzar un backup con el comando backup equivale a:
- Ejecutar el script pre (si existe)
- Ejecutar el backup
- Ejecutar el script post (si existe)
Pero podemos componer nuestras propias secuencias con las siguientes acciones:
- pre (ejecuta el script ~/.duply/nombre_perfil/pre)
- post (ejecuta el script ~/.duply/nombre_perfil/post)
- bkp (ejecuta full si no existe y en caso de tener uno ejecutará un incremental)
- full (fuerza un backup completo)
- inc (fuerza un backup incremental)
- purge (realiza un limpiado de backups con antigüedad mayor que MAX_AGE en el conf).
- verify (comprueba los archivos que han cambiado, útil si el backup devuelve errores porque hay ficheros que han cambiado durante su ejecución.)
Para crear una secuencia simplemente usamos el carácter "" para separar acciones, y estas se ejecutarán en orden de izquierda a derecha. Por ejemplo: `duply nombreperfil prebkppurge`.
Incluso tenemos la opción de usar otros separadores:
-
- Sólo se ejecutará si la acción anterior ha tenido éxito.
-
- Sólo se ejecutará si la acción anterior ha fallado.
Borrar los backups antiguos si el backup ha tenido éxito
duply nombre_perfil bkp+purge
Estadísticas
Al finalizar la copia obtendremos un conjunto de estadísticas:
--------------[ Backup Statistics ]--------------
StartTime 1545991044.99 (Fri Dec 28 10:57:24 2018)
EndTime 1545991049.75 (Fri Dec 28 10:57:29 2018)
ElapsedTime 4.76 (4.76 seconds)
SourceFiles 5038
SourceFileSize 34095125 (32.5 MB)
NewFiles 5038
NewFileSize 34095125 (32.5 MB)
DeletedFiles 0
ChangedFiles 0
ChangedFileSize 0 (0 bytes)
ChangedDeltaSize 0 (0 bytes)
DeltaEntries 5038
RawDeltaSize 32030591 (30.5 MB)
TotalDestinationSizeChange 12009790 (11.5 MB)
Errors 0
-------------------------------------------------
Forzar un backup completo
Cada cuánto hacemos un backup full se controla con el flag --full-if-older-than de duplicity, sin embargo si por algún motivo queremos lanzar de inmediato un backup completo simplemente tecleamos:
duply nombre_perfil full
Lanzar script antes del backup
Es muy habitual querer lanzar un script antes o después de hacer un backup, por ejemplo si queremos incluir un volcado de la base de datos en el mismo.
Para ello podemos crear el script que queramos en las rutas indicadas:
~/.duply/nombre_perfil/pre
~/.duply/nombre_perfil/post
Script para backup
Otra opción es crear un pequeño script que controle todo el flujo de la copia invocando él mismo a duply. En mi github dejo un ejemplo de script en python que he preparado. Hace un volcado de mysql y además envía por correo el log de duply: https://github.com/davidpoza/dps-backups-duply
Contenido del backup
Historial
Es muy interesante disponer de un listado de las fechas y los tipos de backup que se han ido realizando a lo largo del tiempo así como los volúmenes que ocupan cada uno.
Con el comando status podemos ver las diferentes cadenas (chain) que se han ido realizando, siendo una cadena cada grupo de full backup + sus incrementales.
duply nombre_perfil status
Chain start time: Sun Sep 23 17:57:43 2018
Chain end time: Thu Dec 27 02:00:05 2018
Number of contained backup sets: 96
Total number of contained volumes: 106
Type of backup set: Time: Num volumes:
Full Sun Sep 23 17:57:43 2018 7
Incremental Mon Sep 24 02:00:03 2018 1
Incremental Tue Sep 25 02:00:03 2018 2
Incremental Wed Sep 26 02:00:03 2018 1
Incremental Thu Sep 27 02:00:04 2018 1
Incremental Fri Sep 28 02:00:04 2018 2
Incremental Sat Sep 29 02:00:04 2018 1
Incremental Sun Sep 30 02:00:04 2018 1
Incremental Mon Oct 1 02:00:04 2018 1
Incremental Tue Oct 2 02:00:04 2018 1
Incremental Wed Oct 3 02:00:04 2018 1
Incremental Thu Oct 4 02:00:04 2018 1
Incremental Fri Oct 5 02:00:05 2018 1
Incremental Sat Oct 6 02:00:06 2018 1
.....
Si vamos a S3 podremos observar los diferentes volúmenes(contienen los ficheros respaldados) que va creando duply en función del --volsize especificado. También vemos archivos manifest, que son los que determinan todos los volúmenes que componen un backup y qué rango de ficheros se guardan en cada uno. Y por último veremos los archivos de signatures, que son listados de ficheros con su hash SHA1, usados para poder identificar cuáles han cambiado desde la última copia y así poder realizar un incremental o para crear el listado de ficheros que veremos a continuación.
Así cuando queremos restaurar un fichero, se leen los manifest y signatures y de este modo duply sabe exactamente qué volúmenes debe descargar de aws s3.
Listado de ficheros
Puede ser que queramos saber si nuestro backup contiene un fichero o concreto. Esta opción es útil pero requiere descargar todo el listado de ficheros del backup, y puede tardar. Por supuesto es útil filtrar con grep.
duply nombre_perfil list
duply nombre_perfil list | grep /var/www
Borrar copias con antigüedad mayor que
Podemos limpiar las copias que tengan una antigüedad mayor a la indicada. Si no indicamos antigüedad entonces usará la variable MAX_AGE del conf. Por defecto no realiza los cambios, para hacerlos efectivamente hay que incluir el flag --force.
duply nombre_perfil purge [max_age] [--force]
En realidad no tiene mucho sentido hacer el purgado manualmente, se puede automatizar, para ello ver apartado Ejecutar secuencias personalizadas.
Borrar copias dejando N backups full
Si lo que deseamos es dejar N copias full (más sus incrementales asociados), debemos usar el comando purgeFull. Si no se indica el parámetro se usa la variable MAXFULLBACKUPS del conf.
duply nombre_perfil purgeFull [max_full_backups] [--force]
Realizar una restauración
Restaurar copia completa
Podemos restaurar toda la copia en el directorio que deseemos. Además tenemos un segundo parámetro age para indicar el momento exacto que queremos. Por defecto si no se indica, se recupera la última versión.
Age acepta los siguientes formatos:
- 2002-01-25T07:00:00+02:00
- 2002/3/5 (fecha AAAA/MM/DD)
- 12D (hace 12 días)
- 1h78m (hace 1 hora y 78 minutos)
duply nombre_perfil restore /destino [age]
Restaurar un fichero o directorio concreto
Salvo catástrofe, lo normal es querer restaurar solo un fichero o directorio, no toda la copia completa.
duply nombre_perfil fetch dir/subdir /restore [age]
Una restauración puede llevar bastante tiempo (dependiendo del tamaño total del backup) aunque solo queramos unos pocos ficheros, ya que tendremos que recuperar de AWS S3 un backup full más cierto número de incrementales. Toda esta operación se realiza en un directorio temporal del tipo /tmp/duplicity-jUXZc-tempdir_. Al finalizar la restauración podremos ver el tiempo que ha durado la operación:
--- Finished state OK at 17:33:50.030 - Runtime 00:14:08.329 ---
Resturar backup cifrado
Si el backup lo hemos cifrado, y tenemos el GPG_PW definida en el fichero conf, entonces la restauración realiza automáticamente el descifrado sin intervención del usuario. En caso contrario nos preguntará por el passphrase.
Documentación
Como siempre, me gusta apuntar a la documentación oficial, para poder profundizar en el funcionamiento de duply o de duplicity.