Restic


(Picture by Martin Spiske)

Beginnen wir mit der guten Reihe Backups. Es gibt ja die Regel:

Kein Backup, kein Mitleid

Kein Backup-Werkzeug ist perfekt für alles. Ich versuche mal verschiedene Techniken für Backups zu zeigen. Jeder muß für sich entscheiden, ob er und wie er eine Technik einsetzt. Ich selbst mische die verschiedensten Methoden, wie Syncthing, btrbk, restic, git-Annex. Meine Strategien, was wo hingespeichert wird, sind dementsprechend auch relativ flexibel.

Heute beginne ich mit restic. Hier handelt es sich eher um eine klassische Backup-Lösung. Das Backup wird in einem Repository abgelegt. Dies kann eine lokale Directory sein oder remote abgelegt werden. Hier gibt es verschiedenste Methoden, wie sftp, ein REST-Server oder Wolkenstorages, wie S3, minio usw.

Backups werden in Snapshots gespeichert, die dann per Hostname, Tags usw. organisiert sind. Snapshots sind incrementell, zudem werden die Dateien dedupliziert (indem sie im Repository mit eineindeutiger SHA-Prüfsumme weggespeichert werden). Ein Snapshot muß nicht unbedingt eine Directory sein, man kann auch Daten per Unix-Pipe wegspeichern. Damit ist es möglich, direkt einen Datenbank-Dump in einen Snapshot zu pumpen.

Restores funktionieren z. B. über eine per fuser eingespiegelte Directory oder mit gezieltem Download.

Ein Beispielszenario

Nehmen wir an, wir haben eine Maschine backup, die die Backups halten soll. Diese ist per ssh erreichbar und stellt eine r/w-Directory /srv/restic-repo zur Verfügung.

Initialisierung

Nun kann man ein Repository folgendermaßen inititalisieren:

$ restic -r sftp:user@backup:/srv/restic-repo init
enter password for new backend:
enter password again:
created restic backend f1c6108821 at sftp:user@backup:/srv/restic-repo
Please note that knowledge of your password is required to access the repository.
Losing your password means that your data is irrecoverably lost.

Das Backend-Paßwort wird zur Verschlüsselung des Repositories auf dem Server verwendet. Auch für die Schlüsselverwaltung gibt es natürlich Funktionalitäten, auf die ich hier mal nicht eingehe.

Backup

Machen wir einfach mal ein Backup, auf einer Maschine:

$ restic -r sftp:user@backup:/srv/restic-repo --verbose backup ~/work
open repository
enter password for repository:
password is correct
lock repository
load index files
start scan
start backup
scan finished in 1.837s
processed 1.720 GiB in 0:12
Files:        5307 new,     0 changed,     0 unmodified
Dirs:         1867 new,     0 changed,     0 unmodified
Added:      1.200 GiB
snapshot 40dc1520 saved

Hat der Backup funktioniert?

$ restic -r sftp:user@backup:/srv/restic-repo snapshots
enter password for repository:
ID        Date                 Host      Tags  Directory
----------------------------------------------------------------------
40dc1520  2015-05-08 21:38:30  kasimir         /home/user/work

Macht man nun kurz darauf erneut einen Backup…

$ restic -r sftp:user@backup:/srv/restic-repo --verbose ~/work
open repository
enter password for repository:
password is correct
lock repository
load index files
using parent snapshot d875ae93
start scan
start backup
scan finished in 1.881s
processed 1.720 GiB in 0:03
Files:           0 new,     0 changed,  5307 unmodified
Dirs:            0 new,     0 changed,  1867 unmodified
Added:      0 B
snapshot 79766175 saved

… geht das wesentlich schneller und man sieht, daß in Wirklichkeit keine neuen Daten übertragen wurden. Hier greift das incrementell und deduplizierend konzipierte System. Trotzdem sehen wir nun zwei Snapshots:

$ restic -r sftp:user@backup:/srv/restic-repo snapshots
enter password for repository:
ID        Date                 Host      Tags  Directory
----------------------------------------------------------------------
40dc1520  2015-05-08 21:38:30  kasimir         /home/user/work
79766175  2015-05-08 21:40:19  kasimir         /home/user/work

Man kann diese nun auch vergleichen (hier mal als Beispiel ein weiterer Backup, in dem sich was getan hat):

$ restic -r sftp:user@backup://srv/restic-repo diff 40dc1520 2ab627a6
password is correct
comparing snapshot 40dc1520 to 2ab627a6:

 C   /home/user/work/cmd_diff.go
+    /home/user/work/foo
 C   /home/user/work/bla

