Restic es un software de backups rápido, eficiente y seguro que soporta multitud de sistemas operativos como Linux, macOS, Windows, FreeBSD y OpenBSD.
Además es capaz de utilizar multitud de sistemas como backend:
- Locales
- Sftp
- REST Server
- Amazon S3
- Minio
- Opentack Swift
- Backblaze B2
- Microsoft Azure Blob Storage
- Google Cloud Storage
- Rclone
- Windows
Empezamos por el servidor, primero clonaremos el repositorio del proyecto:
Compilamos el software y lo instalamos:
make
make install
Creamos el usuario del sistema que correrá el software:
En Restic hay dos conceptos que debemos tener claro para evitar confusiones:
- Rest-server: Es el servidor de restic, este estará protegido mediante password.
- Repositorio de backups: Es un repositorio privado del cliente dentro del restic server, este es protegido mediante un password único que solo conoce el cliente.
Para generar el fichero de autenticación del restic server necesitamos las apache-tools, asà que las instalamos:
Generamos el fichero de auth:
mkdir backups
cd backups
htpasswd -B -c .htpasswd kr0m
NOTA: Si queremos añadir un segundo usuario al fichero ya existente tan solo debemos suprimir el parámetro -c:
kr0m:$2y$05$yLbYcT96wddTqvsuwTp0UkSOK.xkvJhs9CwKXKwaAllNkWWT3mIRSO
kr0m2:$2y$05$YQrJ215y3tcIqJbjaEtq..gNBZhqviwERAL1HcGGnfZyCWQJsrwQ4
Generamos un certificado para que los backups se transmitan de forma segura a través de la red, si vamos a utilizar la dirección ip en el certificado SSL tendremos que generar el certificado con un subjectAltName indicando la dirección ip del servidor.
cd
mkdir ssl
cd ssl
Generamos la private key:
Generamos el certificado con la configuración indicada:
openssl req -x509 -sha256 -days 3650 -key private_key -out public_key -config <(
cat «-EOF
default_bits = 2048
distinguished_name = dn
x509_extensions = san
req_extensions = san
extensions = san
prompt = no
[ dn ]
countryName = ES
stateOrProvinceName = XXXX
localityName = XXXX
organizationName = Alfaexploit
[ san ]
subjectAltName = @alt_names
[ alt_names ]
IP.1 = RESTICSERVERIP
EOF
)
Creamos un script de arranque del servidor:
su restic -s /bin/bash -c "nohup /usr/local/bin/rest-server --path /home/restic/backups --private-repos --prometheus --tls --tls-cert /home/restic/ssl/public_key --tls-key /home/restic/ssl/private_key &"
Asignamos los permisos necesarios:
Lo arrancamos manualmente:
Comprobamos que está arrancado:
restic 18354 0.0 0.0 112272 10668 ? Sl 08:03 0:00 /usr/local/bin/rest-server --path /home/restic/backups --private-repos --prometheus --tls --tls-cert /home/restic/ssl/public_key --tls-key /home/restic/ssl/private_key
NOTA: El parámetro --private-repos es interesante para que los clientes no puedan ver los backups de los otros clientes, otro parámetro destacable es --append-only, con este parámetro habilitado los clientes solo pueden realizar backups pero no borrarlos, si el servidor cliente es hackeado no podrá borrar backups, otra opción muy interesante es --prometheus que nos presentrará métricas que podremos leer mediante Prometheus.
Podemos debugear arrancándolo con el parámetro debug:
/usr/local/bin/rest-server --path /home/restic/backups --private-repos --prometheus --tls --tls-cert /home/restic/ssl/public_key --tls-key /home/restic/ssl/private_key --debug
Para el cliente tendremos que bajamos el binario:
https://github.com/restic/restic/releases
tar xvzf restic-VERSION.tar.gz
cd restic-VERSION
Lo compilamos:
Lo instalamos:
cp restic /usr/local/bin/
useradd -m restic
chown restic:restic /usr/local/bin/restic
chmod 500 /usr/local/bin/restic
Si vamos a backupear ficheros fuera del home de nuestro usuario como backups de bases de datos por ejemplo, necesitaremos acceso a estos datos, para ello modificamos las capabilities del binario de restic:
El binario restic ya puede leer cualquier fichero y directorio independientemente de quién lo ejecute, pero si queremos hacer backups mediante streaming como por ejemplo con xtrabackup, este también necesitará las mismas capabilities ya que es este el que leerá los ficheros.
Copiamos el certificado del rest-server al cliente:
scp root@RESTICSERVERIP:/home/restic/ssl/public_key /usr/local/share/ca-certificates/resticKey.crt
Updateamos la base de datos de CAs:
Consultamos los datos de la CA:
Issuer: C = ES, ST = XXXX, L = XXXX, O = Alfaexploit
Validity
Not Before: Feb 25 08:03:25 2020 GMT
Not After : Feb 22 08:03:25 2030 GMT
Subject: C = ES, ST = XXXX, L = XXXX, O = Alfaexploit
X509v3 extensions:
X509v3 Subject Alternative Name:
IP Address:RESTICSERVERIP
Y del servidor:
depth=0 C = ES, ST = XXXX, L = XXXX, O = Alfaexploit
Definimos los datos de acceso al servidor de restic y el password de nuestro repo:
export RESTIC_REPOSITORY=rest:https://kr0m:PASSWORD@RESTICSERVERIP:8000/kr0m
export RESTIC_PASSWORD=REPOSITORY-PASSWORD
source .bashrc
Inicializamos el repo:
El password del repo es importante, sin él no podremos acceder a los backups realizados.
Podemos ver las keys de un repo con:
repository 17def041 opened successfully, password is correct
ID User Host Created
--------------------------------------------
*65c102fa restic RX4 2020-02-25 09:07:21
--------------------------------------------
NOTA: Se pueden añadir mas keys, por si queremos utilizar distintas contraseñas para el mismo repo.
Backupeamos el directorio work:
touch work/AA
restic -v backup ~/work
Comprobamos que toda la info del repo se ha almacenado sin errores, esto es importante para asegurarse de que los backups son consistentes incluso si se compromete el rest-server:
no errors were found
Restic permite comparar snapshots:
restic -v backup ~/work
restic -v snapshots
ID Time Host Tags Paths
------------------------------------------------------------------------
df975885 2020-02-25 09:08:33 RX4 /home/restic/work
0dd2c06a 2020-02-25 09:24:31 RX4 /home/restic/work
5cf720c5 2020-02-25 09:25:08 RX4 /home/restic/work
------------------------------------------------------------------------
comparing snapshot 0dd2c06a to 5cf720c5:
+ /home/restic/work/BB
Files: 1 new, 0 removed, 0 changed
Dirs: 0 new, 0 removed
Others: 0 new, 0 removed
Data Blobs: 0 new, 0 removed
Tree Blobs: 3 new, 3 removed
Added: 1.312 KiB
Removed: 1.031 KiB
Es posible leer los datos de stdin, puede ser útil para backupear mysqls por ejemplo, los siguientes comandos leerán la salida del dump y lo guardará con el nombre indicado en el parámetro --stdin-filename:
mysqldump --all-databases -uUSER -p’PASSWORD’ | restic backup -v --stdin --stdin-filename dump.sql
xtrabackup --user=USER --password=PASSWORD --backup --stream=tar | restic -v backup --stdin --stdin-filename xtrabackup.tar
Se pueden asignar tags a los snapshots:
restic -v snapshots
ID Time Host Tags Paths
------------------------------------------------------------------------
df975885 2020-02-25 09:08:33 RX4 /home/restic/work
0dd2c06a 2020-02-25 09:24:31 RX4 /home/restic/work
5cf720c5 2020-02-25 09:25:08 RX4 /home/restic/work
0424e81b 2020-02-25 09:39:47 RX4 /dump.sql
41f32b15 2020-02-25 09:41:47 RX4 TAG00 /home/restic/work
------------------------------------------------------------------------
Podemos filtrar por path:
restic -v snapshots
ID Time Host Tags Paths
------------------------------------------------------------------------
df975885 2020-02-25 09:08:33 RX4 /home/restic/work
0dd2c06a 2020-02-25 09:24:31 RX4 /home/restic/work
5cf720c5 2020-02-25 09:25:08 RX4 /home/restic/work
0424e81b 2020-02-25 09:39:47 RX4 /dump.sql
41f32b15 2020-02-25 09:41:47 RX4 TAG00 /home/restic/work
59e93273 2020-02-25 09:45:58 RX4 MYSQLDUMP /dump.sql
------------------------------------------------------------------------
ID Time Host Tags Paths
----------------------------------------------------------------
0424e81b 2020-02-25 09:39:47 RX4 /dump.sql
59e93273 2020-02-25 09:45:58 RX4 MYSQLDUMP /dump.sql
----------------------------------------------------------------
También se puede filtrar por el host que realizó el snapshot:
ID Time Host Tags Paths
------------------------------------------------------------------------
df975885 2020-02-25 09:08:33 RX4 /home/restic/work
0dd2c06a 2020-02-25 09:24:31 RX4 /home/restic/work
5cf720c5 2020-02-25 09:25:08 RX4 /home/restic/work
0424e81b 2020-02-25 09:39:47 RX4 /dump.sql
41f32b15 2020-02-25 09:41:47 RX4 TAG00 /home/restic/work
59e93273 2020-02-25 09:45:58 RX4 MYSQLDUMP /dump.sql
------------------------------------------------------------------------
Para restaurar un snapshot primero consultamos los snapshots:
ID Time Host Tags Paths
------------------------------------------------------------------------
df975885 2020-02-25 09:08:33 RX4 /home/restic/work
0dd2c06a 2020-02-25 09:24:31 RX4 /home/restic/work
5cf720c5 2020-02-25 09:25:08 RX4 /home/restic/work
0424e81b 2020-02-25 09:39:47 RX4 /dump.sql
41f32b15 2020-02-25 09:41:47 RX4 TAG00 /home/restic/work
59e93273 2020-02-25 09:45:58 RX4 MYSQLDUMP /dump.sql
------------------------------------------------------------------------
Restauramos el que nos interese:
restoring <Snapshot 41f32b15 of [/home/restic/work] at 2020-02-25 09:41:47.447912749 +0100 CET by restic@RX4> to /tmp/restore
Comprobamos que se haya restaurado con el contenido correcto:
total 8
drwxr-xr-x 2 restic restic 4096 feb 25 09:25 .
drwxr-xr-x 3 restic restic 4096 feb 25 09:28 ..
-rw-r--r-- 1 restic restic 0 feb 25 09:08 AA
-rw-r--r-- 1 restic restic 0 feb 25 09:25 BB
Si solo queremos un fichero en concreto:
restic -v restore 41f32b15 --target /tmp/restore --include /home/restic/work/BB
ls -la /tmp/restore/home/restic/work/
total 8
drwx------ 2 restic restic 4096 feb 25 09:51 .
drwx------ 3 restic restic 4096 feb 25 09:51 ..
-rw-r--r-- 1 restic restic 0 feb 25 09:25 BB
Restic nos brinda la posibilidad de montar los repositorios mediante FUSE(RO):
restic -v mount mntRestic
En otro terminal podemos navegar por el repo:
total 4
dr-xr-xr-x 1 restic restic 0 feb 25 09:54 .
drwxr-xr-x 6 restic restic 4096 feb 25 09:54 ..
dr-xr-xr-x 1 restic restic 0 feb 25 09:54 hosts
dr-xr-xr-x 1 restic restic 0 feb 25 09:54 ids
dr-xr-xr-x 1 restic restic 0 feb 25 09:54 snapshots
dr-xr-xr-x 1 restic restic 0 feb 25 09:54 tags
Se puede sacar por la stdout un fichero de un snapshot, por ejemplo podrÃamos empipar un dump de mysql directamente a un mysql, es parecido a un cat:
ID Time Host Tags Paths
------------------------------------------------------------------------
df975885 2020-02-25 09:08:33 RX4 /home/restic/work
0dd2c06a 2020-02-25 09:24:31 RX4 /home/restic/work
5cf720c5 2020-02-25 09:25:08 RX4 /home/restic/work
0424e81b 2020-02-25 09:39:47 RX4 /dump.sql
41f32b15 2020-02-25 09:41:47 RX4 TAG00 /home/restic/work
59e93273 2020-02-25 09:45:58 RX4 MYSQLDUMP /dump.sql
194533ab 2020-02-25 10:00:53 RX4 MYSQLDUMP2 /dump.sql
eb0045b8 2020-02-25 10:05:45 RX4 MYSQLDUMP /dump.sql
------------------------------------------------------------------------
En este caso restauramos la base de datos directamente desde el backup:
Debemos tener en cuenta ciertos aspectos de Restic cuando eliminemos snapshots:
- El proceso de borrado puede llevar mucho tiempo, mientras se borra el Ãndice se bloquea y los backups se paralizan hasta que termine.
- Si tenemos un repo por cada cliente solo se bloquean los backups de ese cliente, pero hay que tener en cuenta que la deduplicación funciona a nivel de repo, por lo tanto si los otros clientes copian la misma info NO se deduplicará.
- Es aconsejable realizar un check después de cada prune.
- También se podrÃa dejar un dÃa de descanso de backups para realizar mantenimiento.
Los pasos para eliminar un snapshot son forget y prune:
ID Time Host Tags Paths
------------------------------------------------------------------------
df975885 2020-02-25 09:08:33 RX4 /home/restic/work
0dd2c06a 2020-02-25 09:24:31 RX4 /home/restic/work
5cf720c5 2020-02-25 09:25:08 RX4 /home/restic/work
0424e81b 2020-02-25 09:39:47 RX4 /dump.sql
41f32b15 2020-02-25 09:41:47 RX4 TAG00 /home/restic/work
59e93273 2020-02-25 09:45:58 RX4 MYSQLDUMP /dump.sql
194533ab 2020-02-25 10:00:53 RX4 MYSQLDUMP2 /dump.sql
eb0045b8 2020-02-25 10:05:45 RX4 MYSQLDUMP /dump.sql
------------------------------------------------------------------------
Si hemos arrancado el server con --append-only al eliminar snapshots saldrá el siguiente error:
repository 17def041 opened successfully, password is correct
blob not removed, server response: 403 Forbidden (403)
Sin --append-only funcionará correctamente:
repository 17def041 opened successfully, password is correct
removed snapshot 41f32b15
Realizamos el prune para que libere el espacio de los snapshots borrados:
repository 17def041 opened successfully, password is correct
counting files in repo
building new index for repo
[0:00] 100.00% 9 / 9 packs
repository contains 9 packs (17 blobs) with 3.153 MiB
processed 17 blobs: 0 duplicate blobs, 0 B duplicate
load all snapshots
find data that is still in use for 7 snapshots
[0:00] 100.00% 7 / 7 snapshots
found 15 of 17 data blobs still in use, removing 2 blobs
will remove 0 invalid files
will delete 1 packs and rewrite 0 packs, this frees 810 B
counting files in repo
[0:00] 100.00% 8 / 8 packs
finding old index files
saved new indexes as [4cbba758]
remove 7 old index files
[0:00] 100.00% 1 / 1 packs deleted
done
NOTA: Si algún snapshot contiene ficheros del snapshot eliminado no se recupera el espacio ya que todavÃa es necesario mantener dichos ficheros.
El comando forget permite varias opciones muy interesantes:
--keep-last n, mantiene n snapshots.
--keep-hourly n, mantiene n snapshots guardando el último de cada hora.
--keep-daily n, mantiene n snapshots guardando el último de cada dÃa.
--keep-weekly n, mantiene n snapshots guardando el último de cada semana.
--keep-monthly n, mantiene n snapshots guardando el último de cada mes.
--keep-yearly n, mantiene n snapshots guardando el último de cada año.
--keep-tag tag, mantiene todos los snapshots con la etiqueta indicada.
--keep-within duración, mantiene todos los snapshots hacia atrás el tiempo indicado
ex: 2y5m7d mantendrá los snapshots realizados antes de 2y5m7d desde el último snapshot.
NOTA: Antes de ejecutar comandos que eliminen snapshots es recomendable hacerlo con el parámetro --dry-run para que nos muestre lo que va a hacer.
ID Time Host Tags Paths
------------------------------------------------------------------------
df975885 2020-02-25 09:08:33 RX4 /home/restic/work
0dd2c06a 2020-02-25 09:24:31 RX4 /home/restic/work
5cf720c5 2020-02-25 09:25:08 RX4 /home/restic/work
0424e81b 2020-02-25 09:39:47 RX4 /dump.sql
59e93273 2020-02-25 09:45:58 RX4 MYSQLDUMP /dump.sql
194533ab 2020-02-25 10:00:53 RX4 MYSQLDUMP2 /dump.sql
eb0045b8 2020-02-25 10:05:45 RX4 MYSQLDUMP /dump.sql
------------------------------------------------------------------------
repository 17def041 opened successfully, password is correct
Applying Policy: keep the last 1 snapshots snapshots
snapshots for (host [RX4], paths [/dump.sql]):
keep 1 snapshots:
ID Time Host Tags Reasons Paths
-------------------------------------------------------------------------------
eb0045b8 2020-02-25 10:05:45 RX4 MYSQLDUMP last snapshot /dump.sql
-------------------------------------------------------------------------------
1 snapshots
remove 3 snapshots:
ID Time Host Tags Paths
----------------------------------------------------------------
0424e81b 2020-02-25 09:39:47 RX4 /dump.sql
59e93273 2020-02-25 09:45:58 RX4 MYSQLDUMP /dump.sql
194533ab 2020-02-25 10:00:53 RX4 MYSQLDUMP2 /dump.sql
----------------------------------------------------------------
3 snapshots
snapshots for (host [RX4], paths [/home/restic/work]):
keep 1 snapshots:
ID Time Host Tags Reasons Paths
---------------------------------------------------------------------------------------
5cf720c5 2020-02-25 09:25:08 RX4 last snapshot /home/restic/work
---------------------------------------------------------------------------------------
1 snapshots
remove 2 snapshots:
ID Time Host Tags Paths
------------------------------------------------------------------------
df975885 2020-02-25 09:08:33 RX4 /home/restic/work
0dd2c06a 2020-02-25 09:24:31 RX4 /home/restic/work
------------------------------------------------------------------------
2 snapshots
Para actualizar el binario basta con:
writing restic to /usr/local/bin/restic
find latest release of restic at GitHub
restic is up to date
La monitorización de los backups se puede realizar en el propio script de backup, hay algunos comandos que permiten la salida en formato json, la lista de snapshots por ejemplo, si después del backup sacamos los snapshots y parseamos las fechas podemos saber si todo está en orden o si ha fallado.
Instalamos la herramienta jq para poder parsear los jsons:
Para obtener la salida en json debemos especificar la opción --json:
[
{
"time": "2020-02-25T09:08:33.133725964+01:00",
"tree": "bb4f59228062d10744ed264faef9885665054cc2b7a9a565e2e192ec72cb0775",
"paths": [
"/home/restic/work"
],
"hostname": "RX4",
"username": "restic",
"uid": 1004,
"gid": 1004,
"id": "df9758853f76a6ab34c30f2235f0437ff583e299965d490253d75d1d02f312dd",
"short_id": "df975885"
},
{
"time": "2020-02-25T09:24:31.60798947+01:00",
"parent": "df9758853f76a6ab34c30f2235f0437ff583e299965d490253d75d1d02f312dd",
"tree": "bb4f59228062d10744ed264faef9885665054cc2b7a9a565e2e192ec72cb0775",
"paths": [
"/home/restic/work"
],
"hostname": "RX4",
"username": "restic",
"uid": 1004,
"gid": 1004,
"id": "0dd2c06afd43c4887cff65e4272685bea0f336088ac39384b69983fdf8b79c02",
"short_id": "0dd2c06a"
},
{
"time": "2020-02-25T09:25:08.029555517+01:00",
"parent": "0dd2c06afd43c4887cff65e4272685bea0f336088ac39384b69983fdf8b79c02",
"tree": "e2c27a6608162f37683543d2f387f0989f30cf5cfbb092b942f794d3bbafab94",
"paths": [
"/home/restic/work"
],
"hostname": "RX4",
"username": "restic",
"uid": 1004,
"gid": 1004,
"id": "5cf720c54226ef0777248c43819c31bbaf88359ae472101c434907648de72516",
"short_id": "5cf720c5"
},
{
"time": "2020-02-25T09:39:47.189660055+01:00",
"parent": "5cf720c54226ef0777248c43819c31bbaf88359ae472101c434907648de72516",
"tree": "7c47d858d305bd52e87fc2a60621e966f2e091faea90a974a356ed154476d773",
"paths": [
"/dump.sql"
],
"hostname": "RX4",
"username": "restic",
"uid": 1004,
"gid": 1004,
"id": "0424e81b2e8c93a8a1a7d607a5d432b9429502f8232ac5db381430c46a104d7a",
"short_id": "0424e81b"
},
{
"time": "2020-02-25T09:45:58.501015101+01:00",
"parent": "41f32b15861e7fc5b831f7b6c5bee556891f4cd92d760e75a04fc3e218fdca1f",
"tree": "2815575e89be143230ac007e0e6c8d66b0fbff87785a31461fa08f23980f3ca4",
"paths": [
"/dump.sql"
],
"hostname": "RX4",
"username": "restic",
"uid": 1004,
"gid": 1004,
"tags": [
"MYSQLDUMP"
],
"id": "59e932730b2152f16040bde3628220b9bb700fcc3a38bd32f2b5877cdb09e49d",
"short_id": "59e93273"
},
{
"time": "2020-02-25T10:00:53.224338735+01:00",
"parent": "59e932730b2152f16040bde3628220b9bb700fcc3a38bd32f2b5877cdb09e49d",
"tree": "71188ad64f4ec0fa21a9a358e5d4d37f806b1dda3fe920d2afe44fdf74b44ea9",
"paths": [
"/dump.sql"
],
"hostname": "RX4",
"username": "restic",
"uid": 1004,
"gid": 1004,
"tags": [
"MYSQLDUMP2"
],
"id": "194533ab50641d55aa91a9738bf23b0964f2f98b7d5a7a346f48db35e2971e5d",
"short_id": "194533ab"
},
{
"time": "2020-02-25T10:05:45.896647702+01:00",
"parent": "194533ab50641d55aa91a9738bf23b0964f2f98b7d5a7a346f48db35e2971e5d",
"tree": "5b6420bf946faed29e452d36a67b0f6e0a75eb55c909c479238c6c9180d66f70",
"paths": [
"/dump.sql"
],
"hostname": "RX4",
"username": "restic",
"uid": 1004,
"gid": 1004,
"tags": [
"MYSQLDUMP"
],
"id": "eb0045b835292f7528cb192698e09e32ed756de4ef8035266e8d003d1a91e8be",
"short_id": "eb0045b8"
},
{
"time": "2020-02-25T12:39:07.288277607+01:00",
"parent": "5cf720c54226ef0777248c43819c31bbaf88359ae472101c434907648de72516",
"tree": "826f0ce90202612a7d961cd5a26b132dbea9efb7f6cc7de4d83d944449e6959c",
"paths": [
"/home/restic/work"
],
"hostname": "RX4",
"username": "restic",
"uid": 1004,
"gid": 1004,
"id": "c905cdff6e951cbdf02f93ea1e970face6430b371631dc7f10d3fdcb3aba2816",
"short_id": "c905cdff"
}
]
Mediante jq parseamos el campo time del json:
"2020-02-25T09:08:33.133725964+01:00"
"2020-02-25T09:24:31.60798947+01:00"
"2020-02-25T09:25:08.029555517+01:00"
"2020-02-25T09:39:47.189660055+01:00"
"2020-02-25T09:45:58.501015101+01:00"
"2020-02-25T10:00:53.224338735+01:00"
"2020-02-25T10:05:45.896647702+01:00"
Creamos un bot con botfather para recibir alertas cuando los backups fallen:
/newbot
Use this token to access the HTTP API:
XXXXXX:YYYYYYYYYYYY
Programamos un script de envÃo de mensajes:
import requests
import sys
apiKey = "XXXXXX:YYYYYYYYYYYY"
url = "https://api.telegram.org/bot{}/sendMessage".format(apiKey)
msg = sys.argv[1]
print msg
userId = "ZZZZZZ"
data = {"chat_id":userId,"text":msg}
r = requests.post(url,json=data)
Le asignamos los permisos necesarios:
Ahora procedemos con el script de backup:
#! /bin/bash
HOSTNAME=$(hostname)
# Make backup
echo -e ">> Making Backup"
restic -v backup ~/work2
# Make backups manteinance
echo -e ">> Keeping last 7 backups and prunning old backups"
restic -v forget -\-keep-last 7
restic prune
# Check last backup time
echo -e ">> Checking last backup time"
TIME=$(restic --json -v snapshots|jq '.[-1].time')
TIME=$(echo $TIME | tr -d '"')
#echo Processing: $TIME
YEAR=$(echo $TIME | awk -F "-" '{print$1}')
#echo YEAR: $YEAR
MONTH=$(echo $TIME | awk -F "-" '{print$2}')
#echo MONTH: $MONTH
DAY=$(echo $TIME | awk -F "-" '{print$3}' | awk -F "T" '{print$1}')
#echo DAY: $DAY
HOUR=$(echo $TIME | awk -F "T" '{print$2}' | awk -F ":" '{print$1}')
#echo HOUR: $HOUR
MINUTE=$(echo $TIME | awk -F "T" '{print$2}' | awk -F ":" '{print$2}')
#echo MINUTE: $MINUTE
SECOND=$(echo $TIME | awk -F "T" '{print$2}' | awk -F ":" '{print$3}' | awk -F "." '{print$1}')
#echo SECOND: $SECOND
DATESTRING="$MONTH/$DAY/$YEAR $HOUR:$MINUTE:$SECOND"
#echo dateString: $DATESTRING
EPOCH=$(date -d "$DATESTRING" +%s)
#echo EPOCH: $EPOCH
EPOCHNOW=$(date +%s)
# One day in s, we add some time because of job is cronttabed, we prefer not to count 24h exactly:
# 24*60*60=86400+3600
TRESHOLD=$(echo "scale=3;$EPOCHNOW-86400+3600" | bc)
#echo TRESHOLD: $TRESHOLD
if [ $TRESHOLD -gt $EPOCH ]; then
#echo -e "ERROR: Last day backup NOT detected!!"
#echo -e "Last correct backup: $TIME"
python ~/.scripts/tg.py "ERROR $HOSTNAME: Last day backup NOT detected -> last correct backup: $TIME"
fi
Le asignamos los permisos necesarios:
NOTA: Solo comprobamos el último backup, si falla nos avisará diariamente del fallo.
Restic permite la exportación de métricas a través de Prometheus, para ello arrancamos el rest-server con el parámetro --prometheus:
Podemos acceder a las métricas manualmente mediante curl:
rest_server_blob_delete_bytes_total{repo="kr0m",type="locks",user="kr0m"} 334
rest_server_blob_delete_total{repo="kr0m",type="locks",user="kr0m"} 2
rest_server_blob_read_bytes_total{repo="kr0m",type="keys",user="kr0m"} 894
rest_server_blob_read_total{repo="kr0m",type="keys",user="kr0m"} 2
rest_server_blob_write_bytes_total{repo="kr0m",type="data",user="kr0m"} 920
rest_server_blob_write_bytes_total{repo="kr0m",type="index",user="kr0m"} 354
rest_server_blob_write_bytes_total{repo="kr0m",type="locks",user="kr0m"} 334
rest_server_blob_write_bytes_total{repo="kr0m",type="snapshots",user="kr0m"} 318
rest_server_blob_write_total{repo="kr0m",type="data",user="kr0m"} 1
rest_server_blob_write_total{repo="kr0m",type="index",user="kr0m"} 1
rest_server_blob_write_total{repo="kr0m",type="locks",user="kr0m"} 2
rest_server_blob_write_total{repo="kr0m",type="snapshots",user="kr0m"} 1
La configuración de scraping de Prometheus quedarÃa del siguiente modo:
scrape_configs:
- job_name: rest_server
scrape_interval: 5s
scrape_timeout: 5s
metrics_path: /metrics
scheme: https
static_configs:
- targets:
- RESTICSERVERIP:8000
basic_auth:
username: kr0m
password: PASSWORD
tls_config:
ca_file: /usr/local/share/ca-certificates/resticKey.crt
insecure_skip_verify: false
NOTA: Debemos instalar en Prometheus nuestra CA de confianza:
scp root@RESTICSERVERIP:/home/restic/ssl/public_key /usr/local/share/ca-certificates/resticKey.crt
update-ca-certificates
Hay dashboards ya creadas listas para importarlas en Grafana, en mi caso he tenido que editar cada una de las gráficas porque el source era prometheus y en mi instalación se llama Prometheus:
https://github.com/restic/rest-server/tree/master/examples/compose-with-grafana/dashboards
El resultado final es este:
Troubleshooting
Bloqueos
Hay ocasiones en las que el repositorio queda bloqueado, si al realizar backups vemos:
Fatal: unable to create lock in backend: repository is already locked by PID 28679 on RX4 by restic (UID 1005, GID 1006)
Debemos hacer limpieza mediante:
restic -v rebuild-index
restic -v check
restic -v prune
PolÃtica de backups ignorada
Cuando ejecutamos el comando forget Restic por defecto hace un group by path, esto implica que si path backupeado cambia, por ejemplo un fichero que tiene como nombre un hash distinto en cada backup, el comando forget identificará cada backup como único.
Esto provocará que el keep-last X no se respete ya que cada backup es independiente y no se seguirá la polÃtica de backups indicada, si esto no es detectado a tiempo corremos el peligro de llenar el disco duro.
Para solventar el problema en el comando forget debemos agrupar por host y no por path:
--group-by host