Rotierendes Backup mit rsync und Links

In diesem Beitrag beschreibe ich meine persönliche Backupphilosophie und das von mir genutzte Skript zum Rotieren der Backups. Ziel ist ein Backupsystem, welches mit möglichst einfachen (Bord-) Mitteln auskommt.

Ich gebe zu, mit meinen Daten bin ich paranoid. Ich halte wichtige Daten auf bis zu sechs verschieden Speichersystemen in vier verschiedenen Orten in drei verschiedenen Städten vor …1 Jede Nacht gehen die Daten dann spazieren …

Daten speichere ich ausschließlich im (lokalen) Netz. Auf den Rechnern befinden sich nur Programme und Daten, die aktuell benötigt werden. Als Speichermedien nutze ich seit Jahren verschiedene Arten von Raidsystemen.2 Vereinfacht gesagt sind das Geräte mit mehreren Festplatten. Fällt eine Festplatte aus, sind immer noch alle Daten verfügbar und die defekte Festplatte kann ersetzt werden. Ich habe mehrere Jahre Drobos genutzt. Allerdings hatte ich ein recht unschönes Erlebnis mit einem Drobo, bei dem eine Festplatte defekt war und der Drobo hiermit überfordert war. Ich habe damals zwar keine Daten, wohl aber das Vertrauen verloren. Seit dem nutze ich DiskStations von Synology. Die Drobos verwende ich weiterhin – allerdings nur noch im dritten Glied …

Ein Raid-System schützt zwar (relativ gut) vor Festplattenausfällen. Es hilft aber nicht, wenn Daten bewusst oder aus Versehen gelöscht werden. Ein Raidsystem ersetzt also kein Backupsystem.

Meine Anforderungen an ein Backupsystem sind sehr einfach: Ich muss es verstehen und im Ernstfall ohne irgendwelchen Aufwand Daten zurückspielen können. Konkret will ich im V-Fall mit einem einfachen Dateimanager auf die Daten zugreifen können. Irgendwelche komplizierten inkrementalen Backups, bei denen ich mir im V-Fall die Daten mühsam über verschiedene Backupgenerationen restaurieren muss, sind deshalb nicht mein Fall. Backupgenerationen ist allerdings ein durchaus relevantes Stichwort: Ich möchte auf vergangene Versionen meines Backups zurückgreifen können. Der Ernstfall sieht für mich folgendermaßen aus: Ein bösartiger Makrovirus hat den Weg in meine Buchhaltungsdaten gefunden. Ich will nun auf die letzte virenfreie Version von gestern / vorletzter Woche / vor zwei Monaten zugreifen können.

Weiter gehe ich davon aus, dass wenn das Unglück zuschlägt, es richtig zuschlägt. Das zu berücksichtigende Szenario ist deshalb ein Hausbrand: Da hilft es wenig, wenn im Keller ein Backupsystem vorhanden ist … Mein Backupsystem setzt deshalb zunächst auf mehrfache Redundanz. Die Daten werden zunächst vor Ort auf ein zweites Systemen gesichert. Außerdem sichere ich die Daten über das Internet an verschiedenen Orten.

Für den Datenabgleich nutze ich rsync.3 Dabei handelt es sich um eines jener UNIX-Standardprogramme, die seit Jahrzehnten weltweit im Einsatz sind und ihre Aufgabe zuverlässig erfüllen. Ein großer Vorteil ist, dass die Daten beim Transport automatisch verschlüsselt werden. Ein weiterer Vorteil ist, dass jeder Mac und jedes Linux-System (einschließlich der Synology DiskStation oder des Drobos) mit vorinstallierten Versionen von rsync ausgeliefert werden. Unter Windows lässt sich rsync über cygwin ebenfalls einfach nutzen. Im Ernstfall muss man – jedenfalls, wenn man ein vernünftiges Betriebssystem verwendet – also nicht erst noch irgendein Programm einspielen.

Die erste Stufe meines Backupkonzepts besteht also aus einer Reihe von Skripten die per rsync Daten zwischen verschiedenen Systemen hin-und-her-schieben. Ein Skript rsynct etwa die Kanzleidaten und die Daten von meinem Rootserver zu meinem „privaten“ System. Von dort werden die Daten dann auf verschiedene (weitere) Backupsysteme gersynct. Die privaten Daten gehen den umgekehrten Weg und werden u. a. auf ein System, welches in der Kanzlei sitzt, gersynct.

