Linux things 🐧

un blog sur les technologies des logiciels libres et autres digressions

Garage : un serveur S3

la sauvegarde avec Garage et Restic

Wed, 26 Jun 2024 17:40:50 +0200
# S3   # garage   # restic   # auto-hebergement  

Introduction

La sauvegarde est une composante impĂ©rative dans un systĂšme d’information mais aussi pour un particulier. Les annecdotes de particuliers ayant perdu des semaines de travail ou de prĂ©cieuses photos de famille sont rĂ©currentes, mais il est vrai qu’on ne s’y intĂ©resse qu’une fois le mal fait.

Il existe un nombre incalculable de solutions diffĂ©rentes pour appliquer des sauvegardes, pour ma part j’utilise depuis des annĂ©es Restic associĂ© Ă  un serveur S3.
Restic est une solution de sauvegarde en ligne de commande (en Go), ce qui permet de facilement l’automatiser via un tĂąche cron, sur des serveurs et poste de travail. Il sait utiliser diffĂ©rentes solutions de stockage en cloud comme Azure, Google Cloud, Wasabi, et bien sĂ»r Amazon S3.
L’avantage de S3 est qu’il existe un grand nombre de clone qui ont implĂ©mentĂ© l’API d’Amazon comme Scaleway Object Storage, mais aussi des logiciels libres comme Minio (en Go) ce qui permet de possĂ©der son propre serveur S3.

Garage

J’ai dĂ©couvert il y a peu cette implĂ©mentation libre de S3. Garage est un serveur dĂ©veloppĂ© en Rust, donc par nature plus lĂ©ger et rapide que Minio, il se veut aussi plus simple car il ne possĂšde pas d’interface web. Garage est dĂ©veloppĂ© par l’association française Deuxfleurs, vous pouvez retrouver une vidĂ©o de prĂ©sentation lors du Pas Sage En Seine 2023 : Surmonter les difficultĂ©s de l’auto-hĂ©bergement ensemble avec Garage.
L’intĂ©rĂȘt pour moi face Ă  Minio est donc sa lĂ©gĂšretĂ© et sa rapiditĂ©, ce qui doit permettre de l’utiliser avec un RaspberryPi. Pour ma part je l’utilise avec un NUC (core I3/16Go RAM) avec 2 disques de 1To. Auparavant j’utilisais le service S3 de Scaleway, mais l’augmentation de la taille des sauvegardes de mon poste de travail fait que la facture peut ĂȘtre salĂ©e. Dans ce cas l’auto-hĂ©bergement sur ses propres disques peut ĂȘtre une solution. Si l’on veut plus de rĂ©silience on peut monter un cluster entre diffĂ©rentes localisations : Deployment on a cluster. Ainsi les donnĂ©es sont rĂ©pliquĂ©es et sĂ©curisĂ©es en cas d’incident sur un lieu.

Installation

L’installation est trĂšs simple puisqu’il s’agit de tĂ©lĂ©charger un fichier binaire selon votre architecture (X86 ou ARM). Pour ce service je n’ai pas choisi un environnement Docker / Nomad, car pour l’instant il ne s’agit que d’un usage local. Je suis parti du quick-start pour dĂ©marrer la configuration et mis en place un service systemd (voir la doc). A savoir que j’ai commentĂ© la ligne DynamicUser=true car mes disques sont montĂ©s dans /opt et pas dans /var/lib/garage :

cat /etc/systemd/system/garage.service

[Unit]
Description=Garage Data Store
After=network-online.target
Wants=network-online.target

[Service]
Environment='RUST_LOG=garage=info' 'RUST_BACKTRACE=1'
ExecStart=/usr/bin/garage server
StateDirectory=garage
#DynamicUser=true
ProtectHome=true
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

cat /etc/garage.toml

metadata_dir = "/opt/garage/meta"

data_dir = [
    { path = "/opt/garage/sdc", capacity = "1T" },
    { path = "/opt/garage/sdd", capacity = "1T" },
]

db_engine = "lmdb"

replication_factor = 1

