Loading...
 

Datensicherung: Simples Backup via rSync

howto:rsync

phL0w hat auf unterschiedlichen Rechnern zu unterschiedlichen Zwecken unterschiedliche Backup-Skripte auf Basis von 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-NaVd` $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 #
                   
-----------------

 

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 #
---

Die »backup-home-exclude.list« sieht dabei so aus:

.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


Google Search