Zu Erstellung verschiedener Backupstände nutze ich sogenannte symbolische Links.4 Dabei wird eine Datei nicht kopiert, sondern es wird lediglich ein Verweis auf die Datei erzeugt. Die Daten sind also nicht wirklich doppelt auf dem System vorhanden, erscheinen aber in zwei oder mehr Verzeichnissen. Löscht man die Datei in einem Verzeichnis, ist sie im anderen noch vorhanden. Man kann also annähernd beliebig viele Verweise auf eine Datei erzeugen, ohne dass der Speicherbedarf spürbar ansteigen würde.

Ein fertiges System, welches exakt die gleiche Technik nutzt, ist rsnapshot. Ich habe es selbst mehrere Jahre eingesetzt – und mir die Technik letztlich hiervon abgeschaut. Der einzige Nachteil von rsnapshot ist, dass sich das Zielverzeichnis auf dem System befinden muss, auf dem rsnapshot läuft. Ich möchte meine Backups aber von einem zentralen System aus steuern und auf andere Geräte verteilen. Außerdem kommt mein Skript zum Rotieren der Backups mit minimalen Systemanforderungen aus – und läuft etwa auch auf einem alten DroboFS …

Das Skript ist in Bash-Skript geschrieben und sollte dementsprechend auf einer großen Zahl von Geräten laufen – etwa auf einem Mac, der Synology DiskStation oder einem DroboFS.

Nota bene: Ich bin Anwalt, kein Programmierer. Das Skript funktioniert für mich. Eventuell funktioniert es auch für Sie – das müssen Sie auf eigenes Risiko herausfinden. Ich übernehme keine Haftung für irgendwelche Sach- oder Personenschäden!

#!/bin/sh
QUELLE=$1
ZIEL=$2
SET=$3
ANZAHL=$4

LOCKFILE=$(basename $0).lock
[ -f $LOCKFILE ] && {
  echo "$(basename $0) laeuft schon" | tee -a $LOGFILE;
  exit 1;
}
touch $LOCKFILE