rpc_bind_addr = "[::]:3901"
rpc_public_addr = "IP_NUC:3901"
rpc_secret = "TOKEN"

[s3_api]
s3_region = "garage"
api_bind_addr = "[::]:3900"
root_domain = ".s3.garage.localhost"

[s3_web]
bind_addr = "[::]:3902"
root_domain = ".web.garage.localhost"
index = "index.html"

[k2v_api]
api_bind_addr = "[::]:3904"

[admin]
api_bind_addr = "[::]:3903"
admin_token = "TOKEN"
metrics_token = "TOKEN"

Comme indiqué dans la doc, les tokens ont été générés par openssl rand -hex 32. On lance le service par systemctl enable --now garage puis on le prépare :

garage status
# on récupÚre l'ID
garage layout assign -z home -c 1T ID
garage layout apply --version 1
garage bucket create nuc
garage key create nuc-app-key
# on note les TOKEN générées dans son gestionnaire de pass
garage bucket allow --read --write --owner nuc --key nuc-app-key

On vérifie que le bucket est opérationnel avec garage bucket info nuc puis on peut passer à Restic.

Restic

Sur son PC de travail on l’installe via pacman ou en tĂ©lĂ©chargeant le binaire. Ensuite on Ă©crit dans un fichier .restic_garage :

cat .restic_garage

export AWS_ACCESS_KEY_ID=TOKEN
export AWS_SECRET_ACCESS_KEY=TOKEN
export AWS_DEFAULT_REGION='garage'
export AWS_ENDPOINT_URL='http://IP_NUC:3900'
export RESTIC_REPOSITORY=s3:http://IP_NUC:3900/nuc/restic

Les tokens sont celles générées précédement sur le serveur NUC par la commande garage key create nuc-app-key. Puis il faut appliquer ce fichier avec source .restic_garage (ajouter cette commande dans son .bashrc / .zshrc).
Et pour finir lancer :
restic init

Restic demande alors un nouveau mot de passe que je conseille de gĂ©nĂ©rer via son gestionnaire de passe. Puis l’ajouter Ă  la fin du fichier .restic_garage :

export AWS_ACCESS_KEY_ID=TOKEN
export AWS_SECRET_ACCESS_KEY=TOKEN
export AWS_DEFAULT_REGION='garage'
export AWS_ENDPOINT_URL='http://IP_NUC:3900'
export RESTIC_REPOSITORY=s3:http://IP_NUC:3900/nuc/restic
export RESTIC_PASSWORD=PASS

source .restic_garage

⚠

Restic chiffre les sauvegardes sur le serveur S3, vos données seront alors illisible si on vole vos disques (bien) ou si vous perdez votre mot de passe (pas bien). Les données sont également compressées.

⚠

Sauvegarde et restauration

On peut maintenant sauvegarder ses répertoires, exemple avec le répertoire code :

restic --verbose backup code

Attention selon le volume du rĂ©pertoire cela peut prendre du temps la premiĂšre fois. Au prochain backup Restic n’enverra que la diffĂ©rence.

Ensuite on peut consulter ses snapshots

restic snapshots
repository 73f79abc opened (version 2, compression level auto)
ID        Time                 Host        Tags        Paths
---------------------------------------------------------------------------
bc5d52a3  2024-06-26 08:16:29  zenbook                 /home/fred/code
2e21a158  2024-06-26 08:45:05  zenbook                 /home/fred/Documents
a0b642bf  2024-06-26 09:23:30  zenbook                 /home/fred/Images
7d0a765c  2024-06-26 14:31:04  zenbook                 /home/fred/code
---------------------------------------------------------------------------
4 snapshots

On voit ici 2 snapshots pour le rĂ©pertoire code. On peut soit restaurer une version particuliĂšre en prĂ©cisant l’ID :

restic restore bc5d52a3 --target /

Soit la version la plus récente :

restic restore latest --target / --path "/home/fred/code"

On peut aussi monter Restic dans un répertoire si on veut naviguer dans son dépÎt avant une restauration :

