Auf Nummer sicher: Backupstrategie
Als ich heute mit Dennis, der jetzt seine Backup-Strategie aufstockt, über mögliche Backup-Implementationen diskutiert habe, kam mir die Idee, meine persönliche Vorgehensweise zu erläutern.
Die Hardware
Neben den Clients, die die zu sichernden Daten beherbergen, steht mir folgende Hardware für Backups zur Verfügung:
- NAS - Eigenbau-Gerät mit energiesparendem AMD-Prozessor, 4 GB Arbeitsspeicher und sechs 1 TB-Festplatten im Software-RAID 5 (4.5 TB nutzbar)
- Bandroboter - ein gebrauchter HP StorageWorks DAT72-Autoloader mit einem DDS5-Bandlaufwerk und 10 Schächten für Medien
- Externe Festplatte (genau genommen ein DAS) - eine Onnto DataTale mit vier 2 TB-Festplatten im RAID5 (6 TB nutzbar)
Datenüberblick
Die erste Frage dürfte jetzt sein, was überhaupt gesichert wird. Sicherungen werden auf meinem NAS pro "Sicherungsziel" angelegt - solche Sicherungsziele sind beispielsweise:
- Der Webserver, auf dem dieser Blog läuft 😉
- Mein Notebook
- Die virtuellen Maschinen meines Hypervisors
- ...
Für jedes Sicherungsziel wird auf dem NAS ein Ordner angelegt. Innerhalb dieses Ordners existiert ein Unterordner "latest" - in diesem Ordner landen dann die jeweils zu sichernden aktuellen Daten. Wenn eine Sicherung isoliert von neueren aufbewahrt werden soll, genügt es den Ordnernamen zu ändern. So habe ich schnell und unkompliziert einen "Snapshot". Auf dem NAS befindet sich im Backup-Ordner für jedes Sicherungsziel eine Blacklist-Datei (Sicherungsziel_blacklist), die eine Liste von Ordnern und Dateien, die nicht auf Band gesichert werden sollen, enthält.
Skripte und Logdateien
Für die Sicherung der einzelnen Sicherungsziele habe ich mir diverse Skripte programmiert, die mir einige händische Arbeit abnehmen und den Prozess so beschleunigen.
Sicherungen eines Ziels erfolgen mithilfe des folgenden Skripts:
1#!/bin/bash
2
3###########################################
4# #
5# !!! AUTOMATISIERTE SICHERUNG !!! #
6# #
7###########################################
8
9#Variablendeklaration
10backups_path="/mnt/storage/data/Backups"
11exclude_file_prefix="blacklist_"
12max_size_gb=200
13dev_streamer="$1"
14
15#Datumprefix und Logfile erstellen
16logprefix="$(date +"%d_%m_%Y_%H_%M")"
17if [ -d "/var/log/backup/tape/$2" ]; then
18 #Ordner vorhanden
19 echo "Log directory for this target (/var/log/backup/tape/$2) exists."
20else
21 #Ordner nicht vorhanden
22 mkdir -p /var/log/backup/tape/$2
23 echo "Log directory for this target (/var/log/backup/tape/$2) didn't exist - I created it for you. 🙂"
24fi
25echo "log file from $(date)" >> /var/log/backup/tape/$2/$logprefix.log
26echo "parameters were: $1 $2 $3 $4" >> /var/log/backup/tape/$2/$logprefix.log
27
28#Wurde ein Streamer angegeben?
29if [ "$1" = "" ]; then
30 #Nein
31 echo "ERROR: You must specify a streamer device (e.g. nst0)!" | tee -a /var/log/backup/tape/$2/$logprefix.log
32 exit 1
33fi
34
35#Wurde ein Ziel angegeben?
36if [ "$2" = "" ]; then
37 #Nein
38 echo "ERROR: You must specify a target (e.g. host)!" | tee -a /var/log/backup/tape/$2/$logprefix.log
39 echo "Aborting..." | tee -a /var/log/backup/tape/$2/$logprefix.log
40 exit 1
41fi
42
43#Flag setzen
44if [ "$3" = "--from" ]; then
45 #Ein vorheriges Backup wurde angefordert --> wurde ein Datum angegeben?
46 if [ "$4" = "" ]; then
47 #Nein
48 echo "ERROR: You need to tell me the backup date in DD_MM as parameter after --from!" | tee -a /var/log/backup/tape/$2/$logprefix.log
49 echo "Aborting..." | tee -a /var/log/backup/tape/$2/$logprefix.log
50 exit 1
51 else
52 sel_flag="$4"
53 fi
54
55else
56 #Setze Flag
57 sel_flag="latest"
58fi
59
60#Ordner fuer Backup vorhanden?
61if [ -d "$backups_path/$2/$sel_flag" ]; then
62 #Ja
63 echo "Backup exists" | tee -a /var/log/backup/tape/$2/$logprefix.log
64else
65 #Nein
66 echo "ERROR: There is no backup #$sel_flag for that target!" | tee -a /var/log/backup/tape/$2/$logprefix.log
67 echo "Aborting..." | tee -a /var/log/backup/tape/$2/$logprefix.log
68 exit 1
69fi
70
71#Ueberpruefe ob das Backup auf das Tape passt
72backup_size="$(du -cs $backups_path/$2/$sel_flag --exclude-from=$backups_path/$exclude_file_prefix$2 | grep insgesamt | cut -f1)"
73echo -n "Backup size is $backup_size kbytes" | tee -a /var/log/backup/tape/$2/$logprefix.log
74
75if [ "$backup_size" -gt "$(($max_size_gb*1024*1024))" ]; then
76 #Nein
77 echo ", more than $max_size_gb gbytes - that won't fit!" | tee -a /var/log/backup/tape/$2/$logprefix.log
78 echo "Aborting..." | tee -a /var/log/backup/tape/$2/$logprefix.log
79 exit 1
80else
81 #Ja
82 echo " - that will fit." | tee -a /var/log/backup/tape/$2/$logprefix.log
83fi
84
85#Streamer vorhanden?
86if [ "$(ls /dev | grep $dev_streamer)" = "" ]; then
87 echo "ERROR: Streamer device not found" | tee -a /var/log/backup/tape/$2/$logprefix.log
88 echo "Aborting..." | tee -a /var/log/backup/tape/$2/$logprefix.log
89 exit 1
90fi
91
92#Ist das Geraet belegt?
93echo -n "Checking whether the device is currently in use..." | tee -a /var/log/backup/tape/$2/$logprefix.log
94if [ "$(mt -f /dev/$dev_streamer status | grep busy)" = "" ]; then
95 #Nein
96 echo "NO" | tee -a /var/log/backup/tape/$2/$logprefix.log
97else
98 #Ja
99 echo "YES" | tee -a /var/log/backup/tape/$2/$logprefix.log
100 echo "Aborting..." | tee -a /var/log/backup/tape/$2/$logprefix.log
101 exit 1
102
103fi
104
105#Ist ein Band eingelegt?
106echo -n "Checking whether a tape is inserted..." | tee -a /var/log/backup/tape/$2/$logprefix.log
107if [ "$(mt -f /dev/$dev_streamer status | grep DR_OPEN)" = "" ]; then
108 #Ja
109 echo "YES" | tee -a /var/log/backup/tape/$2/$logprefix.log
110else
111 #Nein
112 echo "NO" | tee -a /var/log/backup/tape/$2/$logprefix.log
113 echo "Aborting..." | tee -a /var/log/backup/tape/$2/$logprefix.log
114 exit 1
115fi
116
117#Spiele Band zurueck
118echo "Rewinding tape..." | tee -a /var/log/backup/tape/$2/$logprefix.log
119mt -f /dev/$dev_streamer rewind | tee -a /var/log/backup/tape/$2/$logprefix.log
120
121#Gebe Dateien aus
122echo "The FOLLOWING files will be backupped:" | tee -a /var/log/backup/tape/$2/$logprefix.log
123echo "" | tee -a /var/log/backup/tape/$2/$logprefix.log
124du -h "$backups_path/$2/$sel_flag/" --exclude-from="$backups_path/$exclude_file_prefix$2" | tee -a /var/log/backup/tape/$2/$logprefix.log
125
126#Sichere Daten
127echo "About to backup files..." | tee -a /var/log/backup/tape/$2/$logprefix.log
128tar cvzf "/dev/$dev_streamer" "$backups_path/$2/$sel_flag/" --exclude-from="$backups_path/$exclude_file_prefix$2" | tee -a /var/log/backup/tape/$2/$logprefix.log
Eine Sicherung des Ziels "hostA
" auf das Bandlaufwerk "/dev/st0
" erfolgt beispielsweise wie folgt:
1# ./backup.sh st0 hostA
Für jedes Sicherungsziel habe ich noch ein dediziertes Wochen- und Monatsskript, welches mithilfe von mtx
das entsprechende Band gleich in den Bandroboter einlegt und das o.g. Backup-Skript mit den notwendigen Paramtern startet.
1#!/bin/sh
2TAPE_DEV="/dev/sg8"
3TAPE1="7"
4TAPE2="8"
5
6mtx -f $TAPE_DEV load $TAPE1
7./backup.sh st0 hostA
8mtx -f $TAPE_DEV unload $TAPE1
9mtx -f $TAPE_DEV load $TAPE2
10./backup.sh st0 hostA
11mtx -f $TAPE_DEV unload $TAPE2
Für die Sicherung meines Webservers habe ich ein Skript geschrieben, welches den FTP-Server mit curlftpfs
mountet und die Dateien mithilfe von rsync
kopiert:
1#!/bin/bash
2
3##########################################
4# #
5# Webspace-Spiegelung mittels RSync #
6# --------------------------------- #
7# #
8# 2011 By Christian Stankowic #
9# info@christian-stankowic.de #
10# #
11##########################################
12
13#Variablendeklaration
14path_curlftpfs="/usr/bin/curlftpfs"
15path_rsync="/usr/bin/rsync"
16path_tee="/usr/bin/tee"
17
18ftp_server="..."
19ftp_mount="/mnt/ftp"
20ftp_user="..."
21ftp_pass="..."
22
23log_path="/var/log/backup/ftp"
24copy_path="/mnt/storage/data/Backups/web/latest"
25
26#Datumprefix und Logfile erstellen
27logprefix="$(date +"%d_%m_%Y_%H_%M")"
28echo "log file from $(date)" >> $log_path/$logprefix.log
29echo "parameters were: $1 $2 $3 $4" >> $log_path/$logprefix.log
30
31#FTP mounten
32curlftpfs $ftp_server $ftp_mount -o user=$ftp_user:$ftp_pass
33
34#Spiegel gemountet?
35echo "Checking if ftp is mounted..." | $path_tee -a $log_path/$logprefix.log
36if [ "$(mount | grep $ftp_mount)" = "" ]; then
37 echo "Error: Mirror ($ftp_mount) NOT mounted" | $path_tee -a $log_path/$logprefix.log
38 exit 1
39else
40 echo "Mirror ($ftp_mount) mounted" | $path_tee -a $log_path/$logprefix.log
41fi
42
43#Spiegelung
44$path_rsync -a -r --delete -v $ftp_mount $copy_path | $path_tee -a $log_path/$logprefix.log
45
46#FTP unmounten
47umount $ftp_mount
Die Spiegelung der NAS-Daten auf das DAS erfolgt mit einem einfachen rsync-Skript:
1#!/bin/bash
2
3######################################
4# #
5# !!! SPIEGEL AUF DATATALE !!! #
6# #
7######################################
8
9#Variablendeklaration
10backups_path="/mnt/storage/data/Backups"
11
12#Datumprefix und Logfile erstellen
13logprefix="$(date +"%d_%m_%Y_%H_%M")"
14echo "log file from $(date)" >> /var/log/backup/mirror/$logprefix.log
15echo "parameters were: $1 $2 $3 $4" >> /var/log/backup/mirror/$logprefix.log
16
17#Spiegel gemountet?
18echo "Checking if mirror is mounted..." | tee -a /var/log/backup/mirror/$logprefix.log
19if [ "$(mount | grep /mnt/mirror)" = "" ]; then
20 echo "Error: Mirror (/mnt/mirror) NOT mounted" | tee -a /var/log/backup/mirror/$logprefix.log
21 exit 1
22else
23 echo "Mirror (/mnt/mirror) mounted" | tee -a /var/log/backup/mirror/$logprefix.log
24fi
25
26#Spiegelung
27rsync -a -r --exclude-from "/opt/bak/exclude_rsync" --delete -v /mnt/storage/data/ /mnt/mirror/data/ | tee -a /var/log/backup/mirror/$logprefix.log
Alle Skripte legen übrigens Logdateien unterhalb von /var/log/backup
an - so kann ich nachvollziehen, ob die automatisierten Backups fehlerfrei durchlaufen sind:
1# cd /var/log/backup/tape/hostA
2# 29_01_2012_20_42.log
3log file from So 29. Jan 20:42:48 CET 2012
4parameters were: st0 hostA
5Backup exists
6Backup size is 1226994 kbytes - that will fit.
7Checking whether the device is currently in use...NO
8Checking whether a tape is inserted...YES
9Rewinding tape...
10The FOLLOWING files will be backupped:
11
1224K ...
13...
Zeitliche Planung
Sicherungen sind nur dann sinnvoll, wenn man sie auch konsequent und regelmäßig durchführt.
Meine Planung sieht derzeit wie folgt aus:
- Tägliche automatisierte Generierung von Sicherungsdaten auf bestimmten Hosts - i.d.R wichtige Server-Systeme
- Wöchentliche händische Synchronisation der Notebook-Daten auf das NAS
- Wöchentliche händische Sicherung des Webservers inklusive Datenbanken mithilfe von MySQLDumper und eines FTP-Skripts
- Wöchentliche skriptgesteuerte doppelte Sicherung auf Band und Synchronisation mit DataTale
Bänder, Bänder, Bänder,...
Die Sicherung auf Band erfolgt in der Regel immer doppelt. Das hat zur Folge, dass ich von jedem Backup zwei Bänder hab - ein Band landet im Schrank, das andere bewahre ich an einem anderen Ort (außerhalb meiner Wohnung) auf.
Ich habe für jedes "Sicherungsziel" habe ich dedizierte Bänder für wöchentliche, monatliche und jährliche Backups. Auf dem Jahresband landet die Jahressicherung, während das Monatsband jeden Monat mit dem aktuellen Datenbestand überschrieben wird. Ebenso ist es mit dem Wochenband, was jede Woche überschrieben wird. Die Sicherungen sind übrigens Full-Backups - ich praktiziere keine inkrementellen Backups auf Band. Der wöchentliche Backup-Vorgang nimmt 2 bis 4 Stunden Zeit in Anspruch.
Das Ganze mag jetzt ein wenig übertrieben klingen - ich sichere allerdings auch geschäftliche Daten, die ich 10 Jahre vorhalten muss. Und wenn ich ohnehin schon profesionell Backups anfertige, können davon meine privaten Daten auch profitieren, oder? 🙂
Videos
Einen Überblick über den DDS-Bandroboter und dessen Funktionen gibt es im ersten Clip:
Wer schon immer mal wissen wollte, wie ein Bandroboter arbeitet, kann sich das Ganze hier mal anschauen:
Mein DAS habe ich vor einiger Zeit mit neuen Festplatten versorgt - zu sehen ist das im letzten Clip: