ZFS-Snapshots für die Datensicherung mit FreeBSD
2018-12-21
Das Thema Datensicherung (Backup) ist ein großes und jeder, der sich ernsthafter mit Computertechnik beschäftigt, sollte damit Berührung gehabt haben. Im Guten wie im Schlechten. ;-)
In dieser kleinen Anleitung möchte ich kurz beschreiben wie man mit wenig Aufwand in die Lage versetzt wird die Snapshots von ZFS zu nutzen, um verschlüsselte Sicherungen auf eine externe Festplatte zu ziehen.
Voraussetzungen
Diese Anleitung bezieht sich ausdrücklich auf die Nutzung von FreeBSD! Theoretisch dürfte das aber auch alles mit Linux funktionieren.
Das verwendete Dateisystem muß ZFS und via GELI verschlüsselt sein. Der Installer von FreeBSD bietet diese Option an, es ist also kein “Hexenwerk” ein solches System zu haben.
Einrichtung der externen Festplatte
Die externe Festplatte sollte ausreichend groß sein und eine entsprechend schnelle Schnittstelle haben (USB 3.0). Da im weiteren Verlauf die Sicherungen inkrementell durchgeführt werden, ist Geschwindigkeit nicht mehr ganz so wichtig, wenn der erste Datensatz erstmal gesichert ist und die Abstände zwischen den Sicherungen nicht zu groß sind.
Partitionierung
Für die folgenden Befehle gehe ich davon aus, daß die externe Platte als
Gerät /dev/da4
erkannt wurde. Es werden alle etwaigen Daten auf der Platte
gelöscht. Zusätzlich gelten die folgenden Annahmen:
- Name des zu sichernden Pools:
zroot
- Name des Backup-Pools:
backup
Zunächst legen wir ein GTP Partitionierungsschema auf der Platte an und erstellen eine Partition für ein FreeBSD-ZFS.
# gpart create -s GPT /dev/da4
# gpart add -t freebsd-zfs -l backup-vol da4
# gpart show
Der letzte Befehl gpart show
sollte die Partitionierungsinformationen
ausgeben.
Verschlüsselung
Der folgenden Befehl initialisert die angelegte Partition mit der Standardverschlüsselung von GELI bei einer Schlüssellänge von 256 Bit.
# geli init -l 256 /dev/gpt/backup-vol
Bitte verwendet ein gutes Paßwort und verliert es nicht! Es gibt noch alternative Methoden (Schlüsseldatei), die man in der Anleitung von GELI nachlesen kann.
ZFS einrichten
Jetzt muß die Partition eingebunden und ZFS entsprechend eingerichtet werden:
# geli attach /dev/gpt/backup-vol
# zpool create backup /dev/gpt/backup-vol.eli
# zfs create -o compress=lz4 backup/home
Diese Befehle entschlüsseln die Partition, erstellen einen Pool für ZFS
darauf und einen ZFS-Datensatz, den wir später für die Sicherung von
Snapshots verwenden. Falls die Option zstd
für die Komprimierung verfügbar
ist, sollte sie verwendet werden, da sie im Vergleich zu lz4
erheblich
bessere Performance bietet!
Initialen Snapshot erstellen und sichern
Damit die zukünftigen Sicherungen inkrementell erfolgen können, muß erst ein initialer Datensatz angelegt werden.
Einen solchen erstellt man mittels des folgenden Befehls für den Datensatz
/usr/home
:
# zfs snapshot "zroot/user/home@2018-12-21"
Der Teil hinter dem Klammeraffen (@
) ist der Name des Snapshots, hier ein
Datum in ISO-Notation.
Anschließend muß der Snapshot auf die externe Platte überspielt werden, was eine Weile dauern kann und mittels des folgenden Befehls geschieht:
# zfs send "zroot/usr/home@2018-12-21" | zfs receive -F "backup/home@2018-12-21"
Vorhandene Snapshots kann man sich mit dem Befehl zfs list -t snapshot
anzeigen lassen.
Zu guter Letzt speichern wir noch das Datum der letzten Sicherung als “User Property” im ZFS-Pool, den wir für die Backups verwenden.
# zfs set backup:latest=2018-12-21 backup
Insofern wir das alles auch als normale Benutzer ausführen wollen, sollten wir die entsprechenden Rechte setzen:
# zfs allow -u USER send,snapshot zroot
# zfs allow -u USER compression,mountpoint,mount,create,receive,userprop backup
Skript für die regelmäßige Sicherung
Das folgende Skript kann regelmäßig ausgeführt werden, um Daten zu sichern. Vorher muß jedoch der ZFS-Pool der externen Platte eingebunden werden.
#!/bin/sh
#
# Script for Snapshot based backups via ZFS.
#
# Permissions needed for source pool:
# zfs allow -u USER send,snapshot SOURCE_POOL
# Permissions needed for target pool:
# zfs allow -u USER compression,mountpoint,mount,create,receive,userprop BACKUP_POOL
SOURCE_POOL="zroot"
BACKUP_POOL="backup"
LATEST_PROP="backup:latest"
zpool get -Hp -o value free ${BACKUP_POOL} >/dev/null 2>&1 || {
echo "ZFS backup pool (${BACKUP_POOL}) not found!"
exit 1
}
LATEST=$(zfs get -H -o value ${LATEST_PROP} ${BACKUP_POOL})
if [ ${LATEST} == "-" ]; then
echo "No property '${LATEST_PROP}' with last backup date found in backup pool ('${BACKUP_POOL}')!"
echo "If you don't have a last backup please create one using the following commands:"
echo '# SNAPSHOT=$(date +"%F")'
echo "# zfs snapshot ${SOURCE_POOL}/usr/home@\${SNAPSHOT}"
echo "# zfs send ${SOURCE_POOL}/usr/home@\${SNAPSHOT} | zfs receive -F ${BACKUP_POOL}/home@\${SNAPSHOT}"
echo "# zfs set ${LATEST_PROP}=\${SNAPSHOT} ${BACKUP_POOL}"
echo "If the script is run as a regular user then please ensure the following permissions are set:"
echo "- send,snapshot on the SOURCE_POOL"
echo "- compression,mountpoint,mount,create,receive,userprop on the BACKUP_POOL"
exit 1
else
SNAPSHOT=$(date +"%F")
if [ ${LATEST} == ${SNAPSHOT} ]; then
echo "Last backup is identical with current snapshot (${SNAPSHOT})!"
echo "Please investigate and fix manually."
exit 1
else
echo "Going to start incremental snapshot backup from ${LATEST} to ${SNAPSHOT} in 15 seconds."
echo "If unsure, press Ctrl+C now..."
sleep 15
zfs snapshot "${SOURCE_POOL}/usr/home@${SNAPSHOT}"
echo "Snapshot complete, sending to backup device..."
zfs send -i ${LATEST} "${SOURCE_POOL}/usr/home@${SNAPSHOT}" | zfs receive -F "${BACKUP_POOL}/home@$SNAPSHOT"
echo "Setting ${LATEST_PROP} on ${BACKUP_POOL} pool."
zfs set ${LATEST_PROP}=${SNAPSHOT} ${BACKUP_POOL}
echo "Operation complete. Please also backup important system files and directories like /boot /etc and /usr/local/etc."
echo "Remember to export the zpool and detach the geli device before unplugging!"
fi
fi
Aus- und wiedereinhängen der Platte und des ZFS-Pools
Nach erfolgter Datensicherung kann der Pool von ZFS exportiert, GELI ausgehängt und anschließend die Festplatte abgezogen werden.
Für die ersten beiden Punkte sind folgende Befehle zuständig:
# zpool export backup
# geli detach /dev/gpt/backup-vol.eli
Für das Einhängen gehen wir in folgendermaßen vor:
# geli attach /dev/gpt/backup-vol
# zpool import backup