Backup
Backup Drucken E-Mail
Geschrieben von: Administrator   
Freitag, 15. Februar 2008 10:07

Wer einen root Server hat, kennt das Problem: Wie werden die Daten so gesichert, dass einmal eine Wiederherstellung möglich ist und nicht mehr Traffic als nötig erzeugt wird.

Das hier vorgestellte Verfahren nutzt die Tatsache aus, dass das Datenvolumen auf monatlicher Basis abgerechnet wird und jeden Monat das Freivolumen zur Verfügung steht. Das Freivolumen sollte nicht zu klein gewählt werden. In vielen Fällen steht auch eine Backupmöglichkeit beim Hoster zuer Verfügung, deren Traffic nicht berechnet wird.

 

Was muss gesichert werden ?

Die Beantwortung dieser Frage spart schon manchen Traffic. Bei einem Debian Linux müssen auf jeden Fall gesichert werden:

  • Paketliste
  • /etc (dort sind praktisch alle Konfigurationen zu finden)
  • /home (die Dateien der Benutzer)
  • evtl. /var/lib und /var/spool weil da Statusdateien liegen können

Der Rest kann meist mit den Installations CDs problemlos wiederhergestellt werden. Nach dem ersten Backup Lauf sollte man versuchen, den so gewonnenen Datenbestand zu hause auf einem PC neu aufzusetzen. Ist das Backup ok, dann sollte man auf dem PC nun eine genaue Kopie seines Root Servers haben.

Backup Tools

backup2l ist eine einfache, aber für einen Root-Server meist ausreichende Lösung. Es werden keine SQL Datenbanken etc. benötigt. Die Konfiguration besteht aus einem Config-File und einigen Skripten, die auch bei problematischer Software zu brauchbaren Backups führen.

/etc/backup2l.conf

Die Konfiguration legt fest, was gesichert wird und ruft verschiedene Skripte auf, damit ein konsistenes Backup sichergestellt wird. 

##################################################
# Configuration file for backup2l #
##################################################


# Define the backup2l version for which the configuration file is written.
# This way, future versions can automatically warn if the syntax has changed.
FOR_VERSION=1.4

##################################################
# Volume identification
# This is the prefix for all output files;
# multiple volumes can be handled by using different configuration files
VOLNAME="all"



##################################################
# Source files

# List of directories to make backups of.
# All paths MUST be absolute and start with a '/'!
SRCLIST=(/etc /root /home /usr/local /var/lib /var/spool /opt /var/backups /backup.d/premilinary)

# The following expression specifies the files not to be archived.
# See the find(1) man page for further info. It is discouraged to
# use anything different from conditions (e. g. actions) as it may have
# unforeseeable side effects.

# This example skips all files and directories with a path name containing
# '.nobackup' and all .o files:
SKIPCOND=(-path "*.nobackup*" -o -name "*.o")

# If you want to exclude several directories use the following expression:
# SKIPCOND=(-path '/path1' -o -path '/path1/*' -o -path '/path2' -o -path '/path2/*')

# NOTE: If you do not have anything to skip, use:
# SKIPCOND=(-false) # "SKIPCOND=()" does not work



##################################################
# Destination

# Mount point of backup device (optional)
#BACKUP_DEV="/disk2"

# Destination directory for backups;
# it must exist and must not be the top-level of BACKUP_DEV
BACKUP_DIR="/backup.d/final"

##################################################
# Backup parameters

# Number of levels of differential backups (1..9)
MAX_LEVEL=1

# Maximum number of differential backups per level (1..9)
MAX_PER_LEVEL=9

# Maximum number of full backups (1..8)
MAX_FULL=1

# For differential backups: number of generations to keep per level;
# old backups are removed such that at least GENERATIONS * MAX_PER_LEVEL
# recent versions are still available for the respective level
GENERATIONS=1

# If the following variable is 1, a check file is automatically generated
CREATE_CHECK_FILE=1

##################################################
# Pre-/Post-backup functions

