Archive

Kategorien

Backup Script für LVM Volumes

Backup LVM Volumes
LVM (Logical Volume Manager) bietet unter Linux die einfache Möglichkeit flexibel Speicherplatz zur Verfügung zu stellen. Dabei kann LVM sowohl ganze Platten oder auch nur Partitionen verwalten. Diese werden zu sogeannten Volume Groups (VG) zusammengefasst. In diesen VG kann man dann Logical Volume(s) (LV) erstellen, welche dann die Daten aufnehmen können. Diese LV werden als Block Devices zur Verfügung gestellt, damit kann man ihnen alles machen was man sonst mit Block Devices macht z.B. Partitionieren.

LVM Snapshot
Hier soll es um das Backup von LVs gehen, denn dieses kann je nach Anforderung etwas komplizierter werden. Trotzdem wird das Backup durch ein sehr nettes Feature von LVM etwas erleichtert. LVM bietet die Möglichkeit sogeannte Snapshots zu machen, dabei wird ein LV in einem konsistenten Zustand gehalten, damit man davon ein Backup machen kann.

Ein Snapshot des LV meinSystem in der VG vg_system kann man so erstellen

1
lvcreate -s -L5G -nbackup /dev/vg_system/meinSystem

Das erstellt einen maximal 5GByte grossen Snapshot d.h. wenn sich mehr als 5GByte Daten am Dateisystem des LV verändern wird dieser Snapshot ungültig. Je nachdem wie schnell und wieviel sich Daten im LV verändern muss man diese Grösse anpassen. Wenn man den Snapshot gleich gross setzt wie die Grösse des LV, dann geht der Platz im Snapshot nie aus.

Image vom Snapshot
Nun hat man unter /dev/vg_system/backup bzw /dev/mapper/vg_system-backup ein Block Device mit dem Snapshot. Dieses könnte man jetzt z.B. mit einem Tool wie dd in ein Image File kopieren

1
2
dd if=/dev/mapper/vg_system-backup of=/pfad/zum/image.img bs=10M
lvremove /dev/vg_system/backup

es ist wichtig den Snapshot nach Gebrauch immer zu entsorgen!

Partitionen aus dem Image mounten
Dieses Image kann man leider meist nicht so ohne weiteres mounten v.a. wenn sich darin verschiedene Partitonen befinden. Dazu muss man sich eines Programms wie z.B. **kpartx** bedienen. Dieses kann aus Image Files die Partitionstabellen rauslesen und die Partitionen einbinden.

1
kpartx -av /pfad/zum/image.img

.
Anhand der Ausgabe von kpartx kann man sehen wo die Devices erstellt wurden z.B. /dev/mapper/vg_system-image1 für die erste Partition. Wenn man das Dateisystem kennt kann man das Ganze dann so mounten

1
mount -t ext3 /dev/mapper/vg_system-image1 /mnt

Dann kann man in /mnt die Daten z.B. mit rsync oder rdiff-backup sichern.

Partitionen direkt aus dem Snapshot mounten
Alternativ kann man sich den Weg über das Image auch sparen und den Snapshot direkt an kpartx übergeben

1
kpartx -av /dev/mapper/vg_system-backup

kpartx bindet die gefundenen Partitionen so ein, dass man die nachher mounten kann. Dabei ist die erste Partition des LV im obigen Beispiel /dev/mapper/vg_system-backup1 und die zweite logischerweise vg_system-backup2. kpartx -av gibt genau an welche Partitionen und wie sie erkannt wurden. Um jetzt also die zweite Partition von oben auf /mnt zu mounten, muss man erst wissen welches Dateisystem sich darin befindet. Ich habe bei mir ext3

1
mount -t ext3 /dev/mapper/vg_system-backup2 /mnt

Jetzt kann man von /mnt z.B. ein Backup mit rsync machen.

Es ist wichtig, dass man zum Schluss (nach dem Backup) folgendes macht:

1
2
3
umount /mnt
kpartx -dv /dev/mapper/vg_system-backup
lvremove /dev/vg_system/backup

Backup Script
Für das Backup der LVs meiner virtuellen Maschinen habe ich mir folgendes Script geschrieben. Allerdings ist es stark an meine Umgebung angepasst, von daher sollte man das nur als Idee sehen und entsprechend selber anpassen. Das Script erstellt bei mir zuverlässig rdiff-backups aller Partitionen der VMs. Das Script mountet dazu die Partitionen direkt aus dem Snapshot-Device, es wird also kein Image erstellt, sondern es erfolgt ein Filebackup auf Filesystembasis

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#!/bin/bash

# export path for use the script in cron
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# "hosts" to backup. These are patterns for matching of lv-volumes
# it specifies the beginning pattern of the lvm to backup
VIRT_HOSTS='
host1.mydomain
host2.mydomain
'

# volume group where $VIRT_HOSTS are situated
VG='vg_virtual'
# basedir for backups
BKP_DIR_FIX='/backup/vm-filesystems'
# enable output to shell by setting to 1
# otherwise it will only be logged to the file
VERB=0
# defines the logfile
BKP_LOG=/var/log/lvm_bkp.log && touch $BKP_LOG