if [ $# -ne 4 ]
then
  echo "backrotate QUELLE ZIEL SET ANZAHL"
  echo "Z.B.: backrotate /volume1/aktuell /volume1 taeglich 7"
  echo "QUELLE und ZIEL ohne abschliessendes /"
  exit 1
fi

[ ! -d $QUELLE ] && {
  echo "$QUELLE existiert nicht!";
  exit 1
}

[ ! -d $ZIEL ] && {
  echo "$ZIEL existiert nicht!";
  exit 1
}

[ ! -d $ZIEL/$SET ] && {
  echo "$ZIEL/$SET wird erstellt!";
  mkdir $ZIEL/$SET
}

[ -d $ZIEL/$SET/$ANZAHL ] && {
  echo "Loesche $ZIEL/$SET/$ANZAHL";
  rm -rfv $ZIEL/$SET/$ANZAHL
}

i=$ANZAHL
while [ $i -gt 1 ]
do
  [ -d $ZIEL/$SET/$(($i-1)) ] && {
    echo "Verschiebe $ZIEL/$SET/$(($i-1)) nach $ZIEL/$SET/$i";
    mv $ZIEL/$SET/$(($i-1)) $ZIEL/$SET/$i
    touch $ZIEL/$SET/$i
  }
  i=$(($i - 1))
done

echo "Kopiere $QUELLE $ZIEL/$SET/1"
cp -al $QUELLE $ZIEL/$SET/1

rm $LOCKFILE

In den Zeilen 2-5 werden die Parameter eingelesen, die beim Start übergeben wurden.
QUELLE: Das Verzeichnis mit den aktuellen Daten, die gesichert werden sollen.
ZIEL: Das Backupverzeichnis.
SET: Eine Bezeichnung für das Backupset – also etwa taeglich, woechentlich, monatlich.
ANZAHL: Zahl der Backups, die erstellt werden sollen. Etwa 7 für die täglichen Backups, 5 für die wöchentlichen und 36 für die monatlichen.

In den Zeilen 7-12 wird ein Lockfile angelegt. Existiert der Lockfile, läuft das Skript bereits und es wird mit einer Fehlermeldung abgebrochen. So wird verhindert, dass verschiedene Versionen des Skriptes parallel gestartet werden und Chaos entsteht.

In den Zeilen 14-20 wird überprüft, ob vier Parameter übergeben wurden. Ist das nicht der Fall, wird ein kurzer Hilfetext ausgegeben.

In den Zeilen 22-30 wird geprüft, ob das Quell- und das Zielverzeichnis existieren und es wird ggf. mit einer Fehlermeldung abgebrochen.

In den Zeile 32-35 wird geprüft, ob das Verzeichnis für das Set (also beispielsweise /Backup/woechentlich/) existiert. Ggf. wird das Verzeichnis angelegt.

In den Zeilen 37-40 wird zunächst geprüft, ob das letzte Backup der Reihe (also beispielsweise /Backup/woechentlich/5/) bereits erstellt wurde. Ist das der Fall, wird das Verzeichnis gelöscht.

In den Zeilen 42-51 werden schließlich die Backups rotiert:
/Backup/wochentlich/4/ wird nach /Backup/woechentlich/5/ verschoben,
/Backup/wochentlich/3/ wird nach /Backup/woechentlich/4/ verschoben,
/Backup/wochentlich/2/ wird nach /Backup/woechentlich/3/ verschoben und
/Backup/wochentlich/1/ wird nach /Backup/woechentlich/2/ verschoben.

In der Zeile 54 wird schließlich das Verzeichnis mit den aktuellen Daten in das Verzeichnis /1/ (also etwa /Backup/wochentlich/1/) kopiert. Der Parameter -a sorgt dafür, dass alle Einstellungen (z. B. hinsichtlich des Eigentümers oder des Datums) erhalten bleiben. Der Parameter -l bewirkt, dass die Dateien nicht „wirklich“ kopiert werden, sondern Links erzeugt werden.

In der letzten Zeile wird schließlich der Lockfile wieder gelöscht.

In meinem Backupsystem wird der gesamte Backupvorgang über ein System zentral gesteuert. Das backrotate-Skript läuft allerdings auf dem Backupsystem. Das Skript muss deshalb ferngesteuert aufgerufen werden. Das ist über ssh aber kein Problem. Um das Ganze für mich übersichtlicher zu gestalten, binde ich hierzu das backrotate-Skript in kleine Skripte für taeglich, woechentlich und monatlich ein. Das Skript für das tägliche Backup sieht etwa folgendermaßen aus:

#!/bin/sh

#
# Hier werden die verschiedenen Skript für die diversen Backupaufgaben aufgerufen.
#

ssh SYSTEM "/volume1/bin/backrotate /volume1/aktuell /volume1 taeglich 7"

SYSTEM ist dabei der Name bzw. die IP-Adresse des Backupsystems. Für das wöchentliche Skript würde die entsprechende Zeile:

ssh SYSTEM "/volume1/bin/backrotate /volume1/aktuell /volume1 woechentlich 5"

lauten und für das monatliche Skript:

ssh SYSTEM "/volume1/bin/backrotate /volume1/aktuell /volume1 monatlich 36"

Die Skripte werden schließlich über Cronjobs gesteuert. Die entsprechenden Einträge sehen bei mir folgendermaßen aus:

0       1       *       *       *       root    /volume1/bin/backup_taeglich
0       12      *       *       0       root    /volume1/bin/backup_woechentlich
0       18      1       *       *       root    /volume1/bin/backup_monatlich

Das tägliche Skript wird jeden Tag um 1 Uhr nachts gestartet. Das wöchentliche Skript startet am Sonntag um 12 Uhr (bis dahin sollte das tägliche Skript abgeschlossen sein) und das monatliche jeweils am 1. des Monats um 18 Uhr.

Notes:
1. … wobei hier noch genügend Raum für Paranoia ist; muss ich doch zugeben, dass sich alle Städte auf dem gleichen Kontinent befinden – hier wäre also durchaus noch Raum für Optimierungen.
2. Mehr erfahren Sie in der Wikipedia.
3. Eine gute Einführung liefert das Wiki der UbuntuUsers.de.
4. Voraussetzung ist freilich, dass das Filesystem symbolische Links kennt. Das ist bei HFS+, dem Filesystem des Mac, oder ext3 welches etwa von der DiskStation oder dem Drobo genutzt wird der Fall.