# This user-defined bash function is executed before a backup is made
PRE_BACKUP ()
{
echo "start pre backup scripts"

cd /crypt/backup.d/scripts
sh ./hotcopy-mysql.sh
sh ./hotcopy-cyrus.sh
sh ./hotcopy-exim.sh
sh ./hotcopy-ldap.sh
sh dump-dpkg-selections.sh

chmod -R u=rw,go-rwx /backup.d/preliminary/*
umask 177
echo "pre backup scripts completed"
}

# This user-defined bash function is executed after a backup is made
POST_BACKUP ()
{
echo "Executing post backup actions."

cd /crypt/backup.d/scripts
chown -R root:backup /crypt/backup.d/final
chmod -R u=rw,g=r /crypt/backup.d/final/*

echo "The backup has been completed."
echo "----------------------------------------------"

sh ./send.sh
}

##################################################
# Misc.

# Create a backup when invoked without arguments?
AUTORUN=0

# Size units
SIZE_UNITS="" # set to "B", "K", "M" or "G" to obtain unified units in summary list

# Archive driver for new backups (optional, default = "DRIVER_TAR_GZ")
# CREATE_DRIVER="DRIVER_MY_AFIOZ"



##################################################
# User-defined archive drivers (optional)

# This section demonstrates how user-defined archive drivers can be added.
# The example shows a modified version of the "afioz" driver with some additional parameters
# one may want to pass to afio in order to tune the speed, archive size etc. .
# An archive driver consists of a bash function named
# "DRIVER_<your-driver-name>" implementing the (sometimes simple) operations "-test", "-suffix",
# "-create", "-toc", and "-extract".

# If you do not want to write your own archive driver, you can remove the remainder of this file.

# USER_DRIVER_LIST="DRIVER_MY_AFIOZ" # uncomment to register the driver(s) below (optional)

DRIVER_MY_AFIOZ ()
{
case $1 in
-test)
# This function should check whether all prerequisites are met, especially if all
# required tools are installed. This prevents backup2l to fail in inconvenient
# situations, e. g. during a backup or restore operation. If everything is ok, the
# string "ok" should be returned. Everything else is interpreted as a failure.
require_tools afio
# The function 'require_tools' checks for the existence of all tools passed as
# arguments. If one of the tools is not found by which(1), an error message is
# displayed and the function does not return.
echo "ok"
;;
-suffix)
# This function should return the suffix of backup archive files. If the driver
#�does not create a file (e. g. transfers the backup data immediately to a tape
# or network device), an empty string has to be returned. backup2l uses this suffix
# to select a driver for unpacking. If a user-configured driver supports the same
# suffix as a built-in driver, the user driver is preferred (as in this case).
echo "afioz"
;;
-create) # Arguments: $2 = BID, $3 = archive file name, $4 = file list file
# This function is called to create a backup file. The argument $3 is the full file
# name of the archive file including path and suffix. $4 contains a list of files
# (full pathname) to be backed up. Directories are not contained, they are handled
# by backup2l directly without using the driver. All output to stderr should be
# directed to stdout ("2>&1").
afio -Zo -G 9 -M 30m -T 2k $3 < $4 2>&1
# This line passes some additional options to afio (see afio(1)):
# '-G 9' maximizes the compression by gzip.
# '-M 30m' increases the size of the internal file buffer. Larger files have to
# be compressed twice.
# '-T 2k' prevents the compression of files smaller than 2k in order to save time.
;;
-toc) # Arguments: $2 = BID, $3 = archive file name
# This function is used to validate the correct generation of an archive file.
# The output is compared to the list file passed to the '-create' function.
# Any difference is reported as an error.
afio -Zt $3 | sed 's#^#/#'
# The sed command adds a leading slash to each entry.
;;
-extract) # Arguments: $2 = BID, $3 = archive file name, $4 = file list file
# This function is called by backup2l's restore procedure for each archive.
# It is extremely important that only those files contained in $4 are restored.
# Otherwise it may happen that files are overwritten by incorrect (e. g. older)
# versions of the same file.
afio -Zinw $4 $3 2>&1
;;
esac
}



##################################################
# More sample archive drivers (optional)

# This is an unordered collection of drivers that may be useful for you,
# either to use them directly or to derive own drivers.


# Here's a version of the standard DRIVER_TAR_GZ driver,
# modified to split the output archive file into multiple sections.
# (donated by Michael Moedt)
DRIVER_TAR_GZ_SPLIT ()
{
case $1 in
-test)
require_tools tar split cat
echo "ok"
;;
-suffix)
echo "tgz_split"
;;
-create) # Arguments: $2 = BID, $3 = archive file name, $4 = file list file
mkdir -p ${3}
tar cz -T $4 --no-recursion | split --bytes=725100100 - ${3}/part_
;;
-toc) # Arguments: $2 = BID, $3 = archive file name
cat ${3}/part_* | tar tz | sed 's#^#/#'
;;
-extract) # Arguments: $2 = BID, $3 = archive file name, $4 = file list file
cat ${3}/part_* | tar xz --same-permission --same-owner -T $4 2>&1
;;
esac
}


# This driver uses afio and bzip2, where bzip2 is invoked by afio.
# (donated by Carl Staelin)
DRIVER_MY_AFIOBZ2 ()
{
case $1 in
-test)
require_tools afio bzip2
echo "ok"
;;
-suffix)
echo "afio-bz2"
;;
-create) # Arguments: $2 = BID, $3 = archive file name, $4 = file list file
afio -z -1 m -P bzip2 -Q -9 -Z -M 50m -T 1k - <$4 >$3 2>&1
# This line passes some additional options to afio (see afio(1)):
# '-P bzip2' utilizes bzip2 as an external compressor
# '-Q 9' maximizes the compression by bzip2.
# '-M 50m' increases the size of the internal file buffer. Larger files have to
# be compressed twice.
# '-T 1k' prevents the compression of files smaller than 1k in order to save time.
;;
-toc) # Arguments: $2 = BID, $3 = archive file name
afio -t -Z -P bzip2 -Q -d - <$3 | sed 's#^#/#'
# The sed command adds a leading slash to each entry.
;;
-extract) # Arguments: $2 = BID, $3 = archive file name, $4 = file list file
afio -Zinw $4 -P bzip2 -Q -d - <$3 2>&1
;;
esac
}


# This driver uses afio and bzip2, such that the I/O stream is piped through bzip2.
# (donated by Carl Staelin)
DRIVER_MY_AFIO_BZ2 ()
{
case $1 in
-test)
require_tools afio bzip2
echo "ok"
;;
-suffix)
echo "afio.bz2"
;;
-create) # Arguments: $2 = BID, $3 = archive file name, $4 = file list file
afio -o - < $4 | bzip2 --best > $3 2>&1
;;
-toc) # Arguments: $2 = BID, $3 = archive file name
bzip2 -d < $3 | afio -t - | sed 's#^#/#'
# The sed command adds a leading slash to each entry.
;;
-extract) # Arguments: $2 = BID, $3 = archive file name, $4 = file list file
bzip2 -d < $3 | afio -inw $4 - 2>&1
;;
esac

Wird ein Backupserver beim Hoster verwendet, dann sollten die Backup-Files unbedingt mit GnuPG verschlüsselt werden. Man weiss nie, wer da alles auf die Files zugreifen kann.

Ansonsten müssen nun noch die Skripte aufgebaut werden.

MySQL 

In hotcopy-mysql.sh wird MySQL gesichert. Zweckmäßigerweise erstellt man einen Dump der gesamten Datenbank. Falls einzelne Datenbanken sehr groß sind, werden diese in gesonderten Dumps gesichert. 

#!/bin/sh

umask 077
DST="/backup.d/preliminary/mysql"

# This script creates a hot copy of the mysql data files.
echo "creating mysql dump"

echo "   removing old dumps and creating directory"
mkdir -p ${DST} > /dev/null 2> /dev/null
rm ${DST}/all.dump

echo "   executing mysqldump"
mysqldump -AR --add-locks -u root --password=geheim > ${DST}/all.dump

echo "mysql dump created"

Mit diesem Dump kann man MySQL komplett wiederherstellen.

LDAP

Auf ähnlichem Wege wird LDAP gesichert 

#!/bin/sh

umask 077
DST=/backup.d/preliminary/ldap
# This script creates a hot copy of the mysql data files.
echo "creating ldap dump"

echo "   removing old dumps and creating directory"
rm -rf ${DST}
mkdir -p ${DST} > /dev/null 2> /dev/null

echo "   executing slapcat"
slapcat > ${DST}/ldap.ldif

echo "ldap dump created

Damit kann LDAP wiederhergestellt werden.

Cyrus

Bei Cyrus wird es etwas schwieriger, da es nicht sonderlich backupfreundlich ist. 

#!/bin/sh

# This script creates a hot copy of the cyrus data files.

# We use a trick from the cyrus wiki. First, we use rsync to copy the spool
# and the cyrus dbs to the preliminary backup directory. Then, we shut down
# cyrus, rsync again and start cyrus again. This way, we reduce cyrus' downtime
# to a minimum.

echo "creating Cyrus backup"

echo "   creating directories"
rm -rf /backup.d/preliminary/cyrus
rm -rf /backup.d/preliminary/sieve
mkdir -p /backup.d/preliminary/cyrus/lib
mkdir -p /backup.d/preliminary/cyrus/spool
mkdir -p /backup.d/preliminary/sieve/spool

echo "   first rsync pass"

rsync -a /var/lib/cyrus /crypt/backup.d/preliminary/cyrus/lib
rsync -a /var/spool/cyrus /crypt/backup.d/preliminary/cyrus/spool
rsync -a /var/spool/sieve /crypt/backup.d/preliminary/sieve/spool

echo "   halting cyrus"
/etc/init.d/cyrus2.2 stop

echo "   second rsync pass"
rsync -a /var/lib/cyrus /crypt/backup.d/preliminary/cyrus/lib
rsync -a /var/spool/cyrus /crypt/backup.d/preliminary/cyrus/spool
rsync -a /var/spool/sieve /crypt/backup.d/preliminary/sieve/spool

echo "   starting cyrus again"
/etc/init.d/cyrus2.2 start
echo "Cyrus backup finished

Der Trick besteht darin zunächst alles zu sichern, obwohl Cyrus läuft. Danach wird Cyrus angehalten, noch einmal mit rsync gesichert und es werden dann die Dateien überschrieben, die sich seit der letzten Sicherung geändert haben. Die Downtime ist dann sehr kurz und man hat dennoch ein konsistentes Backup seines E-Mail Systems.

Exim4

Die meisten MTAs wie Exim4 oder Postfix unterhalten ebenfalls kleine Datenbanken, die nur zuverlässig gesichert werden können, wenn das Mailsystem angehalten wird. Deshalb das gleiche Vorgehen, wie bei Cyrus. 

#!/bin/sh

# We use the same trick as with cyrus here: rsync, shutdown, rsync again and
# hopefully our backup is clean then.

echo "creating Exim backup"

echo "   creating backup directories"
rm -rf /backup.d/preliminary/exim
mkdir -p /backup.d/preliminary/exim

echo "   first rsync pass"
rsync -a /var/spool/exim4 /backup.d/preliminary/exim

#echo "   stop exim"
/etc/init.d/exim4 stop

echo "   second rsync pass"
rsync -a /var/spool/exim4 /backup.d/preliminary/exim

echo "   start exim again"
/etc/init.d/exim4 start
echo "Exim backup finished

Nachdem nun auch die MTA Files gesichert sind, muss das Backup nun an einem sicheren Ort aufbewahrt werden.

Sichern (Backup bei Hoster)

Die Backup Dateien liegen nun in einem Verzeichnis. Nun müssen sie an einen sicheren Ort übertragen werden. Die Dateien sind bereits mit gzip kompremiert, so dass nicht mehr Platz und Übertragungsvolumen als notwendig verbraucht werden.

Werden die Dateien auf einem Backupserver des Hosters gesichert, so ist dringend eine Verschlüsselung zu empfehlen. Am besten wird das Verzeichnis /backup.d/final mit tar in ein Archiv gepackt und dieses dann verschlüsselt. 

#!/bin/sh

cd /home/backup
tar cvf backup.tgz final
gpg -e -r AABBCCDD backup.tgz

Man erhält dann eine Datei backup.tgz.gpg, diese kann dann auf den Backupserver übertragen werden. AABBCCDD ist die Schlüssel-ID.  Ohne den privaten Schlüssel und der Passphrase kommt dann niemand an das Backup heran. Beides sollte sich nicht af dem zu sichernden Server befinden.

Sichern (Backup über DSL)

Will man die Backups zu hause haben, bietet sich wieder rsync an, einmal im Monat sollte man dann ein Full Backup machen und ansonsten ein inkrementelles Backup. 

#!/bin/sh

TARGET=172.17.0.10
TARGETPATH="/home/backup/files"
SRCPATH="/backup.d/final"

rsync --stats -v -z -c -r -l -p -g -e "ssh -i /backup.d/scripts/id_rsa" --delete --force \
        ${SRCPATH}/ \
        backup@${TARGET}:${TARGETPATH}

Es wird davon ausgegangen, dass die rsync Übertragung über ssh mit hinterlegtem Key erfolgt. Dazu wird ein gesondertes Schlüsselpaar erzeugt, der private Schlüssel wird im Skript angegeben.

 

Aktualisiert ( Freitag, 15. Februar 2008 10:42 )