Skip to content

Instantly share code, notes, and snippets.

@rolfn rolfn/restic.md
Last active Nov 14, 2019

Embed
What would you like to do?
Backup auf Cloud-Speicher mit »restic«

Backup auf Cloud-Speicher mit »restic«

Das Programm »restic« ist ein modernes Backup-Programm, welches als Ziel lokal gemountete Verzeichnisse verwenden kann. Darüber hinaus unterstützt es einige ausgewählte Protokolle, um direkt auf Cloud-Speicher zugreifen zu können (SFTP, S3, OpenStack Swift, Google Cloud Storage u.a.). Im Folgenden soll gezeigt werden, wie man unter Linux automatische Backups konfigurieren kann. Als Ziel wird in diesem Beispiel der S3-kompatible »Object Storage Service« (TelekomCLOUD) benutzt. Sinngemäß lassen sich die folgenden Angaben auch auf andere Backup-Ziele (z.B. NFS-Mounts) anwenden. Getestet wurde unter openSUSE, wobei aber auch alle anderen systemd-basierten Linux-Distributionen in derselben Art oder mit geringfügigen Änderungen geeignet sind.

Der Autor von »restic« zeigt in anschaulicher Weise in zwei Videos viele Details zur Arbeitsweise seines Programms: »FOSDEM 2015« (2015-01-28) und »CCC Cologne« (2016-01-29)

Festlegen der Zeitabläufe

Es hat sich als günstig herausgestellt, zwei verschiedene Zeitabläufe zu definieren.

Zeitablauf zum Anlegen eines neuen Backups (snapshot)

Die Datei $HOME/.config/systemd/user/backup.timer

[Unit]
Description=Backup (Timer)

[Timer]
OnCalendar=22:00
Persistent=true 

[Install]
WantedBy=default.target

legt fest, dass täglich um 22 Uhr ein Ablauf gestartet wird, der in der Datei backup.service definiert ist. Sollte der betreffende Nutzer zu diesem Zeitpunkt nicht eingeloggt sein, wird beim nächsten Einloggen die auszuführende Aktion sofort begonnen.

Zeitablauf zum Bereinigen des Backups

Die Datei $HOME/.config/systemd/user/backup-purge.timer

[Unit]
Description=Purge backup snapshots (Timer)

[Timer]
OnCalendar=weekly
Persistent=true  

[Install]
WantedBy=default.target

legt fest, dass einmal wöchentlich ein Ablauf gestartet wird, der in der Datei backup-purge.service definiert ist. Sollte der betreffende Nutzer zu diesem Zeitpunkt nicht eingeloggt sein, wird beim nächsten Einloggen die auszuführende Aktion sofort begonnen.

Initialisierung des Backup-Repositoriums

Für die Initialisierung des Backup-Repositoriums und auch für andere Aufrufe des Programms »restic« ist es nützlich, die Adresse des Repositoriums sowie alle Angaben zur Autorisierung in Form von Umgebungsvariablen bereitzustellen. Dazu erhält die Datei $HOME/.config/backup/backup-env.txt vorerst folgenden Inhalt:

AWS_ACCESS_KEY_ID=????????????????????
AWS_SECRET_ACCESS_KEY=????????????????????????????????????????
RESTIC_REPOSITORY='s3:obs.eu-de.otc.t-systems.com/ob3-3215/backup'

RESTIC_REPOSITORY ermöglicht den S3-kompatiblen Zugriff auf einen Server, der durch den »endpoint« obs.eu-de.otc.t-systems.com definiert ist (hier: »Object Storage Service« der Telekom). Dort wurde ein Speicherbereich (»bucket«) mit dem Namen ob3-3215 definiert. Das Backup soll künftig darin in einem Verzeichnis backup untergebracht werden. Die Angaben zu AWS_ACCESS_KEY_ID und AWS_SECRET_ACCESS_KEY erhält man per Web-Zugang zum Server beim Anlegen des Buckets. Mit dem folgenden restic-Aufruf wird das Backup-Repositorium initialisiert:

eval $(cat $HOME/.config/backup/backup-env.txt) restic init

Das dabei erfragte Passwort für die Verschlüsselung des späteren Backups muss danach als weitere Zeile der Datei $HOME/.config/backup/backup-env.txt hinzugefügt werden:

RESTIC_PASSWORD='????????????'

Es ist zu empfehlen, die Lese- und Schreibrechte der Datei auf ihren Eigentümer zu beschränken:

chmod 600 $HOME/.config/backup/backup-env.txt

Zeitgesteuertes Anlegen eines neuen Backups (Snapshot)

Durch den in der Datei backup.timer festgelegten Zeitablauf wird periodisch ein neuer Snapshot entsprechend dem Inhalt der Datei $HOME/.config/systemd/user/backup.service erstellt:

[Unit]
Description=Backup %H
Documentation=https://restic.readthedocs.io/en/latest/
OnFailure=failure-email@%n.service

