Wie versprochen die „rundum glücklich“-Lösung für das Backup. Ein grundlegendes Problem ist das Backup im laufenden Betrieb. Noch während das Backup läuft, verändern laufende Prozesse Dateien. Im Allgemeinen ist die /var
-Partition und im Besonderen sind Datenbanken und Mailqueues problematisch. Man kann sich nie sicher sein, ob der Stand im Backup wirklich konsistent ist.
Es gibt verschiedene Ansätze dem Problem Herr zu werden. Eine Datenbank könnte man in ein SQL-File dumpen, der Mailserver könnte kurz angehalten werden um die Mailqueue zu sichern. Das sind jedoch alles nur 99%-Lösungen. Eigentlich müsste man das System für den Zeitpunkt des Backups komplett einfrieren, das Backup durchführen und es danach weiterlaufen lassen.
Snapshots implementieren diese Technik und verhindern so eine Downtime des betroffenen Services. Zunächst in Datenbanken wie z.B. Oracle populär, finden sich Snapshots jetzt auch in Dateisystemen (LVM, Windows Vista Shadow Copies). Der Snapshot selbst ist eine atomare Aktion, die lediglich den Snapshot-Zeitpunkt (t) festhält. Alle nach diesem Zeitpunkt (t+x) geschriebenen Blöcke werden separat gespeichert, so dass nun in aller Ruhe alle Blöcke des Zeitpunkt (t) ins Backup wandern können. Ist das Backup beendet, kann der Snapshot verworfen werden.
Möchte man LVM-Snapshots nutzen, benötigt man noch etwas freien Platz in einer Volume Group. Dieser freie Speicher wird dafür verwendet, Änderungen am Dateisystem nach dem Zeitpunkt (t) zu speichern. Man sollte diesen Platz ausreichend dimensionieren, denn läuft das Snapshot-Volume voll, wird der Snapshot ungültig. Eine Faustregel sagt 15 bis 20% der Größe des Originaldateisystems sind angemessen. Wenn wir also einen Snapshot von einem 10GB Volume anlegen wollen, sollte der Snapshot 2GB groß sein. Das bedeutet, es können 2GB an Änderungen in das Dateisystem geschrieben werden, bevor der Snapshot ungültig wird. Da das Backup relativ schnell durchläuft, sind wir mit der Faustregel auf der sicheren Seite.
Snapshots erstellen
Ok, genug Theorie, wir legen also von den Volumes /var, /home und /usr einen Snapshot an:
sudo lvcreate -L2G -s -n usrbackup /dev/mainvg/usr Logical volume "usrbackup" created sudo lvcreate -L2G -s -n homebackup /dev/mainvg/home Logical volume "homebackup" created sudo lvcreate -L5G -s -n varbackup /dev/mainvg/var Logical volume "varbackup" created
Zur Kontrolle schauen wir mal mit lvscan
nach:
sudo lvscan ACTIVE Original '/dev/mainvg/usr' [10.00 GB] inherit ACTIVE Original '/dev/mainvg/var' [30.00 GB] inherit ACTIVE Original '/dev/mainvg/home' [10.00 GB] inherit ACTIVE '/dev/mainvg/backup' [50.00 GB] inherit ACTIVE Snapshot '/dev/mainvg/usrbackup' [2.00 GB] inherit ACTIVE Snapshot '/dev/mainvg/homebackup' [2.00 GB] inherit ACTIVE Snapshot '/dev/mainvg/varbackup' [5.00 GB] inherit
Die Snapshots können jetzt unter z.B. /mnt/lvm-backup
gemountet werden.
cd /mnt/lvm-backup sudo mkdir var sudo mkdir usr sudo mkdir home
sudo mount /dev/mainvg/varbackup /mnt/lvm-backup/var/ sudo mount /dev/mainvg/usrbackup /mnt/lvm-backup/usr/ sudo mount /dev/mainvg/home /mnt/lvm-backup/home/
Jetzt können wir uns unter /mnt/lvm-backup
umsehen und davon überzeugen, dass alle Dateien da sind 😉 Wenn die Snapshots nicht mehr gebraucht werden, können sie wieder gelöscht werden:
umount /mnt/lvm-backup/var umount /mnt/lvm-backup/usr umount /mnt/lvm-backup/home lvremove /dev/mainvg/varbackup lvremove /dev/mainvg/usrbackup lvremove /dev/mainvg/homebackup
Backup mit dar
Für das eigentliche Backup ist es dann schon fast egal, welches Tool verwendet wird. Tar ist der Klassiker und sicher eine gute Wahl. Ich bevorzuge allerdings dar, weil man damit sehr einfach inkrementelle Backups erstellen kann und die Unterstützung für Wechselmedien eingebaut ist. Wechselmedien wie DVDs haben wir bei dem Rootserver zwar nicht, es gibt jedoch FTP-Server, die nur Dateien bis zu einer Größe von 2GB unterstützen. Also wird das Backup in kleinere Slices gesplittet.
Falls dar
dar noch nicht auf dem Server installiert ist, kann das jetzt nachgeholt werden:
sudo aptitude install dar
Für das erstellen eines Backup-Scriptes empfehle ich wärmstens das DAR-Tutorial. Es macht wenig Sinn, die folgenden Scripte zu Copy&Pasten, wenn man sie nicht verstanden hat. Ok, Tutorial gelesen und verstanden? Fein, dann kann es ja losgehen.
Durch das Setup unseres Servers müssen wir etwas umdenken: /home, /usr und /var können mittels der LVM-Snapshot Technik gesichert werden, das Root-Dateisystem (bin, boot, etc, lib, opt, tmp) liegt jedoch nicht auf einem LVM-Volume und muss „klassisch“ gesichert werden. Wer sein Root auf einem LVM hat, ist jetzt fein raus. Da in den betroffenen Verzeichnissen eher statische Daten liegen, sollte das jedoch kein Problem sein.
Komplett-Backup der Root-Partition
Das Backup-Script dar-root-full-backup.sh
für ein Full-Backup der Root-Partition sieht so aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #!/bin/sh # target dir DIR=/mnt/backup FILE=${DIR}/`date -I`_root-backup_full echo Backing up to $FILE # start from root cd / # run dar nice -n 19 /usr/bin/dar -m 256 -y -s 1073741824 -D -R / -c $FILE \ -Z "*.gz" \ -Z "*.bz2" \ -Z "*.zip" \ -Z "*.png" \ -Z "*.jpg" \ -X "*~" \ -X ".*~" \ -X "*backup*.dar" \ -P home \ -P usr \ -P var \ -P media \ -P mnt \ -P sys \ -P dev/pts \ -P proc |
Dank des DAR-Tutorials ist natürlich sofort klar, dass hier in Slices zu je 1GB gesichert wird. Verzeichnisse wie /proc
und die LVM-Volums /home
, /usr
und /var
werden vom Backup ausgeschlossen (-P).
Das Backup landet dann z.B. in /mnt/backup/2007-07-14_root-backup_full.1.dar
.
Differentialbackup der Root-Partition
Das Backup-Script dar-root-diff-backup.sh
für ein Differentialbackup der Root-Partition sieht so aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #!/bin/sh # target dir DIR=/mnt/backup FILE=${DIR}/`date -I`_root-backup_diff PREV=`/bin/ls $DIR/*_root-backup*.dar|/usr/bin/tail -n 1|/usr/bin/awk -F '.' '{print $1;}'` echo Backing up to $FILE echo Previous backup is $PREV # start from root cd / # run dar nice -n 19 /usr/bin/dar -m 256 -y -s 1073741824 -D -R / -c $FILE \ -Z "*.gz" \ -Z "*.bz2" \ -Z "*.zip" \ -Z "*.png" \ -Z "*.jpg" \ -X "*~" \ -X ".*~" \ -X "*backup*.dar" \ -P home \ -P usr \ -P var \ -P media \ -P mnt \ -P sys \ -P dev/pts \ -P proc \ -A $PREV |
Der Einzeiler PREV=...
sucht immer das jüngste Backup. Der Unterschied zum vorherigen Script ist lediglich der Parameter -A $PREV. Damit macht man DAR das vorhergehende Backup als Referenz bekannt. Jetzt werden nur noch die Unterschiede zum letzten Backup gesichert.
Vollständiges Backup der LVM-Partitionen
Das Backup-Script dar-homeusrvar-full-backup.sh
für ein Full-Backup der LVM-Partitionen sieht so aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #!/bin/sh # target dir DIR=/mnt/backup # target file FILE=${DIR}/`date -I`_homeusrvar-backup_full echo Backing up to $FILE # create snapshots echo Creating snapshots... lvcreate -L2G -s -n usrbackup /dev/mainvg/usr lvcreate -L2G -s -n homebackup /dev/mainvg/home lvcreate -L5G -s -n varbackup /dev/mainvg/var # mount snapshots mount /dev/mainvg/varbackup /mnt/lvm-backup/var/ mount /dev/mainvg/usrbackup /mnt/lvm-backup/usr/ mount /dev/mainvg/home /mnt/lvm-backup/home/ # start /mnt/lvm-backup cd /mnt/lvm-backup # run dar nice -n 19 /usr/bin/dar -m 256 -y -s 1073741824 -D -R /mnt/lvm-backup -c $FILE \ -Z "*.gz" \ -Z "*.bz2" \ -Z "*.zip" \ -Z "*.png" \ -Z "*.jpg" \ -X "*~" \ -X ".*~" \ -X "*backup*.dar" # umount snapshots umount /mnt/lvm-backup/var umount /mnt/lvm-backup/usr umount /mnt/lvm-backup/home echo Removing snapshots... lvremove -f /dev/mainvg/varbackup lvremove -f /dev/mainvg/usrbackup lvremove -f /dev/mainvg/homebackup |
Das ist ein wenig mehr Magie. Vor dem Backup werden die Snapshots erstellt, nach dem Backup wieder weggeräumt. Da die Snapshots nach /mnt/lvm-backup
gemountet werden, ist die Exclude-Liste relativ kurz.
Differentielles Backup der LVM-Partitionen
Das Backup-Script dar-homeusrvar-diff-backup.sh
für ein Differentialbackup der LVM-Partitionen sieht so aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #!/bin/sh # target dir DIR=/mnt/backup # target file FILE=${DIR}/`date -I`_homeusrvar-backup_diff PREV=`/bin/ls $DIR/*_homeusrvar-backup*.dar|/usr/bin/tail -n 1|/usr/bin/awk -F '.' '{print $1;}'` echo Backing up to $FILE echo Previous backup is $PREV # create snapshots echo Creating snapshots... lvcreate -L2G -s -n usrbackup /dev/mainvg/usr lvcreate -L2G -s -n homebackup /dev/mainvg/home lvcreate -L5G -s -n varbackup /dev/mainvg/var # mount snapshots mount /dev/mainvg/varbackup /mnt/lvm-backup/var/ mount /dev/mainvg/usrbackup /mnt/lvm-backup/usr/ mount /dev/mainvg/home /mnt/lvm-backup/home/ # start from /mnt/lvm-backup cd /mnt/lvm-backup # run dar nice -n 19 /usr/bin/dar -m 256 -y -s 1073741824 -D -R /mnt/lvm-backup -c $FILE \ -Z "*.gz" \ -Z "*.bz2" \ -Z "*.zip" \ -Z "*.png" \ -Z "*.jpg" \ -X "*~" \ -X ".*~" \ -X "*backup*.dar" \ -A $PREV # umount snapshots umount /mnt/lvm-backup/var umount /mnt/lvm-backup/usr umount /mnt/lvm-backup/home echo Removing snapshots... lvremove -f /dev/mainvg/varbackup lvremove -f /dev/mainvg/usrbackup lvremove -f /dev/mainvg/homebackup |
Ordnung halten
Die Backup-Scripte können jetzt via cron nachts aufgerufen werden. Zwei Zeilen in /etc/crontab
genügen:
# backup jobs 15 2 2-31 * * root /root/bin/diff-backup.sh 15 2 1 * * root /root/bin/full-backup.sh
An jedem 1. des Monats läuft das Komplettbackup, an allen anderen Tagen das Differentialbackup. full-backup.sh
ist lediglich ein Wrapper-Script und sieht so aus:
1 2 3 | #!/bin/sh /root/bin/dar-root-full-backup.sh /root/bin/dar-homeusrvar-full-backup.sh |
Das gleiche nochmal für’s Differentialbackup (diff-backup.sh
):
1 2 3 | #!/bin/sh /root/bin/dar-root-diff-backup.sh /root/bin/dar-homeusrvar-diff-backup.sh |
Damit das Backup-Verzeichnis nicht voll läuft, müssen alte Backups gelöscht werden. Dafür legen wir unter /etc/cron.daily
ein kleines Script delete_old_backups.sh
an, das alle Dateien, die vor mehr als 32 Tagen erstellt wurden, löscht:
1 2 3 4 5 6 | #!/bin/sh FILES=`find /mnt/backup -mtime +32` if [ -n "$FILES" ]; then echo deleting old backups... rm -v $FILES fi |
Fertig?
Nicht ganz. Zu jedem Backup gehört ein Restore. Am besten testet man das gleich vom Rescue-System aus. Zuerst werden die Volumes gemountet:
/etc/init.d/lvm stop mdrun /etc/init.d/lvm start mount /dev/md1 /mnt/ mount /dev/md0 /mnt/boot/ mount /dev/mainvg/usr /mnt/usr/ mount /dev/mainvg/var /mnt/var/ mount /dev/mainvg/backup /mnt/mnt/backup/ mount /dev/mainvg/home /mnt/home/
Ok, jetzt liegt das Backup unter /mnt/mnt/backup. Wir nehmen das letzte Full-Backup und spielen es nach /mnt/mnt/restore/
dar -x /mnt/mnt/backup/2007-07-14_root-backup_full.1.dar -R /mnt/mnt/restore
Das home/var/usr-Backup muss auch noch zurück gespielt werden:
dar -x /mnt/mnt/backup/2007-07-14_homeusrvar-backup_full.1.dar -R /mnt/mnt/restore
So, das sollte es gewesen sein. Hoffen wir darauf, dass nie ein Backup zurückgespielt werden muss 😉
Lektüre
Lesetipps:
- Das DAR-Tutorial
- Taking a Backup Using Snapshots aus dem LVM-Howto
Zum vorherigen Teil: FTP-Backup: Speicherplatz nutzen »
Zum ersten Teil: Debian Etch auf einem Rootserver mit Raid-1 und LVM »