Anders als Papier oder Mikrofilm, die nicht von selbst Feuer fangen können und eine reguläre Lebensdauer von Jahrzehnten haben, sind elektronische Daten endlich. Endlich in dem Sinne, dass vorhergesagt werden kann, dass sie auf ihrem ursprünglichen Datenträger nicht die Zeit erleben werden, für die sie bestimmt sind.
Das schlimmste am Verlust von Daten ist, dass man nicht weiß, was genau man verloren hat. Einzelne Personen werden sich an ihre Bestandteile vielleicht noch erinnern, das vollständige Bild bleibt aber für immer verloren. Wenn man fragt, woran man eine ordnungsgemäße IT-Verwaltung erkennt, werden wahrscheinlich Backups die Liste der Antworten anführen. Doch sie sind trügerisch, einerseits erkennt man im Regelbetrieb nicht, ob sie (noch) durchgeführt werden. Man plant für das Ungewisse, hofft dass es niemals geschieht, weiß aber gleichzeitig erst ob alles funktioniert hat, wenn das Ereignis eintritt.
Andererseits ist es schwer jemanden wegen Fehlern im Backup zur Verantwortung zu ziehen, wenn Daten verloren gehen. Niemand weiß, was verloren gegangen ist, etwas zu beweisen, was es nicht mehr gibt ist nahezu unmöglich und Schäden können daher weitestgehend nicht beziffert werden. Ein mißlungenes Backups ist somit die Generalausrede für den Verlust von Daten. Dazu kommt, dass nicht alle Daten für die Ewigkeit bestimmt sind, sich der Aufwand für jene also nicht lohnt.
Zusammengefasst bleibt im Ernstfall immer eine Ungewissheit und daneben stellt es auch eine Chance dar, nur wichtige Daten mitzuschleppen. Was jedenfalls bleibt, ist die Strategie, die hinter dem Backup steht.
Im Folgenden einige Begriffe, wie ich sie hier verwenden werde (offizielle sprachliche oder technische Definitionen können und würden davon abweichen):
Ich für meinen Teil habe mir angewöhnt Backups aufzuteilen, auch wenn dieser Tage Speicherplatz so günstig ist, dass grundsätzlich jederzeit ein volles Backup möglich ist. Zumindest trenne ich zwischen dem System und den Daten. So kann im Ernstfall (wenn gewünscht) der Systemausfall gleich zu einem Update genutzt werden.
Daneben bemühe ich mich, auf inkrementelle Backups zu setzen. Dadurch können häufiger, kleinere Backups durchgeführt werden, die jeweils den Zustand einer gewissen Zeitspanne repräsentieren.
Ich setze a) auf freie Software, um die Verfügbarkeit für die Zukunft sicherzustellen, und b) auf Datenformate, die auch ohne eine spezielle Software gelesen werden können. Damit soll sichergestellt werden, dass das Programm auch von einer Rettungskonsole aus benutzt werden kann. Kurz, ich setze auf Duplicity.
Meine Erfahrungen beziehen sich auf Linux-Server, auf die ich keinen physischen Zugriff habe und die keine grafische Oberfläche haben. Der Backup-Server ist dabei via FTP zu erreichen.
Um zu vermeiden, dass Backups von temporären Backup-Dateien entstehen, habe ich ein Verzeichnis /backup angelegt. Das gesamte Verzeichnis befindet sich als ZIP-Datei bei meinen Notfallunterlagen. Auch der Backup-FTP ist nach /backup/ftp gemounted (solange kein Backup läuft, duplicity bringt eine eigene FTP-Funktion mit), allerdings liegen die Zugangsdaten dafür in /root/.netrc.
Das keyfile und die config für duplicity und die Profildateien (dazu später mehr) liegen in /etc/backup. Das Backup-Script in der Datei /backup/tools/backup.
Im Fall der Fälle ließe sich ein mittels Rettungskonsole ein ganz neues System aufsetzen. Duplicity, das Backup-Script und den Ordner /backup installieren sowie das Verzeichnis /etc/backup mit den Profildaten und dem Keyfile füllen.
Dann kann man entscheiden, ob man nur die Daten rückspielt oder auch das System auf den Stand des letzten Backups bringt.
Um Profile nutzen zu können, verwende ich ein selbstgeschriebenes Skript - Dank an dieser Stelle für zahlreiche Ideengeber. Ich erkläre zunächst, wei diese Profile funktionieren und sodann wie sie aufgerufen werden. Zum Schluss findet sich das Skript selbst.
Duplicity ist hervorragend, um verschiedene Orte zu einem Backup zusammen zu fassen. Jede dieser Zusammenfassung ist in meiner Sprechart ein Profil, z.B. System, Home, Mail etc.
Die verschiedenen Profile sind schlicht Dateien im Ordner /etc/backup, welche in Duplicity-Notation die dazugehörigen Verzeichnisse bzw. Auslassungen auflisten, z.B. für das Profil System (/etc/backup/system):
# exclusions first
- /srv/ftp
- /srv/webdav
+ /usr/
+ /bin/
+ /sbin/
+ /opt/
+ /selinux/
+ /srv/
+ /lib/
+ /lib64/
+ /boot/
+ /etc/
+ /initrd*
+ /vmlinuz*
+ /installimage*
- /sys/**
# backup specific data
+ /backup/systemdata/
+ /backup/tools/
Ein weiterer Vorteil ist die Möglichkeit, Befehle auszuführen, bevor das eigentliche Backup beginnt. Am Beispiel des Profils System (/etc/backup/system.pre):
#!/bin/bash
/usr/bin/dpkg --get-selections | /usr/bin/diff -s - /backup/systemdata/installed-packages.txt | /bin/grep "identisch" > /dev/null;
if [ $? -gt 0 ]; then
/usr/bin/dpkg --get-selections > /backup/systemdata/installed-packages.txt;
fi
Zusammengefasst wird hier für ein Backup der Systemverzeichnisse zunächst eine Textdatei mit allen installierten Paketen erstellt (system.pre), um das System in den Ausgangszustand bringen zu können. Diese Datei wird mit den Systemverzeichnissen mitgesichert (system).
Ein crontab könnte wie folgt aussehen:
##
# System - Binary and configuration files
# daily 00:05h
5 0 * * 2-7 /backup/tools/backup --profile system incremental
5 0 * * 1 /backup/tools/backup --profile system full
0 13 * * 1 /backup/tools/backup --profile system remove-all-but-n-full 2
Jeden tag um 00:00 Uhr wird das Backup für System ausgeführt. Einmal die Woche voll, sonst inkrementell. Nach dem Vollbackup werden mittags überflüssige Backupdateien gelöscht.
Wenn alles richtig eingerichtet ist, lässt sich ein Restore wie folgt ausführen:
/backup/tools/backup --profile system <DESTINATION>
<Destination> kann ein temporäres Verzeichnis sein, falls z.B. nur einzelne Dateien aus dem Backup gesucht werden. Oder es kann "/", das root-Verzeichnis, sein, um das System wieder herzustellen.
/backup/tools/backup --profile system <COMMAND>
Mein Skript reicht im Wesentlichen lediglich die Duplicity-Befehle durch, <COMMAND> kann einer der folgenden sein:
Das gesamte Skript:
#!/bin/bash
# System variables
NAME="meinserver.de";
TARGET="/backup/ftp";
LOGFILE="/backup/backup.log";
VERBOSITY=0; # more then 6 gives nonsense, from 6 on file names are written
TMPDIR="/backup/tmp";
FTPHOST=`/bin/fgrep machine ~/.netrc | awk '{print $2}'`;
FTPUSER=`/bin/fgrep login ~/.netrc | awk '{print $2}'`;
FTPPWD=`/bin/fgrep password ~/.netrc | awk '{print $2}'`;
# functions
function debug {
if [ $VERBOSITY -gt 0 ]; then
# print out debug message
echo `/bin/date +"%Y-%m-%d %T"`" $PROFILE: $@";
elif [ "$LOGFILE" != "" ]; then
# write debug to file
echo `/bin/date +"%Y-%m-%d %T"`" $PROFILE: $@" >> "$LOGFILE";
fi
}
STARTTIME=`/bin/date +%s`;
if [ -f "/etc/backup/gpg.conf" ]; then
/bin/chown root.root /etc/backup/gpg.conf;
/bin/chmod 600 /etc/backup/gpg.conf;
. /etc/backup/gpg.conf;
if [ "$GPGKEY" = "" -o "$GPGPWD" = "" ]; then
echo "Can't read encryption key from config. Backup aborted.";
debug "Can't read encryption key from config. Backup aborted.";
exit 99;
fi
else
echo "Can't read encryption key. Backup aborted.";
debug "Can't read encryption key. Backup aborted.";
exit 99;
fi
# check for profile
PROFILE=$2;
if [ "$1" != "--profile" -o ! -f "/etc/backup/$PROFILE" ]; then
echo "No or corrupt profile for backup given. Profile needs to be the first parameter. Aborting.";
debug "No or corrupt profile for backup given.";
exit 2;
else
shift;
shift;
debug "Backup started. Using profile $PROFILE.";
fi
# check for ftp available
FTPCHECK=`/bin/mount -l | grep $TARGET`;
if [ "$FTPCHECK" = "" ]; then
echo "Can't access ftp site. Backup aborted.";
debug "Can't access ftp site. Backup aborted.";
exit 1;
fi
# check for target folder
if [ ! -d "$TARGET/$PROFILE" ]; then
/bin/mkdir "$TARGET/$PROFILE";
/bin/chmod 700 "$TARGET/$PROFILE";
if [ ! -d "$TARGET/$PROFILE" ]; then
debug "Can't create profile folder in ftp site. Aborting.";
echo "Can't create profile folder in ftp site. Aborting.";
exit 3;
else
debug "Created folder $TARGET/$PROFILE";
/bin/chmod 700 "$TARGET/$PROFILE";
fi
fi
## proprietary delete command
if [ "$1" = "drop-backup" ]; then
if [ -d "$TARGET/$PROFILE" ]; then
/bin/rm -R "$TARGET/$PROFILE";
fi
if [ -d "$TMPDIR/$NAME/$PROFILE" ]; then
/bin/rm -R "$TMPDIR/$NAME/$PROFILE";
fi
echo "Deleted all backup files - remote and local - for profile $PROFILE";
debug "Deleted all backup files - remote and local - for profile $PROFILE";
exit 0;
fi
## create duplicity call
FTP="ftp://$FTPUSER@$FTPHOST";
# exclude select the files to be backed up according to profile
EXCLUDE="--exclude-globbing-filelist /etc/backup/$PROFILE --exclude /";
debug "Backup running. Doing $1 backup.";
## check correct parameters
#
# cleanup, remove-older-than, remove-all-but-n-full: add force to really delete
# collection-status, list-current-files: specify only ftp collection
# full, incr / incremental: specify source locally and target on ftp, remove command if incremental update
# restore, verify: specify target on ftp and source locally, rmeove command if restore is selected
#
if [ "$1" = "cleanup" -o "$1" = "remove-older-than" -o "$1" = "remove-all-but-n-full" ]; then
D_COMMAND="$1 --force";
shift;
D_COMMAND="$D_COMMAND $@ $FTP/$PROFILE";
elif [ "$1" = "collection-status" -o "$1" = "list-current-files" ]; then
D_COMMAND="$@ $FTP/$PROFILE";
elif [ "$1" = "full" -o "$1" = "incr" -o "$1" = "incremental" ]; then
if [ "$1" = "incr" -o "$1" = "incremental" ]; then
shift;
fi
D_COMMAND="$@ / $FTP/$PROFILE $EXCLUDE";
L_COMMAND="scripts";
elif [ "$1" = "restore" ]; then
shift;
D_COMMAND="$FTP/$PROFILE $@";
elif [ "$1" = "verify" ]; then
D_COMMAND="$1";
shift;
D_COMMAND="$D_COMMAND $FTP/$PROFILE / $@";
L_COMMAND="changes";
else
debug "Command $1 does not exist. What do you want to do?";
echo "Command $1 does not exist. What do you want to do?";
exit 4;
fi
# take the rest
if [ $VERBOSITY -lt 1 ]; then
D_COMMAND="$D_COMMAND --no-print-statistics";
fi
D_COMMAND="$D_COMMAND --encrypt-key $GPGKEY --sign-key $GPGKEY\
--verbosity $VERBOSITY\
--tempdir $TMPDIR --archive-dir $TMPDIR/$NAME --name $PROFILE";
## running pre script
if [ "$L_COMMAND" = "scripts" -a -f "/etc/backup/$PROFILE.pre" ]; then
debug "Running pre-script for profile $PROFILE.";
. "/etc/backup/$PROFILE.pre";
fi
## unmount to prevent double login
/bin/umount "$TARGET";
## execute duplicity
PASSPHRASE="$GPGPWD" \
FTP_PASSWORD="$FTPPWD" \
/usr/bin/duplicity $D_COMMAND
## check result
if [ "$L_COMMAND" = "changes" -a $? -ne 0 ]; then
if [ $? -gt 0 ]; then
echo "Profile $PROFILE has unsaved changes pending.";
else
echo "There are no differences between backup and local files in profile $PROFILE.";
fi
fi
## mount again
/bin/mount "$TARGET";
## running post script
if [ "$L_COMMAND" = "scripts" -a -f "/etc/backup/$PROFILE.post" ]; then
debug "Running post-script for profile $PROFILE";
. "/etc/backup/$PROFILE.post";
fi
ENDTIME=`/bin/date +%s`;
TOTALTIME=$((ENDTIME-STARTTIME));
debug "Backup finished. Took $TOTALTIME second(s). ";
Bisher hat niemand diese Seite kommentiert.
RSS Feed für die Kommentare auf dieser Seite | RSS feed für alle Kommentare