Datensicherung: Simples Backup via rSync

{DIV(align=>left, width=>25%, float=>right, class="umijabox")}{DIV}

Einleitung, Links

Backup) hat auf unterschiedlichen Rechnern zu unterschiedlichen Zwecken unterschiedliche Backup) Skripte Auf Basis Von ((U:Rsync am Laufen. Er findet das komischerweise einfacher, als eine dafür konzipierte Software auf- und einzusetzen. Wer diese Auffassung sinnvollerweise nicht teilt, sollte sich folgende Projekte mal ansehen:

Wer gerne seine Freizeit damit verscheißt, mit Enterprise-Grade OSS (Open Source Software) zu spielen, sei verwiesen auf

Weiterhin wäre wohl zu bemerken, dass es sich hier um eine ganz brauchbare Lösung für die Sicherung von, äh, Dokumentdaten? handelt (also zB dem $HOME oder einfach ganz /home oder vielleicht noch /etc, aber nicht /usr/lib oder c:\windos\system32). Betriebssystempartitionen sollte man anders sichern. (Oder, die männlichere Variante, einfach drauf scheißen). (Rationale: rsync kann, wenn mans nicht als super user ausführt oder sonst irgendwelche Maßnahmen trifft, keine ownerships sichern. Für daten, die sich selten ändern, wäre außerdem Kompression sicher sinnvoll. D.h. doch lieber tar oder cpio für sowas nehmen, würde ich empfehlen.)

Jetzt aber los...

Die Idee

Die Idee hinter dem Skript ist, Rsync, ein recht mächtiges Tool zum Kopieren von Dateien, regelmäßig (zB. ein mal am Tag) mit den "richtigen" Parametern zu starten, um (schnell, d.h. effizient) eine sinnvolle Datensicherung erstellen zu können.

Dazu wird die --backup bzw. --backup-dir Funktion von rSync gebraucht: Wenn sie gesetzt ist, überschreibt rSync obsolete Dateien beim Kopiervorgang nicht, sondern verschiebt sie in das per --backup-dir angegebene Verzeichnis.

Wenn man diesem --backup-dir Parameter jeden Tag einfach das Datum nach ISO rückwärts mitgibt (heute zB 2009-10-12) erhält man einen Verzeichnisbaum, der einerseits das aktuellste Backup immer komplett vorhält, aber alte Versionen archiviert anstatt löscht. Man könnte das wohl als »rückwärts inkrementelle« Datensicherung bezeichnen (im Gegensatz zu Backup auf Tapes, wo man ein mal / regelmäßig ein volles Backup erstellt und dann die Änderungen, die da drauf kommen, jeden Tag irgendwie wegspeichert. Um dann den letzten Stand zu bekommen braucht man die komplette Sicherung vom WE plus die inkrementellen Sicherungen von jedem Wochentag... nervig).

Vorteile

Der größte Vorteil, den Flo darin sieht, ist der leichte Zugriff auf die Datensicherung sowie das Archiv: Suche ich eine Datei, deren Namen ich kenne, benutze ich die normale Dateisystem-Suche (unter Unix also find oder locate) und bekomme eine Liste mit gesicherten Versionen dieser Datei zurück.

Außerdem ist das Backup schnell wie Hölle (genaueres siehe zB bei "Windows" weiter unten).

Nachteile

Der größte Nachteil ist wohl, dass es nicht sehr leicht fällt, den exakten Stand einer kompletten, aber veralteten Sicherung herzustellen. Das war mir bisher aber immer egal: Wie oben erwähnt handelt es sich um eine Sicherung meines $HOMEs.

Verwendung

Ich habe die Skripte bei mir unter /usr/local/sbin gespeichert und rufe sie per cron auf: Auf meiner Workstation durch einen Eintrag in cron.daily (damit das Backup ein mal am Tag gemacht wird, egal wann), auf dem fuckup per Eintrag in der crontab (damit das Backup zu einer definierten Zeit nachts passiert).

Speziell auf der Workstation ist es sinnvoll, dem Skript eine niedrige Priorität mitzugeben. Per ionice auch für io. (Getestet unter Linux) nice -n 15 ionice -c3 /usr/local/sbin/backup-home.sh

Essenz

Das wichtige an dem Skript ist: /usr/bin/rsync --delete --backup --backup-dir=$DST_INCR/date +%Y-%m-%d $SRC $DST_MAIN

Das komplette Skript - Fuckup Musiksammlung

Die hier aufgeführte Variante wird zum Sichern der Musiksammlung vom Fuckup auf eine andere Maschine via DSL ("off-site backup") verwendet.

Inkl einem einfachen, "gut genug" funktionierendem "versuchs nochmal wenn die DSL Leitung abgekackt ist" Teil, einem "schreib eine Mail mit dem Logfile an Flo"-Teil und etwas unnötigen Ballast aus älteren Versionen:

Download des Skripts (zip-Archiv).


#!/bin/bash # # Scope: Backup Flos Home Directory to another Drive (or Machine) #

### Config SRC="/data/export/Audio" DST_MAIN="user@remote.host.net:/storage/fuckupmirror/aktuell/" DST_INCR="/storage/fuckupmirror/archiv/date +%Y-%m-%d/" DST_LOG="/home/CyberSync/log/date +%Y-%m-%d.log" REPORT_RCPT="your.email@address.com" RSYNC_OPTS="--bwlimit=60 --ignore-errors --delete --backup --backup-dir=$DST_INCR -av --one-file-system" PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ID_STRING="hostname echo $0 | sed 's/\/.*\///'" ### /Config

### see http://www.davidpashley.com/articles/writing-robust-shell-scripts.html set -u

### define custom routines function failexit() { echo "Something went wrong, let's bail out! Sending mail report to $REPORT_RCPT..." mail -s "$ID_STRING: ERROR REASON: $1." $REPORT_RCPT < $DST_LOG cd / exit 1 }

function cleanexit() { # clean exit; remount volume read-only again. sync sleep 5 mail -s "$ID_STRING: OK. Der Vogel ist gelandet." $REPORT_RCPT < $DST_LOG exit 0 }

function commit() { trap "killall rsync; failexit \"Caught signal\"" INT TERM echo "Initiating transfer on date..." >> $DST_LOG rsync $RSYNC_OPTS $SRC $DST_MAIN 2>&1 >> $DST_LOG RSYNC_EXITCODE=$? echo "rsync exit code: $RSYNC_EXITCODE" >> $DST_LOG echo "finished on date." >> $DST_LOG trap - INT TERM }

# do it commit

### action depending on return status of rsync. see rsync man page for a list of exit codes # Success if [ $RSYNC_EXITCODE -eq 0 ]; then cleanexit; fi # 12 happens when the DSL link dies. retry! if [ $RSYNC_EXITCODE -eq 12 ]; then commit; fi # Received SIGINT, SIGTERM, SIGHUP if [ $RSYNC_EXITCODE -eq 20 ]; then failexit "Caught Signal"; fi # Partial transfer due to error if [ $RSYNC_EXITCODE -eq 23 ]; then cleanexit; fi # Partial transfer due to vanished source files if [ $RSYNC_EXITCODE -eq 24 ]; then cleanexit; fi # 255 happens to me when SSH dies. retry! if [ $RSYNC_EXITCODE -eq 255 ]; then commit; fi # "else" failexit "Unknown, have a look at the logfile."

# eof #


{CODE}

Das komplette Skript - Flos Workstation /home

Inkl. "Exclude"-Direktiven für Zeug wie Browsercaches und Bittorrent-Download-Ordner, was ich nicht sichern will. Speichert einfach auf eine zweite Platte in meinem Rechner. Die aktuelle Sicherung von dort kopieren ich 'manchmal' nach off-site, aber das macht ein anderes Skript.

Download des Skripts (zip-Archiv).


#!/bin/bash # # Scope: Backup Flos Home Directory to another Drive (or Machine) #

### Config SRC="/home/" DST_ROOT="/mnt/backup" DST_MAIN="$DST_ROOT/aktuell/jimi/home" DST_INCR="$DST_ROOT/archiv/date +%Y-%m-%d/jimi/home" DST_LOG="$DST_ROOT/archiv/date +%Y-%m-%d/jimi/home-date +%Y-%m-%d.log" EXCLUDES="/usr/local/sbin/backup-home-exclude.list" REPORT_RCPT="mailaddress@recipient.net" RSYNC_OPTS="--force --ignore-errors --delete --delete-excluded --exclude-from=$EXCLUDES --backup --backup-dir=$DST_INCR -av --one-file-system" MOUNT_CHK="/dev/sda3 on /mnt/backup type ext3 (rw,noatime)" PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ID_STRING="hostname echo $0 | sed 's/\/.*\///'" ### Config Ende

### define custom routines function failexit() { echo "Something went wrong, let's bail out! Sending mail report to $REPORT_RCPT..." mail -s "$ID_STRING : ERROR REASON: $1." $REPORT_RCPT < /dev/null mail -s "$ID_STRING : LOGFILE." $REPORT_RCPT < $DST_LOG cd / mount -o remount,ro $DST_ROOT exit 1 } function cleanexit() { # clean exit; remount volume read-only again. sync sleep 5 mount -o remount,ro $DST_ROOT mail -s "$ID_STRING : OK. Die Eier sind fein." $REPORT_RCPT < $DST_LOG exit 0 }

### make volume writable mount -o remount,rw $DST_ROOT

### sanity checks if ! [ e2label /dev/sda3 = "backup" ]; then failexit "FATAL ERROR: /dev/sda3 is not labelled correctly. Will not backup to the wrong disk"; fi if ! [ -f $EXCLUDES ]; then failexit "FATAL ERROR: $EXCLUDES does not exist"; fi if ! mount | fgrep -s -q "$MOUNTCHK" ; then failexit "FATAL ERROR: Check mount options"; fi

### commit install -d $DST_INCR || failexit "Unable to create directories" install -d $DST_MAIN || failexit "Unable to create directories" echo "Initiating transfer on date ..." > $DST_LOG rsync $RSYNC_OPTS $SRC $DST_MAIN 2>&1 >> $DST_LOG RSYNC_EXITCODE=$? echo "finished on date ." >> $DST_LOG

### action depending on return status of rsync. see rsync man page for a list of exit codes # Success if [ $RSYNC_EXITCODE -eq 0 ]; then cleanexit; fi # Received SIGUSR1 or SIGINT # (probably we interactively killed rsync because it ate our resources) if [ $RSYNC_EXITCODE -eq 20 ]; then cleanexit; fi # Partial transfer due to error if [ $RSYNC_EXITCODE -eq 23 ]; then cleanexit; fi # Partial transfer due to vanished source files if [ $RSYNC_EXITCODE -eq 24 ]; then cleanexit; fi # "else" failexit "Unknown, have a look at the logfile."

# eof #

{CODE} Die »backup-home-exclude.list« sieht dabei so aus: {CODE()} .thumbnails/ cache/ Cache/ .opera/cache4/ .gvfs urlclassifier3.sqlite CACHE Desktop/torrent/ Trash/

Schnelles Backup für Windows...

Ich hab auch für Windows ein ähnliches Skript geschrieben, allerdings knapper und in Python und nicht durch Cron sondern durch eine Verknüpfung am Desktop zu starten. Damit kann man schnell seine "Dokumente und Einstellungen" (also $HOME) auf zB eine extern USB Platte sichern. Ursprünglich wollte ich kein eigenes Skript inkl. Interpreter etc. hernehmen, aber ich weiß nicht, wie ich unter XP sonst das aktuelle Datum als Parameter übergeben kann.

Wie schnell?

Auf Consls altem Laptop, der nur USB 1.1 kann - das Backup läuft auf eine via USB 1.1 auf eine externe Platte - braucht das (inkrementelle) Backup ihres gesamten "Dokumente und Einstellungen" Ordners (aktuell ~ 20 GB, normalerweise werden nur 40 MB oder so neu gesichert) typischerweise weniger als eine Minute. Das ist sehr fix, weil da ja halt schon viele sehr kleine Dateien enthalten sind, die überprüft werden müssen (mehrere tausend). (Die eine Minute natürlich ohne das vorher schon mal gemacht zu haben, also ohne Datei-Cache, sonst wär das ja nichts besonderes...). Das finde ich sehr, sehr schnell.

Wo krieg ich das her?

Um das zum Laufen zu bringen, braucht man einen Python-Interpreter, CWRsync (evtl. plus UTF8 Fix ) und fuer die "Fertig!" Nachricht am Ende EasyGUI.

(Update 2010-02: Es gibt auch einen nativen Port von RSync für Win32, der hat wahrscheinlich kein Problem mit UTF-8? Und: Evtl ist DeltaCopy hübscher? Das könnte auch ein rsync für Windows dabei haben, aber unter "inkremental backup" verstehen die anscheinend den delta-algorithmus von rsync bezogen auf die übertragung, nicht die tatsache, dass mann die alten daten vielleicht auch aufheben will)

Und natürlich das Skript selbst: Download des Skripts.


Howto