Workshop: Anatomie eines Backup-Jobs + Demo im Eigenbau
Was genau passiert bei einem Backup? Wir zeigen die Einzelschritte in Theorie und Praxis.
Ein vollwertiges Backup-Programm erledigt eine ganze Reihe einzelner Aufgaben, wie das Kopieren oder Verschlüsseln von Dateien. Wenn Ihr wissen wollt, was genau in einem solchen Werkzeug abläuft, bekommt Ihr hier zwei Ansätze: Zunächst erklären wir die einzelnen Schritte eines Backup-Vorgang in der Theorie. Und dann könnt Ihr ein eigenes Backup-Tool mitbasteln: Jeder Schritt des Backups wird dabei mit einem darauf spezialisiertem Tool erledigt - anders machen es die großen Backup-Suiten übrigens auch nicht. Das hilft nicht nur beim Verständnis, sondern bringt Euch auch ein schon fast einsetzbares Tool!
Theorie: Wie funktionieren Backup-Tools?
Um Backup-Programme wurde immer schon recht viel Wirbel gemacht - kein Wunder: Der Markt ist groß, jeder braucht sie, es geht um Sicherheit und um Vertrauen. Backup-Tool-Hersteller haben immer schon mit Features geworben, aber vor allem um das Vertrauen gebuhlt. Und auch mit hübschen und/oder besonders intuitiven grafischen Benutzeroberflächen wird gerne gepunktet. Die Technik hingegen wird zwar bisweilen gerne in super klingende Marketingbegriffe verpackt, steht aber selten im Vordergrund.
Die eigentliche Technik gibt auch gar nicht so viel her. Nicht, dass da nicht auch viel Finesse im Detail stecken kann, aber die grundsätzlichen Vorgänge bleiben überschaubar. Und so sieht das in Einzelschritten aus:
- Quelle definieren
- Ziel definieren
- Abgleich von Quelle und Ziel
- Komprimieren der Quelle
- Verschlüsseln der Quelle
- Kopieren und löschen von Dateien in Quelle und Ziel
- Validieren des Ziels
Die Punkte und vor allem die Reihenfolge sind natürlich nicht in Stein gemeißelt. Und das Verschlüsseln beinhaltet oft auch schon das Kopieren. Aber mal im Detail:
Quelle definieren heißt einfach nur, dass festgelgt wird, welche Dateien gesichert werden sollen. Das beinhaltet in der Regel zum einen Dateien, die eingeschlossen werden und zum anderen Dateien, die ausgeschlossen werden. Also beispielsweise der Ordner "Meine_Daten", aber ohne Dateien, die auf "*.tmp" enden.
Ziel definieren meint etwas noch Trivialeres: Den Speicherort. Dabei kann das Backup entweder als ein großes Archiv in einer einzelnen Datei erscheinen oder als Ordnerstruktur, die die Quelle nachbildet.
Komprimieren muss man freilich nicht, aber gezippte Dateien verbrauchen weniger Platz - es gibt keinen Grund, es nicht zu tun.
Verschlüsseln ist ebenso optional, und ebenso essenziell: Backups liegen meist nicht in der eigenen Wohnung, sondern auf einem Server, in der Cloud oder auch einfach auf einer mobilen Festplatte in der Handtasche. Es könnte also passieren, dass Fremde Zugriff darauf bekommen. Und da man meist nur Wichtiges backuppt, sollte die Daten selbst dann niemand einsehen können.
Kopieren und löschen sollte zumindest zur Hälfte klar sein: Die komprimierten und verschlüsselten Quelldateien werden ins Ziel kopiert. Gelöscht wird unter Umständen aber auch. Zum Beispiel, wenn eine alte Datei in der Quelle gelöscht wurde, die früher schon mal ins Ziel gesichert wurde. Man kann solche Dateien freilich auch behalten, aber das Archiv wird dann für immer wachsen und wachsen!
Wie oben schon erwähnt: Beim Verschlüsseln oder auch beim Komprimieren können Dateien natürlich direkt irgendwo hin verschlüsselt/komprimiert werden - was einen separaten Schritt für das Kopieren überflüssig macht. Im Praxisbeispiel folgen aber alle Schritte separat, der Nachvollziehbarkeit halber.
Validieren soll zum Schluss sicherstellen, dass das Ziel der Quelle entspricht - schließlich kann beim Kopieren mal ein Byte verloren gehen.
Praxis: Backup-Tool im Eigenbau
Natürlich müssen wir hier etwas vereinfachen: Das Tool ist eine Demo-Anwendung zum Verstehen! Alles bleibt so einfach wie nur möglich, aber ohne Schritte auszulassen. Das "Programm" wird am Ende Quelldateien komprimieren, verschlüsseln und ins Ziel kopieren, sofern es im Ziel nur ältere oder noch gar keine Backup-Versionen dieser Dateien gibt. Und validiert wird natürlich auch.
Und daher nochmal zurück zur obigen Ablauffolge - diesmal mit den Tools, die das bewerkstelligen sollen:
- Quelle definieren: find
- Ziel definieren: mkdir, dirname
- Abgleich von Quelle und Ziel: test (bash)
- Komprimieren der Quelle: gzip
- Verschlüsseln der Quelle: gpg
- Kopieren und löschen von Dateien in Quelle und Ziel: rm, mv
- Validieren des Ziels: sha1sum
Zusammengehalten wird das Ganze durch ein ganz klein wenig Shell-Scripting. Arbeitsort wenn man so will ist der Terminal, genauer gesagt eine Bash-Sitzung: Unter Debian, Ubuntu, Linux Mint und so weiter stehen Euch die Tools in der Regel standardmäßig zur Verfügung. Unter Windows könnt Ihr zum Beispiel Git für Windows installieren, damit bekommt Ihr eine vollwertige, gut ausgestattete Bash-Konsole. Alternativ könnt Ihr auch native Windows-Ports nutzen oder gleich mit dem in Windows eingebetteten Linux arbeiten.
Es handelt sich ausschließlich um etablierte Standardwerkzeuge - und wie gesagt Spezialisten: gzip macht nichts weiter, als sich um Komprimierung zu kümmern, gpg um nichts als Verschlüsselung, sha1sum nur um die Validierung und so weiter. Nebenbei: Das ist eines der Software-Grundprinzipien aus der Unix-Welt: Mache eine Sache und mache sie gut! In vielen auch kommerziellen Produkten stecken nicht selten einfach gpg, tar und ähnliche Open-Source-Tools unter einer schicken grafischen Oberfläche.
Und wieder geht's ins Detail. Zunächst die einzelnen Schritte, im Anschluss das komplette Skript. Hier läuft das Ganze übrigens mit eben besagter Git-Bash - daher die Windows-Pfadangaben.
1. Quelle definieren
In vielen Fällen genügt ein simpler ls-Befehl, um eine Liste mit zu verarbeitenden Dateien zu bekommen. Da hier aber explizit Dateien ein- und ausgeschlossen werden sollen, kommt das etwas unzugänglichere Tool find zum Einsatz. Der Einfachheit halber sollen alle Dateien unterhalb des Verzeichnisses "quelle" (festgehalten in der Variablen $quelle) gesichert werden. Ausnahme: Dateien, die auf .tmp enden:
find $quelle -type f ! -name "*.tmp"
Über type -f wird nach Dateien gesucht und über ! -name (das ! steht für NICHT) werden Dateien ausgeschlossen, und zwar solche mit .tmp-Endung. Das ließe sich an der Stelle natürlich unendlich verfeinern, denn find verträgt beliebig viele solcher Filter und Argumente.
Die gefundenen Dateien werden dann nacheinander zur Verarbeitung in der Variablen $f festgehalten - samt Pfad! Das Wie folgt am Ende, das gehört zum Scripting-Part.
2. Ziel definieren
Das eigentliche Speicherziel wird am Ende beim Kopieren/Verschieben angegeben. Aber es muss zusammengebaut werden: Im Ziel-Ordner sollen nämlich in der originalen Verzeichnisstruktur landen. Eine Datei quelle/meinordner/foo.txt soll also unter ziel/meinordner/foo.txt gespeichert werden. Da diese Strukturen beim Kopieren (mit den gewählten Tools ...) nicht mit angelegt werden, müsst Ihr sie manuell erstellen:
mkdir -p $ziel/$(dirname $f)
mkdir -p legt einfach Ordner samt Eltern-Ordner (p für parent) an. In $ziel ist wieder schlicht der Pfad gespeichert. Interessant ist dirname: Mit dem Befehl wird der komplette Pfad der zu verarbeitenden Datei ($f) ausgelesen -, aber eben ohne den Dateinamen selbst. Und so entsteht unterhalb von Ziel die komplette Ordnerstruktur der Quelle.
$f sieht dann zum Beispiel so aus:
/d/quelle/foobar.txt
Und dirname entsprechend:
/d/quelle/
Das etwas ungewöhnliche /d/ steht schlicht für Laufwerk D, würde unter Windows also standardmäßig D:\ notiert - in der Git-Bash aber natürlich in Linux-Schreibweise.
3. Abgleich Quelle und Ziel
Auch hier bleibt es wieder simpel: Dateien sollen verarbeitet werden, wenn sie neuer als ihr Backup sind oder noch gar kein Backup existiert:
[ $f -nt $ziel/$f ] || [ ! -e $ziel/$f ]
In den eckigen Klammern stehen jeweils Bedingungen und || steht für ODER. Bedingung 1: Die zu verarbeitende Datei ($f) soll neuer als (newer than) als ihre Kopie im Ziel sein. Bedingung 2: Die Datei existiert im Ziel gar nicht (!). Ist eine der beiden Bedingungen erfüllt, wird die Datei gesichert.
4. Komprimieren
Das Komprimieren ist unfassbar simpel:
gzip -k $f
Das -k steht für keep und heißt einfach, dass die Originaldatei behalten wird - anschließend habt Ihr also nebeneinander eine Datei foobar.txt und foobar.txt.gz im Quellordner.
5. Verschlüsseln
Und auch das Verschlüsseln ist trivial:
gpg -c --passphrase=test $f.gz
Das -c läutet die simple symmetrische Verschlüsselung via Passwort ein, das auch direkt folgt. Und $f.gz ist die eben erstellte gzip-Version der Datei, also beispielsweise foobar.txt.gz.
Jetzt habt Ihr folgende Dateien:
foobar.txt
foobar.txt.gz
foobar.txt.gz.gpg
Die gz-Variante braucht Ihr natürlich nicht mehr, gesichert wird nur die verschlüsselte gpg-Datei und das txt-Original verbleibt an Ort und Stelle. Also:
rm $f.gz
6. Validieren 1
Validiert wird am Ende, aber damit im Ziel validiert werden kann, muss erstmal eine Checksumme her: Ein Algorithmus berechnet für die Datei eine solche Prüfsumme, auch Hash genannt, und speichert das Ergebnis in eine Datei, samt dem Namen der zugehörigen Datei:
sha1sum $f.gz.gpg > $f.gz.gpg.sha1
Und Ihr ahnt es, nun gibt es auch noch die Datei foobar.txt.gz.gpg.sha1. Im Ziel wird dann gleich nochmal sha1sum ausgeführt und das Ergebnis mit der sha1-Datei verglichen.
Ein kleines Oh Oh: Der Text in der sha1-Datei sieht zum Beispiel so aus:
123abc456def */d/quelle/foobar.txt.gz.gpg
Der Pfad stimmt aber natürlich nicht mehr, wenn die hier angegebene gpg-Datei erstmal im Zielordner liegt!
ist: /d/quelle/foobar.txt.gz.gpg
soll: /d/ziel/d/quelle/foobar.txt.gz.gpg
Von daher wird hier jetzt kurz und dreckig ziel durch ziel/d/quelle ersetzt - nicht schön, aber fix:
sed -i 's/quelle/ziel\/d\/quelle/' $f.gz.gpg.sha1
-i verändert die Datei (sonst würde nur im Terminal ausgegeben), hinten wird die sha1-Datei angegeben und der sed-String: s ist das Ersetzen-Kommando, zwischen den nächsten beiden / folgen Original und Ersatz, also s/original/ersatz/. Der Ersatz hier, ziel\/d\/quelle, sieht nur so komisch aus, weil die / von ziel/d/quelle mit \ "escaped" werden müssen - sonst würde sed sie als Befehle verstehen.
7. Kopieren/Verschieben
Kopiert werden jetzt nur Daten - auf Dateiebene wird verschoben, und zwar: Natürlich die gpg- und sha1-Dateien:
mv $f.gz.gpg* $ziel$(dirname $f)
Mit dem Sternchen hinter gpg werden die sha1-Dateien gleich mit erfasst und in die Verzeichnisstruktur unterhalb des Ziel-Ordners verschoben, die Ihr oben mit mkdir angelegt habt.
7. Validieren 2
Validieren ist nun wieder einfach, nachdem der Pfad in den sha1-Dateien oben korrigiert wurde:
sha1sum -c $f
Hier wird einfach die in der sha1-Datei angegebene gpg-Datei nochmal geprüft und das Ergebnis mit dem hinterlegten Ergebnis in der sha1-Datei verglichen. Wenn sie übereinstimmen, stimmen auch die gpg-Dateien in Ziel und Quelle hundertprozentig überein.
Scripting
Das Ganze muss nun natürlich noch zusammengenagelt werden: $quelle und $ziel werden festgelegt, find wird in einer for-Schleife ausgeführt und für jede von find gefundene Datei schaut eine if-Abfrage, ob die Quelldatei neuer als die Zieldatei oder die Zieldatei nicht vorhanden ist. Zwei echo-Befehle liefern noch ein wenig Infos. Neu ist auch der Befehl basname, quasi das Gegenstück zu dirname, der schlicht den Dateinamen ohne Pfad ausgibt.
Anschließend folgt das Validieren in einer separaten for-Schleife.
quelle=/d/quelle
ziel=/d/ziel
for f in $(find $quelle -type f ! -name "*.txt")
do
if [ $f -nt $ziel/$f.gz.gpg ] || [ ! -e $ziel/$f.gz.gpg ]
then
echo -e "Verarbeitung $(basename $f) \n\n"
mkdir -p $ziel/$(dirname $f)
gzip -k $f
gpg -c --passphrase=test $f.gz
rm $f.gz
sha1sum $f.gz.gpg > $f.gz.gpg.sha1
sed -i 's/quelle/ziel\/d\/quelle/' $f.gz.gpg.sha1
mv $f.gz.gpg* $ziel$(dirname $f)
else
echo -e "Übersprungen: $(basename $f) \n\n"
fi
done
for g in $(find $ziel -type f -name "*.sha1")
do
sha1sum -c $g
done
Da überall mit absoluten Pfaden gearbeitet wird, könntet Ihr das Skript aus beliebigen Ordnern ausführen, es zum Beispiel in den Windows-Aufgabenplaner stecken.
So also funktionieren Backups - grob
Damit habt Ihr nun im Groben gesehen, wie ein Backup-Programm grundsätzlich arbeitet, beziehungsweise arbeiten kann! In der Praxis ließen sich Anweisungen zum Beispiel auch direkt von find ausführen. Vor allem aber könnte man ein Tool wie 7-Zip nehmen und allein damit ein Backup umsetzen - vergleichen, versschlüsseln, komprimieren und validieren kann 7-Zip nämlich ganz allein. Auch tar würde Optionen für Updates bieten.
Vor allem müsste man für den Praxiseinsatz noch viel der oben erwähnten Finesse einbringen, beispielsweise für komplexere Dateivergleiche, Fehlermeldungen, kontrollierte Programmausstiege, schlankeren Code, Versionierung, Performance, inkrementelle Backups, Journale und und und - bis hin zur zweiten Seite der Medaille: Im Grunde bräuchtet Ihr auch noch ein kleines Wiederherstellungsskript.
Aber Sinn der Sache war ja: Jeden Schritt einzeln und mit einem spezialisierten Tool durchführen. Wie schon erwähnt: Auch viele "echte" Softwareprodukte, freie wie kommerzielle, nutzen unter ihren grafischen Oberflächen einfach nur ein paar solcher Kommandozeilenwerkzeuge. Und das gilt nicht nur für Backup-Tools versteht sich.
Und auch wenn das Skript in der obigen Form natürlich nur ein Rohentwurf ist: Die verwendeten Tools sind grundsolide, laufen Teils seit Jahrzehnten und wie man sie miteinander verbindet, habt Ihr auch gesehen - Ihr könnt hier also durchaus ansetzen und etwas Sinnvolles fertigstellen. Nun, oder auch einfach bessere Kaufentscheidungen treffen, falls Ihr doch lieber zum Kommerz greift ;)
Und wenn Ihr mit Kommandozeilen-Tools ab und an Hilfe braucht, schaut mal bei unserer hauseigenen Linux-Hilfe für den Terminal vorbei - cli.help