[Service]
Type=oneshot
EnvironmentFile=%h/.config/backup/backup-env.txt
#---Ubuntu---#EnvironmentFile=/etc/environment
#---Ubuntu---#Environment=HOME=%h 
ExecStart=/bin/bash -lc "/usr/bin/nice -n 15 /usr/bin/ionice -c2 -n5 \
  /usr/bin/restic backup --cleanup-cache \
  --files-from   %h/.config/backup/backup-include.txt \
  --exclude-file %h/.config/backup/backup-exclude.txt \
  --one-file-system --exclude-caches"

[Install]
WantedBy=default.target

Zur Erklärung: Der restic-Aufruf legt einen neuen Snapshot dessen an, was sich seit dem vorigen geändert hat. Welche Verzeichnisse behandelt und welche ignoriert werden sollen, ist in den Dateien backup-include.txt und backup-exclude.txt enthalten. Das Ziel des Backups und alle nötigen Angaben zur Autorisierung erhält das Programm über die Umgebungsvariablen, die in der Datei $HOME/.config/backup/backup-env.txt definiert sind (siehe oben). Nähere Hinweise zu weiteren Angaben beim Anlegen eines Snapshots entält die Dokumenation. Im Falle dessen, dass dieser Ablauf mit einem Fehler endet, wird die Systemd-Unit failure-email@.service aufgerufen. Näheres zu failure-email@.service siehe weiter unten. Die mit #---Ubuntu---# gekennzeichneten Zeilen sind nur unter »Ubuntu« notwendig.

Test

Mit

systemctl --user start backup.service

kann man einen neuen Snapshot unabhängig vom automatischen Timer-Aufruf erzeugen. Wenn man parallel dazu in einem anderen Terminal

journalctl -f --user-unit backup.service

aufruft, kann man die Ausgabe des restic-Aufrufs beobachten.

Manuelles Überprüfen des Backups

Mit dem folgenden Aufruf lässt sich die Integrität des Backups überprüfen:

eval $(cat $HOME/.config/backup/backup-env.txt) restic check

Eine erweiterte Überprüfung, bei der auch die Daten selbst mit einbezogen werden, erreicht man mit

eval $(cat $HOME/.config/backup/backup-env.txt) restic check --read-data

Diese Überprüfung kann relativ lange andauern.

Zeitgesteuertes Bereinigen und Überprüfen des Backups

Grundsätzlich wäre es möglich, nach der oben gezeigten Definition, unbegrenzt über Jahre hinweg jeden Tag einen neuen Snapshot anzulegen. Ein solches Vorgehen ist allerdings nicht unbedingt notwendig. Es ist ausreichend, wenn man nur eine bestimmte Zahl der täglichen Snapshots aufbewahrt. Das Programm »restic« unterstützt Regeln, nach denen als unnötig betrachtete Snapshots gelöscht werden. Die Datei $HOME/.config/systemd/user/backup-purge-check.service definiert dazu einen geeigneten Ablauf:

[Unit]
Description=Purge backup snapshots 
Documentation=https://restic.readthedocs.io/en/latest/
OnFailure=failure-email@%n.service

[Service]
Type=oneshot
EnvironmentFile=%h/.config/backup/backup-env.txt
#---Ubuntu---#EnvironmentFile=/etc/environment
#---Ubuntu---#Environment=HOME=%h 
ExecStartPre=/usr/local/bin/restic unlock --remove-all
ExecStart=/usr/local/bin/restic forget --prune \
  --keep-daily 7 --keep-weekly 4 --keep-monthly 12 
ExecStart=/usr/local/bin/restic check

[Install]
WantedBy=default.target

Zur Erklärung: Dieser restic-Aufruf löscht alle Snapshots, die älter als sieben Tage sind, wobei aber darauf geachtet wird, dass zusätzlich vier Wochen rückwirkend jeweils ein Snapshot pro Woche erhalten bleibt. Ebenso bleibt zusätzlich 12 Monate rückwirkend jeweils ein Snapshot pro Monat erhalten. Auf diese Weise hat man die Sicherheit, aktuelle Stände zur Verfügung zu haben. Darüber hinaus hat man aber auch die reale Chance, maximal ein Jahr rückwirkend Dateien wiederherstellen zu können.

Fehlerbehandlung

Die besprochenen Systemd-Units (backup.service und backup-purge-check.service) enthalten jeweils die Zeile

OnFailure=failure-email@%n.service

Im Falle eines Fehlers wird dadurch die Unit failure-email@.service mit dem Namen der ursprünglichen Unit als Parameter aufgerufen. Die Datei hat den folgenden Inhalt:

[Unit]
Description=OnFailure email for %i

[Service]
Type=oneshot
KillMode=process
ExecStart=%h/.config/systemd/user/email-on-failure.sh %i

Zur Erklärung: Es wird das Shell-Script $HOME/.config/systemd/user/email-on-failure.sh mit einem Unit-Namen (z.B. backup.service) als Parameter aufgerufen. Das Shell-Script dient der Benachrichtigung über den aufgetretenen Fehler per E-Mail. Es könnte folgenden Inhalt haben (hier als Beispiel: E-Mail-Versand durch den E-Mail-Provider »GMX«):