mkdir /tmp/restic
restic mount /tmp/restic/
repository 73f79abc opened (version 2, compression level auto)
[0:00] 100.00%  25 / 25 index files loaded
Now serving the repository at /tmp/restic/
Use another terminal or tool to browse the contents of this folder.
When finished, quit with Ctrl-c here or umount the mountpoint.
ls -alh /tmp/restic/
total 0
dr-xr-xr-x  1 fred fred    0 26 juin  15:39 .
drwxrwxrwt 30 root root 4,8K 26 juin  15:40 ..
dr-xr-xr-x  1 fred fred    0 26 juin  15:39 hosts
dr-xr-xr-x  1 fred fred    0 26 juin  15:39 ids
dr-xr-xr-x  1 fred fred    0 26 juin  15:39 snapshots
dr-xr-xr-x  1 fred fred    0 26 juin  15:39 tags
ls -alh /tmp/restic/hosts/zenbook/2024-06-26T14:31:04+02:00/
total 0
dr-xr-xr-x 2 root root 0 26 juin  14:31 .
dr-xr-xr-x 1 fred fred 0 26 juin  15:39 ..
drwxrwxr-x 2 fred fred 0 25 juin  11:04 code

Un exemple de script cron journalier avec en bonus le service Gotify pour recevoir des notifications sur mon laptop et smartphone (voir Gotify et notification desktop) :

cat /etc/cron.daily/restic_backup

#!/bin/bash

source /root/.restic_scw

DATE=$(date +%Y-%m-%d_%Hh%M)
curl -X POST "https://gotify.fredix.xyz/message?token=TOKEN" -F "title=node1 : restic backup" -F "message=restic started : ${DATE}" -F "priority=3"

/usr/bin/ionice -c2 nice -n19 /usr/local/bin/restic backup /opt > /var/log/restic_opt.log

/usr/bin/ionice -c2 nice -n19 /usr/local/bin/restic backup /swarm/volumes/nomad --exclude="/swarm/volumes/nomad/radicle/node/.radicle/storage/" > /var/log/restic_backup.log

/usr/bin/ionice -c2 nice -n19 /usr/local/bin/restic backup /etc > /var/log/restic_backup_etc.log

/usr/bin/ionice -c2 nice -n19 /usr/local/bin/restic backup /usr/local/bin > /var/log/restic_backup_usr_local_bin.log

DATE=$(date +%Y-%m-%d_%Hh%M)
curl -X POST "https://gotify.fredix.xyz/message?token=TOKEN" -F "title=node1 : restic backup" -F "message=restic finished : ${DATE}" -F "priority=3"

ionice permet de lancer restic avec une priorité des I/O faible.

Purge

On peut se retrouver avec un grand nombre de snapshots inutiles, aussi il est nĂ©cessaire d’appliquer une politique de purge. Voici un script exĂ©cutĂ© sur mon serveur tous les weekend :

cat /etc/cron.weekly/restic_purge

#!/bin/bash

source /root/.restic_scw

DATE=$(date +%Y-%m-%d_%Hh%M)
curl -X POST "https://gotify.fredix.xyz/message?token=TOKEN" -F "title=restic purge" -F "message=restic purge started : ${DATE}" -F "priority=3"

/usr/bin/ionice -c2 nice -n19 /usr/local/bin/restic forget --keep-last 3 --prune > /var/log/restic_purge.log

DATE=$(date +%Y-%m-%d_%Hh%M)
curl -X POST "https://gotify.fredix.xyz/message?token=TOKEN" -F "title=restic purge" -F "message=restic purge finished : ${DATE}" -F "priority=3"

Je conserve les 3 derniers backups, mais la politique de purge peut ĂȘtre beaucoup plus complexe, voir la doc removing-snapshots-according-to-a-policy. L’option --prune demande Ă  Restic de supprimer physiquement les donnĂ©es du serveur S3.

Le duo Garage / Restic est trĂšs efficace, mĂȘme si un utilisateur lambda prĂ©ferera une interface graphique comme DejaDup ou une solution payante type pCloud. A noter l’existence du projet Resticity comme interface graphique Ă  Restic.

Liens