log() {
echo "$(date +%d.%m.%y\ %H:%M:%S) $*" >> $BKP_LOG
[ $VERB -ne 0 ] && echo "$(date +%d.%m.%y\ %H:%M:%S) $*"
return 0
}

getVolumes() {
[ "x$*" = 'x' ] && exit
host="$*"
disk=''
for i in $(lvdisplay | grep \/$host | awk '{print $3}' | grep -v swap) ; do
[ "$i" = 'status' ] && continue
disk=$disk" "$i
done
log "Fetched $disk for $host"
}
createSnapshot() {
[ "x$*" = 'x' ] && exit
disk="$*"
UUID=$(uuid)
log "Creating snapshot of volume $disk" && lvcreate -L10G -s -n $UUID $disk >/dev/null && log "Created snapshot volume for $disk of $host as $UUID"
}
removeSnapshot() {
[ "x$UUID" = 'x' ] && exit
lvremove -f /dev/$VG/$UUID >/dev/null && log "Snapshot $UUID removed"
}
runBackup() {
echo >/tmp/part.tmp
log "Getting devices from $UUID for $(basename $i)"
kpartx -l /dev/$VG/$UUID >/dev/null 2>&1 && kpartx -av /dev/$VG/$UUID >/tmp/part.tmp
if [ "x$(cat /tmp/part.tmp)" = 'x' ] ; then
log "Mount /dev/$VG/$UUID on /mnt"
mount /dev/$VG/$UUID /mnt && log "/dev/$VG/$UUID sucessfully mounted on /mnt"
log "Create backupdir for $(basename $i) on $BKP_DIR_DYN"
mkdir -p $BKP_DIR_DYN/$(basename $i) >/dev/null 2>&1
log "Starting backup for partition on $(basename $i)"
START_BKP=$(date +%s)
[ $VERB -eq 1 ] && rdiff-backup -v0 --print-statistics /mnt/ $BKP_DIR_DYN/$(basename $i)/ | tee -a $BKP_LOG
[ $VERB -ne 1 ] && rdiff-backup -v0 --print-statistics /mnt/ $BKP_DIR_DYN/$(basename $i)/ >> $BKP_LOG
END_BKP=$(date +%s)
log "Backup finished for partition on $BKP_DIR_DYN/$(basename $i) in $(($END_BKP - $START_BKP)) seconds"
log "Umount /mnt" && umount /mnt && log "Sucessfully umounted /mnt"
sleep 2
touch $BKP_DIR_DYN/$(basename $i)/ && return 0
fi
while read line ; do
PART="$(echo $line | awk '{print $3}' | grep -v 2$)"
[ "x$PART" = 'x' ] && continue
count=${PART: -1}
#echo $count && continue
FS=$(blkid /dev/mapper/$PART | awk '{print $3}' | awk -F'"' '{print $2}')
[ "$FS" = 'swap' ] && continue
[ "x$FS" = 'x' ] && continue
log "Mount /dev/mapper/$PART on /mnt"
mount -t $FS /dev/mapper/$PART /mnt/ && log "/dev/mapper/$PART sucessfully mounted on /mnt"
sleep 1
log "Create backupdir for $(basename $i) on $BKP_DIR_DYN"
mkdir -p $BKP_DIR_DYN/$(basename $i) >/dev/null 2>&1
log "Starting backup for partition $count into $BKP_DIR_DYN/$(basename $i)/partition-${count}"
START_BKP=$(date +%s)
[ $VERB -eq 1 ] && rdiff-backup -v0 --print-statistics /mnt/ $BKP_DIR_DYN/$(basename $i)/partition-${count}/ | tee -a $BKP_LOG
[ $VERB -ne 1 ] && rdiff-backup -v0 --print-statistics /mnt/ $BKP_DIR_DYN/$(basename $i)/partition-${count}/ >> $BKP_LOG
END_BKP=$(date +%s)
log "Backup finished for partition $count on $BKP_DIR_DYN/$(basename $i) in $(($END_BKP - $START_BKP)) seconds"
log "Umount /mnt" && umount /mnt && log "Sucessfully umounted /mnt"
touch $BKP_DIR_DYN/$(basename $i)/partition-${count}
done /dev/null && log "Partitions removed successfully" && touch $BKP_DIR_DYN/$(basename $i)/
}

log "Backup started" && START=$(date +%s)
for host in $VIRT_HOSTS ; do
[ "$host" = 'localhost' ] && VG='vg_sys' && BKP_DIR_DYN='/sys-backup'
[ "$host" != 'localhost' ] && VG='vg_virtual' && BKP_DIR_DYN=$BKP_DIR_FIX
getVolumes $host
for i in $disk ; do
createSnapshot $i
runBackup
removeSnapshot
done
done
END=$(date +%s)
END=$(($END - $START))
log "Backup finished in "$END" seconds"

Leave a Reply

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">

  

  

  

one × five =

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahren Sie mehr darüber, wie Ihre Kommentardaten verarbeitet werden .