Backup mit btrfs-Snapshots

Datensicherung mit btrfs lokal oder auf einen entfernten Rechner

Das Dateisystem btrfs ist inzwischen gut produktiv einsetzbar. Die Möglichkeit Snapshots und Subvolumes anzulegen ermöglicht es Datensicherung sehr schnell und komforabel zu machen. Dieses Beispiel macht zuerst eine lokale Sicherung als Snapshot, und überträgt diese danach auf eine externes Medium.

backup.bt:

download

#!/bin/bash
#
# Aufruf: backup-btrfs
# Inkrementelles Backup für btrfs Dateisysteme in zwei Schritten:
# 1. Es wird zuerst ein lokaler btrfs-Snapshot in einem Subvolume angelegt, das geht sehr schnell.
# 2. Der lokale Snapshot wird differentiell per btrfs send/receive auf das Sicherungslaufwerk transferiert.
#     Das geht immernoch sehr viel schneller als mit rsync oder tar, weil nicht erst der ganzre Verzeichnisbaum
#     nach Änderungen durchsucht werden muss.
#
# Vorteile gegenüber rsync-backup und anderen Methoden: +schnell, +Datenintegrität ist sichergestellt
# Nachteile: keine Ausnahmelisten/Muster möglich, es wird immer das Komplette Volume gesichert.
#            Verwendet man für nicht zu sichernde Daten, z.B. Caches keine Unterverzeichnisse sondern Subvolumes
#            werden diese Daten nicht mitgesichert.
#
# Benötigt: btrfs auf den Quell- und Ziellaufwerk, btrfs-tools
#-------- Start Konfiguration --------------
#
# Funktion zur Sicherung
# Quelle: Absoluter Pfad auf lokaler Festplatte oder Array
# Ziel: Absoluter Pfad zum Sicherungsvolume
# 
myexit()  { echo "Fehlerabbruch: $1"; exit 0; }

REMOTE_MP=/mnt/backup-hd
BACKUPDIR=$REMOTE_MP/backup
QUELL_MP=/mnt/srcfs
logger -p user.info "Start $0"
mount LABEL=Jupiter-backup $REMOTE_MP || myexit "$REMOTE_MP mount fehlgeschlagen"
mount |grep $REMOTE_MP | grep -q btrfs || myexit "$REMOTE_MP ist nicht mit btrfs gemountet"
MountOnly=0
[ "$1" = "-m" ] && MountOnly=1
#
#
btr_backup() {
    #BKDEV=$(mount | grep btrfs | grep "$1" | awk '{print $1 }')
    BKDEV=$(df --output=source "$3"|tail -n +2)
    [ -z "$BKDEV" ] && myexit "kein Gerät für $1 gefunden"
    QUELLE=$QUELL_MP/@
    logger -p user.info "mount $BKDEV $QUELL_MP"
    mount $BKDEV $QUELL_MP || myexit "$BKDEV konnte nicht gemountet werden"
# lokaler Snapshot, MUSS ein Subvolume auf $QUELLE sein!
    SnapShotLocal=$QUELL_MP/.snapshots
# remote Snapshot, auch hier Subvolumes des Sicherungslaufwerks!
    SnapShotRemote=$BACKUPDIR/$2/.snapshots/
#
echo " $SnapShotLocal    $SnapShotRemote "
# Das Datum zur Laufzeit
    DATUM=$(date +%Y-%m-%dT%H%M%S)
#-----------ENDE KONFIGURATION --------------------
#
    [ $MountOnly -eq 1 ] && { echo "nur mounten angefordert. ENDE"; exit; }
    LAST_L=$(ls -1 $SnapShotLocal/ 2>/dev/null |tail -1)
    echo "   1. erstelle lokalen Snapshot $QUELLE -> $SnapShotLocal/$DATUM."
    btrfs sub snapshot -r $QUELLE $SnapShotLocal/$DATUM #|| myexit "Snapshot fehlgeschlagen"
    if [ -z "$LAST_L" ]
    then
        echo "   2. Transferiere ersten Snapshot auf die Sicherungsplatte, das kann dauern...."
	logger -p user.info "Transfer initial snapshot $SnapShotRemote to backup disk"
        btrfs send "$SnapShotLocal/$DATUM" | btrfs receive "$SnapShotRemote"
    else
        echo "   2. Transferiere inkrementelles Backup zu $LAST_L auf die Sicherungsplatte."
	logger -p user.info "Transfer subsequent snapshot $SnapShotRemote to backup disk"
        btrfs send -p "$SnapShotLocal/$LAST_L" "$SnapShotLocal/$DATUM" | btrfs receive "$SnapShotRemote"   || myexit "btrfs send fehlgeschlagen"
        # das Ganze ginge alternativ natürlich auch übers Netz:
        #btrfs send -p $SnapShotLocal/$LAST_L $SnapShotLocal/$DATUM | ssh -c arcfour backupuser@$TARGET_MACHINE sudo btrfs receive $SnapShotRemote
        # wobei arcfour zwar sehr schnell ist, aber nicht wirklich eine starke Verschlüsselung. Bei Bedarf hier also eher sowas wie "aes128-cbc".
        # Der Benutzer "backupuser" sollte ggf. dediziert sein und entsprechende sudo-Rechte bekommen.
        # Alternativ kann man auch direkten root-login mit Schlüsseln verwenden.
    fi
    umount $QUELL_MP
}
##########################################
#          QuellVerz.    RemoteSubVol     TopLevelMountPoint
btr_backup /home home /home
btr_backup "/home/joachim/Virtualbox VMs" js-vm /home
btr_backup /usr/src src /usr/src

umount LABEL=Jupiter-backup
logger -p user.info "Ende $0"

Erforderlich ist, dass sowohl lokal als auch auf dem Sicherungsmedium btrfs als Dateisystem ist. In diesem Beispiel ist im home-Bereich des Benutzers ein Subvolume für VM images angelegt. Der Grund ist, dass VM sehr grosse Dateien beinhaltet, die immer nur kleine Änderungen erfahren. Das btrfs von Haus aus COW macht, wird also bei jeder kleinen Dateiänderung die komplette datei geschrieben. Das fürht zu einer sehr schlechten Leistung. Deshalb ist dieses Subvolume mit den Attribut -C versehen, hier werden also kein Copy-On-Write veranstaltet. Das hätte man auch mit einem Unterverzeichnis machen können, aber so ist das gesamte Verzeichnis erst mal von der Datensicherung des home-Bereichs ausgeschlossen, und das war so gewünscht.