== Übersicht ===
- Einführung
- Voraussetzungen
- Erstellung des Backupscripts
- Aktivieren des regelmäßigen Backups
- Zurückspielen des Backups
- Erweiterungen
- Benutzung des Backupscripts raspiBackup
== Einführung ===
Sobald man seine Pi endlich so eingerichtet und konfiguriert hat, dass sie zuverlässig Ihre Ihr zugewiesenen Aufgaben erfüllt wird es Zeit sich Gedanken zu machen, wie man immer automatisch einen aktuellen Backup erstellen kann, damit im Notfall, falls Daten verloren gehen oder die SD Karte ihren Geist aufgibt, sehr schnell die Pi wieder mit dem Backup zum Leben erwecken kann.
Die Backupmethode und wie häufig und wieviele Backups man erstellt hängt davon ab, wie aktuell die Backups sein müssen, wie die Bandbreite zum Backupmedium ist, wieviel Platz auf dem Backupmedium vorhanden ist und ob man auf ältere Datenstände der Pi in bestimmten Fällen zurückgreifen muss.
Dieses Tutorial beschreibt, wie man recht einfach die Pi dazu bringen kann, sich regelmäßig selbst zu sichern. Voraussetzung dafür ist, dass vor der Sicherung alle aktiven Programme wie xbmc, Apache, mysql, samba, nfs-server usw vorher beendet werden. Dann ist einzig und allein ein externes Speichermedium, welches an die Pi direkt per USB oder per Netz angeschlossen ist, notwendig. Das kann eine USB Platte, irgendein NAS Speicher im Netz wie eine Fritzbox, eine richtige NAS Box, ein anderer ständig laufender Rechner im Netz oder eine Cloud welche per davfs zugreifbar ist, sein. Diese müssen dann ihren Speicher per nfs (Linux) oder samba bzw cifs (Windows) anbieten oder einen ssh Zugang anbieten der von rsync (Linux) benutzt werden kann.
Am Ende des Tutorials hat man seine Pi so konfiguriert, dass sie automatisch regelmäßig einen Backup von sich selbst erstellt welches dann sowohl unter Windows als auch Linux benutzt werden kann um sie wiederzubeleben. Ausserdem wird parallel eine kleine Einführung in Linux bash Programmierung gegeben, denn um die Aufgabe zu erfüllen muss ein kleines bash Script erstellt werden. Es ist nicht schwer und was man lernt hilft zukünftige eigene Automatisierungsaufgaben selbst anzugehen und zu lösen. Wer kein Interesse hat ein wenig die bash Programmierung kennenzulernen und sich einzuarbeiten findet hier hier ein fertiges Script zum Download, welches ich selbst zum Sichern und Wiederherstellen meiner Pis benutze. Wie man dann das Backup wieder restored wird dann natürlich auch für dd und tar beschrieben.
Backups kann man mit dd, tar oder rsync anlegen. dd sichert die gesamte SD Karte während tar nur die wirklich existierenden Daten sichert. D.h. wenn eine SD Karte 8 GB hat werden mit dd auch 8 GB gesichert während mit tar nur die tatsächlichen Daten gesichert werden. Meine raspxbmc hat eine 8GB SD Karte, deren tar Sicherung 300MB belegt. Der Nachteil mit tar ist, dass man dazu auch ein Linux System braucht, um die Daten im Backupfall wieder zu erhalten. Dazu kann man aber die Pi mit einem raspbian nehmen. Bei rsync wird noch weniger gesichert denn dieses sind nur die geänderten Daten. Deshalb geht das Backup mit rsync i.d.R. noch sehr viel schneller. Man kann eine Pi mit Hilfe einer anderen Pi wieder aus einem dd, tar oder rsync Backup restaurieren lassen. Ein dd Backup kann man auch mit Windows wieder zurückspielen.
Wenn man ein laufendes Linux System sichern will, sollten erst alle aktivern Anwendungen gestoppt werden, da sonst inkonsistente Backups entstehen können. D.h. dass besonders Dienste wie samba, apache, owncloud, mysql usw vorher gestoppt werden sollten. Nach erfolgreichem Backup können alle gestoppten Dienste wieder gestartet werden.
=== Voraussetzungen ===
1) Eine laufende Pi mit raspian
2) Ein gemountetes externes Speichermedium und dort ein Unterverzeichnis in welchem die Backups abgelegt werden
=== Erstellung des Backupscripts ===
In der folgenden Beschreibung wird angenommen, dass das ein Backupmedium unter /backup gemountet wurde und darin ein Verzeichnis raspi existiert.
Das Backuperstellen ist ein Aufruf von dd, tar oder rsync. Damit das dann auch regelmässig erstellt wird gibt es in Linux cron, der schon in einem Tutorial (siehe Tutorial zu cron) beschrieben wurde. Dort trägt man einen Befehl ein, der regelmäßig zu bestimmten Zeiten auszuführen ist. Da auch noch dafür gesorgt werden muss, dass nicht unendlich viele Backups sondern nur eine maximale Anzahl erstellt werden, ist es geschickter, ein kleines bash Script zu erstellen, welches den eigentlichen Backupvorgang steuert und dieses über cron aufrufen zu lassen. Der Vorteil ist auch dass man dieses Script auch manuell in der Konsole aufrufen und damit testen kann.
Ein bash Script beginnt immer mit
denn damit wird festgelegt, dass alle folgenden Zeilen der bash Sprachbeschreibung (Syntax) folgen. Alternativ kann man da auch andere
Sprachen festlegen wie
oder
und die folgenden Zeilen müssen dieser Sprachbeschreibung von Python der Perl folgen.
Um das Script aufrufen zu können sind noch folgende Massnahmen notwendig:
Annahme: Das Script soll backup.sh heissen
1) Erstellen des Scripts backup.sh mit einem Editor
2) chmod +x backup.sh
Den Aufruf des Scripts nimmt man dann mit
vor. ACHTUNG: Der Punkt am Anfang ist notwendig!
Will man das Script debuggen und sehen welche Befehle tatsächlich ausgeführt werden ist der folgende Scriptaufruf sinnvoll:
bzw wenn man noch weitere Details der bash Ausführung sehen möchte
Das einfachste bash Script ist einfach eine Aneinanderfolge von Befehlen, die man in der Konsole eingeben kann. Damit kann man mit der folgenden Zeile sehr einfach eine Backup der gesamten SD Karte anstossen:
Am Ende existiert die Datei MeinBackup.img unter/backup/raspi die leicht per dd oder den entsprechnden Windows Tools wieder auf eine andere SD Karte zurückgespielt werden kann. Der Nachteil ist, dass immer nur ein Backup MeinBackup.img existiert. Normalerweise will man wenigstens drei Backups vorhalten. Deshalb muss man den Name der Datei mit dem aktuellen Datum und der Zeit versehen.
Dazu gibt es das date Kommando und mit
bekommt man das aktuelle Datum sowie die aktuelle Zeit.
In ein bash Script kann man den Aufruf von date wie folgt einbinden um einen Backupfilenamen mit Datum und Uhrzeit zu erstellen:
Alles was in $(...) steht wird ausgeführt und das Ergebnis dann in der Zeile im Script ersetzt. Z.B. würde momentan (16.6.2013 um 22:39:27) das Ergebnis des Befehls, wenn das Script ausgeführt würde, wie folgt aussehen:
D.h. es wird bei jedem Backuplauf eine neue Datei erstellt und man kann aus dem Namen erkennen, wann es erstellt wurde. Das führt aber zu einer Invasion von Backups und sprengt über kurz oder lang die Speicherkapazität des Backupmediums. Deshalb müssen nach dem Erstellen des Backups alte nicht mehr benötigte Backups gelöscht werden.
Eine Lösung ist die Hintereinanderschaltung von 3 Befehlen mit dem Pipe Operator |: Dadurch wird das Ergebnis des vorhergehend Befehls jeweils in den folgenden Befehl weitergeleitet und so gefiltert und bearbeitet, dass die Kombination der einfachen Linux Befehle zusammen ein komplex zu berechnendes Ergebnis liefern (Siehe auch Unix Philosophie)
Was macht diese Zeile? Zum Ausprobieren sollte man ein neues Verzeichnis, z.B. Test erstellen und dort Testdateien erstellen mit
In diesem Verzeichnis zeigt dann
alle Dateien in dem aktuellen Verzeichnis an und zwar aufsteigend nach dem Datum sortiert.
filtert aus dieser Liste von Zeilen alle bis zu 3ten Zeile und man erhält damit die Dateien, die älter als die ersten 3 neuesten Dateien sind und welches die zu löschenden Dateien sind. Gibt es weniger ist die Liste leer.
in dem o.g. Verzeichnis mal ausführen.
Mit
werden die Zeilen, die als Eingabe zu dem Befehl geliefert werden alle dem Befehl
als Argument mitgegeben. Somit werden alle Dateien, die älter sind als die ersten 3 neuen Dateien gelöscht. Ausprobieren sollte man das nicht in einem Verzeichnis wo man die Dateien behalten will aber wenn man den Befehl etwas ändert in
wird nur angezeigt welcher rm Befehl ausgeführt werden würde aber der rm Befehl an sich nicht ausgeführt. Diesen Befehl kann man im Verzeichnis Test ausführen und sieht dann welche Dateien gelöscht werden würden.
Ruft man nun den folgenden Befehl auf
bleiben die 3 neuesten Dateien übrig. Alle anderen Dateien werden nun gelöscht.
Damit man sich Schreibarbeit erspart und auch schnell mal zum Testen die Pfade ändern kann benutzt man im bash Script Variablen, die einmal mit Werten versehen werden und dann überall im Script benutzt werden. Dadurch ist eine Änderung nur an einer Stelle notwendig.
Variablen werden in bash definiert mit
und an der Benutzungstelle im Script muss dann der Variablenname mit vorangestelltem $ und geschweiften Klammern stehen wie z.B.
Die Anzahl der Backups sowie den Backupnamen sollte man auch noch variabel machen. Somit muss in dem Script folgendes stehen:
#!/bin/bash
BACKUP_PFAD="/backup/raspi"
ANZAHL_BACKUPS="3"
BACKUP_NAME="MeinBackup"
dd if=/dev/mmcblk0 of=${BACKUP_PFAD}/${BACKUP_NAME}-$(date +%Y%m%d-%H%M%S).img bs=1MB
pushd ${BACKUP_PFAD}; ls -tr ${BACKUP_PFAD}/${BACKUP_NAME}* | head -n -${ANZAHL_BACKUPS} | xargs rm; popd
Das sieht zwar im ersten Moment mit den vielen $ und {} verwirrend aus - aber man gewöhnt sich an die Schreibweise und erhält dadurch auch eine Menge Vorteile.
Die Befehle pushd und popd sorgen dafür, dass man temporär in ein Verzeichnis mit pushd wechselt und mit popd wieder im vorherigen Verzeichnis landet. Das ist notwendig damit man nicht im falschen Verzeichnis - dem aktuellen - alle Dateien bis auf die aktuellsten 3 löscht. Wichtig ist, dass dass Verzeichnis nach pushd angegeben auch tatsächlich das Verzeichnis ist, in dem die Backups abgelegt werden.
Diese bash Datei erstellt man am besten mit nano oder einem anderen Editor in /home/pi und nennt sie z.B. raspiBackup.sh. Danach testet man das Script und ruft es per sudo auf. Am Ende befindet sich eine Backupdatei unter /backup/raspi. Dieses Backup sollte nun getestet und per dd oder einem äquivalenten Windowsprogramm auf eine weitere SD Karte gebracht werden. Nun muss die Pi mit der BackupSD Karte wie gewohnt starten und somit der Backupprozess getestet sein.
Wenn man nun ein anderes Backup erstellen will, z.B. ein tar Backup, muss man nun nur die Zeile im Script, die das Backup erzeugt ändern. Am Besten macht man dazu die Zeile mit dd unwirksam und fügt eine neue Zeile mit dem tar Befehl ein. Zeilen in Script macht man unwirksam wenn man ein # voranstellt. Das kann man auch sehr gut benutzen um Kommentare im Script zu schreiben. Wenn man im Script Befehle hat, die sehr lang sind sollte man sie der Übersichtlichkeit halber auf mehrere Zeilen verteilen. Dazu ist es notwendig am Ende aller Zeilen die zu dem einen Befehl gehören, immer ein \ zu schreiben - ausser in der letzten Zeile. Ausserdem sollte man vor dem Starten des Backups gewisse Services stoppen. Z.b. mysql, xbmc, webserver, samba usw und sie am Ende des Backups wieder starten.
=== Aktivierung des regelmäßigen Backups ===
Das Backupscript sieht nun wie folgt aus um ein dd Backup auf einem raspbmc zu erzeugen. Wer ein tar Backup haben will muss die Zeile mit dd auskommentieren und die Zeilen vom tar aktivieren durch Entfernung des # am Anfang der Zeilen.
#!/bin/bash
#
# Konstanten
#
BACKUP_PFAD="/backup/raspi"
ANZAHL_BACKUPS="3"
BACKUP_NAME="MeinBackup"
STOP_SERVICES="service xbmc stop"
START_SERVICES="service xbmc start"
#
# Stoppe services
#
${STOP_SERVICES}
#
# Backup mit dd erstellen
#
dd if=/dev/mmcblk0 of=${BACKUP_PFAD}/${BACKUP_NAME}-$(date +%Y%m%d-%H%M%S).img bs=1MB
#
# Backup mit tar erstellen
#
#tar -cpz --one-file-system -f ${BACKUP_PFAD}/${BACKUP_NAME}-$(date +%Y%m%d-%H%M%S).tgz \
# --exclude=${BACKUP_PFAD} \
# --exclude=/proc \
# --exclude=/lost+found \
# --exclude=/sys \
# --exclude=/mnt \
# --exclude=/media \
# --exclude=/dev \
# /
#
# Starte services
#
${START_SERVICES}
#
# Loeschen alter Backups
#
pushd ${BACKUP_PFAD}; ls -tr ${BACKUP_PFAD}/${BACKUP_NAME}* | head -n -${ANZAHL_BACKUPS} | xargs rm; popd
Display More
Nun muss man noch überprüfen, ob die voreingestellten Definitionen
BACKUP_PFAD="/backup/raspi"
ANZAHL_BACKUPS="3"
BACKUP_NAME="MeinBackup"
STOP_SERVICES="service xbmc stop"
START_SERVICES="service xbmc start"
stimmen und eventuell anpassen. Das Beispiel geht davon aus dass es ein raspxbmc ist welches gesichert werden soll.
Für raspbian könnten die Definitionen wie folgt aussehen:
BACKUP_PFAD="/backup/raspian"
ANZAHL_BACKUPS="10"
BACKUP_NAME="MeinBackup"
STOP_SERVICES="service cups stop; service mysql stop; service samba stop"
START_SERVICES="service cups start; service nysql start; service samba start"
Nun verschiebt man die Datei raspiBackup.sh in das Verzeichnis was für selbstgeschriebene Scripts unter Linux benutzt wird:
und macht das Script ausführbar
Nun muss mit
noch eine Zeile in der Crontab eingefügt werden:
Danach wird jeden Sonntag automatisch ein Backup um 22 erzeugt. Durch Änderung des Crontabeintrages kann man die Frequenz und Zeit der Backuperstellung entsprechend seinen Bedürfnissen anpassen (Siehe Tutorial zu cron)
=== Zurückspielen des Backups ===
ACHTUNG: Wenn man da aus Versehen nicht das Gerät der SD Karte sondern z.B. eine Festplatte als Gerät beim zurückschreiben angibt dann werden die Daten darauf unwideruflich zerstört! Also vorher immer mit
prüfen ob /dev/sda wirklich die SD Karte ist (Sieht man i.d.R. an der Speichergröße) und ggf den Gerätenamen entsprechend korrigieren.
Bei einem dd Backup braucht man kein Script zum Zurückspielen des Backups. Eine einfach Befehlszeile reicht aus.
Mit dem folgenden Befehl wurde der Backup angelegt.
Mit genau demselben Befehl, bei dem allerdings Eingabe (if=) und Ausgabe (of=) umgedreht wird, wird das dd Backup wieder auf eine SD Karte gespielt. Dabei muss dann die SD Karte in einem Kartenleser angeschlossen sein. I.d.R. wird die SD Karte dann /dev/sda.
D.h. mit folgendem Befehl
wird das Backup sehr einfach auf die SD Karte kopiert.
Beim tar Backup ist es aufwändiger. Genaugenommen muss man auch schon beim Backuprozess weitere Dinge sichern, denn das Partitionslayout der SD Karte wird mit tar im Gegensatz zu einem dd Backup nicht mitgesichert. Weiterhin müssen alle Partitionen per tar gesichert werden, d.h. bei raspbian muss noch die /boot Partition /dev/mmcblk0p1 zusätzlich gesichert werden. Weiterhin müssen die Partitionen vor dem Restore formatiert werden.
Die folgende Anleitung gilt für Images, die keine logischen Paritionen benutzen. wie z.B. raspbian.
Die Partitionstabelle wird wie folgt gesichert:
und später wie folgt auf eine neue SD Karte geschrieben
Nachdem die Partitionstabelle auf den neuen SD Karte angelegt wurde müssen die Partitionen noch formatiert werden. Bei raspbian sieht das wie folgt aus: (Annahme: Die SD Karte ist als /dev/sda angeschlossen) (Ggf /dev/sda durch den korrekten Gerätenamen ersetzen)
Danach kann das tar Backup zurückgespielt werden. Dazu muss die Partition, die zurückgespielt wird, gemounted werden:
und
Wie man sieht sind das schon mehrere Schritte die beim Sichern und Zurückspielen notwendig sind und diese bieten sich an auch in ein bash Script geschrieben zu werden. Man kann also seine bisherigen erworbenen bash Script Kenntnisse sehr gut dazu nutzen .
Eine Warnung: Wer den Restore auch in ein Script giessen will - dem empfehle ich dringend beim Testen vorsichtig zu sein und immer zu prüfen dass immer das richtige Gerät zum Wiederherstellen benutzt wird und sich das bestätigen zu lassen Z.B. hilft es sehr, wenn man vor dem eigentlichen Restore folgenden Code ausführt:
echo "@@@ Achtung: Zielpartition richtig (j/n)? @@@"
echo $(fdisk -l)
read a
[ "$a" == "j" ] || exit 127
=== Erweiterungen ===
Dieses Basisscript kann man nun natuerlich dazu benutzen um es nach Belieben zu erweitern und seinen Bedürfnissen anzupassen. Beispiele sind
- Andere Backupmethoden wie schnelleres und effizienteres rsync benutzen
- Meldung bei Erfolg und Fehler des Backups per email oder im syslog
- Protokollierung des Backupprozesses in /var/log/messages
- Abfangen von Laufzeitfehlern
=== Der einfache Weg - das Script raspiBackup ===
Alle obigen Erweiterungen und viele mehr sind im von mir selbst und mittlerweile auch in der Community genutzten Backup- und Restorescript verfügbar. Als Einleitung in die Shellprogrammierung ist es nicht geeignet. Wer nun aber Interesse an bash Programmierung bekommen hat kann dieses Script aber sehr gut nehmen und es sich ansehen um sich damit weiter in die bash Programmierung einzuarbeiten. bash lernt man am besten, indem man sich existierende Scripts ansieht und versteht was dort getan wird.
Wie immer ist es bei Backups extrem wichtig auch zu testen, dass sie funktionieren. Denn es ist nichts so frustrierend wie zu dem Zeitpunkt, in dem man ein Backup braucht, feststellen muss, das das Backup nicht OK ist. Ein Backup zu testen geht bei der Pi recht einfach, denn man muss nur eine weitere SD Karte haben, auf der man das Backup zurückspielt und testet, ob das zurückgespielte Backup OK ist.
Ein regelmäßiger Test des Backups sollte obligatorisch sein, denn es gibt erfahrungegemäß immer wieder Ereignisse, die dazu führen, dass ein Backup nicht mehr funktioniert, das Backup korrupt ist oder Daten fehlen und ein Restore deshalb nicht mehr möglich ist.