#!/bin/bash

EMAIL="Max.Mustermann@gmx.de"
SUBJECT="OnFailure ($1)"
SENDER="$EMAIL"

cat <<EOF | mailx -s "$SUBJECT" \
-S from=$SENDER \
-S ssl-verify=ignore \
-S smtp-auth=login \
-S smtp=smtps://mail.gmx.de:465 \
-S smtp-auth-user=$EMAIL \
-S smtp-auth-password='__GEHEIM__' \
$EMAIL
*** STATUS ***
$(systemctl --user status -l -n 30 "$1")
EOF

exit

Das Script muss ausführbar gemacht werden:

chmod u+x $HOME/.config/systemd/user/email-on-failure.sh

Im Betreff der E-Mail wird die mit Fehler beendete Unit genannt. Im Hauptteil der E-Mail werden die letzten 30 Zeilen von deren Status-Abfrage angegeben.

Test

Um das Verhalten im Fehlerfalle zu testen, kann Folgendes getan werden. Testweise wird in $HOME/.config/backup/backup-include.txt ein nichtexistierendes Verzeichnis wie z.B.

/Wrzlbrnft

eingetragen, was zu einem fehlerhaften restic-Aufruf nach

systemctl --user start ptb-backup.service

führt. Dies wiederum sollte zum Versenden einer E-Mail an Max.Mustermann@gmx.de führen.

Restore

Wiederherstellen ausgewählter Dateien (Mounten des Backups)

Das Programm »restic« erlaubt es, das gesamte Backup zu mounten. Dies ist eine angemessene Methode, wenn es darum geht, nur einige ausgewählte Dateien aus dem Backup wiederherzustellen. Die Datei $HOME/.config/systemd/user/backup-mount.service enthält den dazu nötigen Aufruf:

[Unit]
Description=Mount the backup
Documentation=https://restic.readthedocs.io/en/latest/

[Service]
Type=simple
EnvironmentFile=%h/.config/backup/backup-env.txt
#---Ubuntu---#EnvironmentFile=/etc/environment
#---Ubuntu---#Environment=HOME=%h 
ExecStart=/usr/bin/restic mount %h/backup
ExecStop=/usr/bin/fusermount -zu %h/backup

[Install]
WantedBy=default.target

Zur Erklärung: Der Aufruf systemctl --user start backup-mount.service macht den Inhalt des Backups über das Verzeichnis $HOME/backup zugänglich. Mit systemctl --user stop backup-mount.service wird er wieder abgemeldet. Die folgende Bash-Funktion vereinfacht das manuelle Mounten (man kann sie in $HOME/.bashrc eintragen):

function mountBackup () {
  local mp="$HOME/backup"
  if $(mountpoint -q $mp); then
    systemctl --user stop backup-mount.service
    echo "\"$mp\" unmounted"
  else
    systemctl --user start backup-mount.service 
    echo "\"$mp\" mounted"
  fi
}

Der Aufruf von mountBackup bindet den Inhalt des Backups als $HOME/backup ein. Ist der Mount-Prozess bereits aktiv, bewirkt der Aufruf, dass er stattdessen ausgehangen wird. Je nach Güte der Netzwerkverbindung zum Cloud-Speicher kann es einige Zeit dauern, bis ein Zugriff möglich ist.

Da auch hier auf systemd zurückgeriffen wird, wäre es bei Bedarf leicht möglich, den Inhalt des Backups automatisch beim Einloggen zu mounten:

systemctl --user enable backup-mount.service
systemctl --user start  backup-mount.service

Wiederherstellen aller gesicherten Dateien

Es ist möglich, mit einem einzelnen restic-Aufruf alle gesicherten Dateien eines bestimmten Snapshots an ihren ursprünglichen Platz zurückzuholen oder sie an anderer Stelle abzulegen. Zur zeitlichen Einordnung der Snapshots ist der folgende Aufruf geeignet:

eval $(cat $HOME/.config/backup/backup-env.txt) restic snapshots

Das Rückholen des kompletten Snapshots könnte so erfolgen:

eval $(cat $HOME/.config/backup/backup-env.txt) restic restore 6ae7c118 --target /home

Statt der konkreten Snapshot-Kennung (in diesem Beispiel 6ae7c118) kann bei Bedarf auch latest angegeben werden.

Näheres dazu ist in der Dokumentation zu finden.

Aktivieren der automatischen Abläufe

systemctl --user enable backup.timer # Timer beim Einloggen automatisch starten 
systemctl --user start  backup.timer # Timer jetzt starten
systemctl --user enable backup-purge.timer
systemctl --user start  backup-purge.timer

Test

systemctl --user status backup.timer
journalctl -f --user-unit backup.service 
journalctl --since yesterday --user-unit backup.service
systemctl --user list-timers 

Rolf (2018/04)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.