Wie ich gelernt habe, unterstützt restic mit dem copy Befehl das Kopieren von Snapshots in ein anderes Repository. Das gibt mir die Möglichkeit, snapshots ohne rsync in ein anderes restic Repository zu kopieren und Repositories an verschiendenen Orten mit unterschiedlichen forget Policies vorhalten zu können, lokal z.B. eine geringere Vorhaltezeit als remote. Auf restic bin ich in vergangenen Beiträgen schon mal eingegangen: Backups mit restic und Restic Backup Nachtrag - Homedir. Ausserdem wollte ich nochmal mein Backup von $HOME überprüfen um herauszufinden, ob ich etwas verbessern kann. Und ja, da war noch ein bisschen Potential. Rein zufällig hat mir ein Kollege die Tage eine sehr schön humoristische Zusammenfassung der Backupprinzipien zukommen lassen: The Tao of Backup.
- Coverage: Backup ALL your data
- Frequency: Backup frequently
- Separation: Take some backups offsite
- History: Keep some old backups
- Testing: Test your backups
- Security: Secure your backups
- Integrity: Perform integrity checking
In diesem Beitrag werden ich versuchen, die Punkte, soweit möglich, mit restic umzusetzen.
Konfiguration
Die folgenden Befehle richten ein lokales und ein remote Repository bei einem S3 Backend, in meinem Fall Minio, ein. Damit restic die Daten im remote Repository auch deduplizieren kann, benötigt dieses die selben Chunk Einstellungen wie das lokale Repository. Deswegen müssen bei der Erstellung des remote Repositories die Chunk Einstellungen des Lokalen mit dem Parameter --copy-chunker-params übertragen werden.
echo -n "SECRET_PASSWORD" > $HOME/.config/.resticpwd
export RESTIC_PASSWORD_FILE=$HOME/.config/.resticpwd
export RESTIC_REPOSITORY="$HOME/Backup/Repository"
mkdir -p "$RESTIC_REPOSITORY"
restic init
export AWS_ACCESS_KEY_ID=YOUR_AWS_ACCESS_KEY_ID
export AWS_SECRET_ACCESS_KEY=YOUR_AWS_SECRET_ACCESS_KEY
export RESTIC_PASSWORD_FILE2=$RESTIC_PASSWORD_FILE
export RESTIC_REPOSITORY2=s3:PATH_TO_S3_BACKEND/restic
restic -r "$RESTIC_REPOSITORY2" init --repo2 "$RESTIC_REPOSITORY" --copy-chunker-params
systemd Units
Wie so oft setze ich auf systemd, in diesem Fall systemd User Services. Am Ende sollte folgende Dateistruktur vorhanden sein:
$HOME/.config/systemd/user
├── notify-failed@.service
├── restic-backup.service
├── restic-backup.timer
├── restic-check.service
└── restic-check.timer
mkdir -p "$HOME/.config/systemd/user/"
restic-backup.service
Dieser Service erstellt lokale Backups, pusht sie ins remote Repository und entfernt aus dem lokalen Repository die Snapshots die nicht den RETENTION_* Variablen entsprechen.
$EDITOR "$HOME/.config/systemd/user/restic-backup.service"
[Unit]
Description=Restic backup service
OnFailure=notify-failed@%i.service
[Service]
Type=oneshot
Environment=BACKUP_PATHS="%h/Git %h/.ssh/config %h/.local/bin"
Environment=BACKUP_EXCLUDES="--exclude=Code --exclude=google-chrome --exclude=VirtualBox --exclude=ImapMail"
Environment=RETENTION_HOURS=8
Environment=RETENTION_DAYS=5
Environment=RETENTION_WEEKS=0
Environment=RETENTION_MONTHS=0
Environment=RETENTION_YEARS=0
Environment=RESTIC_REPOSITORY=%h/Backup/Repository
Environment=RESTIC_PASSWORD_FILE=%h/.config/.resticpwd
Environment=RESTIC_REPOSITORY2=s3:PATH_TO_S3_BACKEND/restic
Environment=RESTIC_PASSWORD_FILE2=%h/.config/.resticpwd
Environment=AWS_ACCESS_KEY_ID=YOUR_AWS_ACCESS_KEY_ID
Environment=AWS_SECRET_ACCESS_KEY=YOUR_AWS_SECRET_ACCESS_KEY
ExecStart=restic backup --one-file-system --host %H --tag systemd.timer $BACKUP_EXCLUDES $BACKUP_PATHS
ExecStartPost=restic -r "$RESTIC_REPOSITORY" copy --repo2 "$RESTIC_REPOSITORY2" --host %H --tag systemd.timer
ExecStartPost=restic forget --tag systemd.timer --group-by "paths,tags" --prune --keep-hourly $RETENTION_HOURS --keep-daily $RETENTION_DAYS --keep-weekly $RETENTION_WEEKS --keep-monthly $RETENTION_MONTHS --keep-yearly $RETENTION_YEARS
restic-backup.timer
Dieser Time führt den restic-backup.service jede Stunde aus und wartet mit der ersten Ausführung nach Boot 5 Minuten. Das ist wichtig weil nicht immer direkt nach dem Boot das Netzwerk zur Verfügung steht und der Service sich sonst mit einer Fehlermeldung beendet.
$EDITOR "$HOME/.config/systemd/user/restic-backup.timer"
[Unit]
Description=Backup with restic
[Timer]
OnCalendar=0/1:00:00
OnBootSec=5min
Persistent=true
[Install]
WantedBy=timers.target
restic-check.service
Dieser Service überprüft das lokale Repository nach Fehlern. Wie genau es funktioniert ist in der passenden restic Dokumentation beschrieben. Die Überprüfung mit --read-data ist genauer, erfordert aber etwas mehr Rechenleistung und sollte nur beim lokalen Repository gemacht werden da jede Datei einmal "entpackt" wird. Sie würde also vom remote Repository runtergeladen werden. Je nach Größe und Inhalt des Repositories kann ich mir vorstellen, dass der Check etwas länger dauern könnte. Bei mir waren es bisher wenige Sekunden bei Repositories mit bis zu 5GB.
$EDITOR "$HOME/.config/systemd/user/restic-check.service"
[Unit]
Description=Check local restic backup for errors
OnFailure=notify-failed@%i.service
Conflicts=restic-backup.service
[Service]
Type=simple
Nice=10
Environment=RESTIC_REPOSITORY=%h/Backup/Repository
Environment=RESTIC_PASSWORD_FILE=%h/.config/.resticpwd
ExecStart=restic check --read-data
restic-check.timer
Dieser Timer führt den restic-check.service jeden Tag um 12:30 aus und wartet 15 Minuten nach Boot falls der letzte Ausführungszeitpunkt verpasst wurde. Somit hat der Backup Service ca. 10 Minuten Zeit sein erstes Backup nach einem Boot zu erstellen.
$EDITOR "$HOME/.config/systemd/user/restic-check.timer"
[Unit]
Description=Check local restic repository for errors
[Timer]
# Run every day at 12:30
OnCalendar=12:30:00
OnBootSec=15min
Persistent=true
[Install]
WantedBy=timers.target
notify-failed@.service
Damit ich auch mitbekomme, ob ein Service fehlschlug, haben die obigen Services als OnFailure diesen notify-failed@.service eingetragen. Dieser erstellt per notify-send eine generische Popup Meldung, die sich dank -t 0 nicht von alleine schließt, mit Hinweis, welcher systemd Service nicht funktionierte.
$EDITOR "$HOME/.config/systemd/user/notify-failed@.service"
[Unit]
Description=notify-send for %i
[Service]
Type=simple
Environment=DISPLAY=:0
Environment=WAYLAND_DISPLAY=wayland-0
ExecStart=notify-send -t 0 "systemd service %i failed."
Fazit
Vergleichen wir die sieben Punkte des Tao Backups mal mit dem hier umgesetzten.
Coverage (Backup all your data): Ist ok. Könnte bestimmt mehr sein. Müsste ich mehr identifizieren. Aber das wichtigste ist drin.
Frequency (Backup frequently): Jede Stunde finde ich für mein $HOME angemessen.
Separation (Take some backups offsite): Ist momentan nur ein Offsite Backup. Sollte mehr sein. Muss ich mir überlegen, wohin. Wenn ich mehrere Locations habe, wird jede copy Aufgabe wahrscheinlich ein eigener systemd Service.
History (Keep some old backups): Lokal werden ein paar wenige Daten vorgehalten. Remote dafür umso mehr:
RETENTION_HOURS=24
RETENTION_DAYS=14
RETENTION_WEEKS=12
RETENTION_MONTHS=12
RETENTION_YEARS=2
Testing (Test your backups): Mache ich momentan nicht
Security (Secure your backups): Restic verschlüsselt die Backups standardmäßig. Ohne Verschlüsselung funktioniert restic nicht.
Integrity (Perform integrity checking): Findet jeden Tag um 12:30 statt.
Fast alle am Anfang genannten Punkte werden erfüllt. Nur, wie ich gestehen muss, kommt das testen bei mir noch ein bisschen zu kurz. Vlt. hat ja jemand eine Idee, wie das automatisiert werden kann 😉