Files:           0 new,     0 removed,     2 changed
Dirs:            1 new,     0 removed
Others:          0 new,     0 removed
Data Blobs:     14 new,    15 removed
Tree Blobs:      2 new,     1 removed
  Added:   16.403 MiB
  Removed: 16.402 MiB

Restore

Backup ist ja immer nett, netter ist aber, wenn man einen Restore anschmeißen kann und der auch funktioniert. Hier also Restore-Strategien.

Zunächst die klassische Methode: Kopieren des Snapshots.

$ restic -r sftp:user@backup:/srv/restic-repo restore 79766175 --target /tmp/restore-work
enter password for repository:
restoring <Snapshot of [/home/user/work] at 2015-05-08 21:40:19.884408621 +0200 CEST> to /tmp/restore-work

Eine viel schickere Methode ist aber der Mount. Hier wird ein Snapshot oder das Repository in eine Directory gemountet:

$ mkdir /mnt/restic
$ restic -r sctp:user@backup:/srv/restic-repo mount /mnt/restic
Now serving /srv/restic-repo at /mnt/restic
When finished, quit with Ctrl-c or umount the mountpoint.

nun kann man mit einem anderen Terminal durch die Struktur des Repos wandern, bis man obigen Mount mit Ctrl-c beendet.

Vereinfachungen

In unserem Fall wurden bei den Aufrufen immer komplett alle Parameter mitgegeben. Man kann allerdings hier etwas einsparen:

  • Setzen der Environment-Variable RESTIC_REPOSITORY ersetzt den Parameter -r.
  • Das Backend-Paßwort kann man ebenfalls in eine Datei auslagern und diese per RESTIC_PASSWORD_FILE dem System bekannt machen.
  • ssh sollte man mit öffentlichen Schlüsseln bearbeiten, damit ist man in der Lage, ohne jegliche Paßworte aufs System zugreifen zu können.
  • Man kann zudem die Backups von einem technischen User durchführen lassen. Damit die Permissions funktionieren kann man diesem User per setcap die nötigen Rechte geben.

Wo einsetzen?

In meinem Fall sind alle wichtigen Maschinen per btrbk gesichert. Aber es gibt Ausnahmen:

  • ein Unifi-Controller auf Raspian-Basis mit ext4-Filesystem
  • Datenbankbackups
  • Smartphones (sic, geht mit dem richtigen Betriebsystem)

Raspian-System-Backup

hier habe ich im /etc/cron.d/backup eine Anweisung für den Backup und eine für das Aufräumen alter Sachen eingebaut:

10 3 * * * root restic -p ~/.restic -r sftp:user@backup:/srv/restic-repo backup --exclude "/dev" --exclude "/proc" --exclude "/sys" --exclude "/tmp" --tag wlc -q /
50 3 * * * root restic -p ~/.restic -r sftp:user@backup:/srv/restic-repo forget --keep-daily 3 --keep-weekly 5 --keep-monthly 2 --tag wlc -q

Hier sind natürlich die oben angegebenen Vereinfachungen mit verwendet. Die keep--Optionen ermöglichen das Vorhalten der letzten 3 Tage, letzen 5 Wochen, letzten 2 Monaten.

Datenbank-Backup

Auch hier gibt es /etc/cron.d-Einträge. Grundsätzlich wird hier der Datenbankdump über einen Pipe in den restic-Befehl gegeben. Beispiel MySQL/MariaDB:

mysqldump -u dbuser --password=dbpassword datenbank | restic -p ~/.restic -r sftp:user@backup:/srv/restic-repo backup --tag db --tag mariadb -q --stdin --stdin-filename database.sql

Der Snapshot besteht dann nur aus einer einzelnen Datei, keiner Directory.

SailfishOS

restic ist in Go geschrieben und es existiert in diversen Linux-Distributionen. Allerdings gibt es auf Github auch schon fertige Binaries und das ist hier im Speziellen interessant:

SailfishOS kann in der neuesten Version das Home-Verzeichnis verschlüsseln. Das macht es aber nur rudimentär: Mit der Verschlüsselung wird die Homedirectory gelöscht. Das ist wie ein Datenverlust und man muß sein System neu aufsetzen. Natürlich kann man das Sailfish-Backup verwenden, aber bei mir ist das sogar gescheitert.

Also muß man das System vorher wegspeichern und da bietet sich natürlich an, auf ein funktionierendes Backup-System zu wechseln.

Bei den Restic-Releases gibt es auch eine linux_arm-Version. Die kann man auf sein Device herunterladen, auspacken und als /usr/local/bin/restic wegspeichern.

restic hat eine eigene Update-Funktionalität.

devel-su restic self-update

ermöglicht dann eine Aktualisierung.

Weitere Infos

Die gesamte Dokumentation von Restic kann man hier finden.

See also