Roh eingepökelt (Linux-Magazin, November 2006)

Mit einer Rescue-CD und einem Perl-Skript lassen sich komplette Festplatten von Clients im lokalen Netz auf einem Backup-Server sichern.

Was tun, wenn die Festplatte ausfällt? Schnellstens eine neue kaufen und das letzte Backup einspielen, natürlich. Was aber, wenn mehrere Partitionen auf der Platte waren? Wieviel Platz war jeder zugeordnet? Welches Filesystem war dort installiert?

Am einfachsten ist es, rohe Partitionen zu sichern, die lassen sich nach einem Ausfall problemlos wieder restaurieren. Stellt die zu sichernde Partition jedoch das Root-Verzeichnis eines laufenden Linux-Systems oder läuft auf einem Laptop gar Windows, ist es nicht ohne weiteres möglich, während des Betriebes gefahrlos eine Kopie der rohen Platte zu sichern.

Notfall-CD als Backup-Lösung

Auf sysresccd.org ([2]) gibt es allerdings eine Rescue-CD, die eine beliebige x86-Machine in ein Minimal-Linux ohne X-Windows bootet, das wichtige Tools wie partimage, sfdisk, fdisk, perl und einen NFS-Client enthält. So kann man Kontakt mit einem NFS-basierten Backup-Server (Installation siehe unten) aufnehmen und sowohl das Partitionierungs-Layout als auch die Partitionen selbst sichern.

Aber natürlich möchte niemand umständliche Kommandos tippen, um ein Backup anzulegen. Nach dem Einlegen der CD in den zu sichernden Rechner sollte möglichst alles automatisch ablaufen. Deshalb stellen wir heute eine leicht angepasste Boot-CD her, die nur kurz fragt, um welchen Rechner es sich gerade handelt, und die dann selbständig Kontakt zum Backup- Server aufnimmt und alle Festplatten sichert.

(Bitte das Diagramm mit einem Grafikprogramm erstellen, danke!)

Abbildung 1: Rechner im lokalen Netz werden ueber die sysresccd auf einem NFS-Server gesichert.

Wie das Diagramm in Abbildung 1 zeigt, nimmt ein mit der Backup-CD gebooteter Rechner über das autorun-Skript sofort Kontakt mit dem unter der IP 192.168.0.40 angeschlossenen Backup-Server auf. Ein zur sysrescCD hinzugefügtes autorun-Skript (Listing 1) initialisiert hierfür zunächst das Netzwerk und startet anschließend NFS mit den zugehörigen Daemons lockd und portmap. Dann mountet es das Verzeichnis /backup des Backup-Servers unter /mnt/backup auf dem zu sichernden Rechner. Dort steht dann das zu einem Binary kompilierte Perlskript bin/pbb.bin (Partition-Based-Backup) des Backup-Servers bereit. autorun ruft es über NFS auf und lässt es auf dem zu sichernden Rechner ablaufen.

Dieses fragt den User mit folgendem Menü nach dem Namen des zu sichernden Rechners:

  [1] desktop1
  [2] desktop2
  [3] laptop1
  Box [1]>

Tippt der User eine Menünummer und die Return-Taste, läuft das Backup unter dem ausgewählten Namen an. Steht hingegen eine Restaurierung an, bricht er einfach mit CTRL-C ab und operiert weiter in der dann aufkommenden Root-Shell.

Listing 1: autorun

    01 IP=192.168.0.40
    02 
    03   # Start network
    04 /etc/init.d/net.eth0 start
    05 /etc/init.d/nfs start
    06 
    07   # Mount directory via NFS 
    08 mkdir /mnt/backup
    09 mount $IP:/backup /mnt/backup ||
    10  (echo "Mount failed ($IP down?)";
    11   exit 1)
    12 
    13   # Run backup script over NFS
    14 /mnt/backup/bin/pbb.bin
    15 
    16   # Close NFS
    17 umount /mnt/backup

Listing pbb zeigt die Source-Version des Backup-Skripts. Die Funktion ask() bietet voreingestellte Rechnernamen aus einer Liste an und sfdisk klappert danach alle sichtbaren IDE-Festplatten auf dem gerade laufenden System ab. Anschließend sichert es deren Partionierungstabellen und die Rohdaten von Linux- oder Windows-Partitionen auf den Backup-Server. Außerdem kopiert es den Master Boot Record der ersten Platte /dev/hda dorthin. Die gesicherten Daten liegen dann im Verzeichnis /backup/data/rechner unter dem anfangs per Menü ausgewählten Rechnernamen auf dem Backup-Server.

Nur Wertvolles Sichern

Abbildung 2: Das Tool partimage archiviert die Daten roher Festplattenpartitionen und restauriert sie wieder.

Beim Sichern von Partitionen stellt sich das Problem, dass diese oft nicht vollständig gefüllt sind. Zieht man die Rohdaten nur mit

    dd if=/dev/hda1 of=backup.img

ab, enthält das Backup-Image backup.img mehr Daten als notwendig. Das Tool partimage hingegen kennt die Struktur bekannter Dateisysteme wie ext2, ext3 oder des unter Windows gängigen NTFS. Es bietet eine nützliche Fortschrittsanzeige, speichert nur relevante Daten und komprimiert diese auch noch. So kann es durchaus vorkommen, dass es aus einer spärlich gefüllten 30-Gig großen Root-Partition eine Backup-Datei erzeugt, die nur einige hundert MB groß ist.

Das Kommando

  partimage -b -d -z1 -o save /dev/hda1 /backup_path/hda1.img.gz

ruft partimage im Batch Mode (-b) auf, damit es sich nach getaner Arbeit automatisch beendet. Die Option -d legt weiterhin fest, dass dem Benutzer kein Kommentar für die Beschreibung der entstehenden Image-Datei abgerungen wird. Mit -o werden eventuell schon bestehende Image-Dateien rücksichtslos überschrieben und -z1 bestimmt, dass die Komprimierung mit gzip durchgeführt wird. partimage spaltet die entstehende Backup-Datei zur leichteren Handhabung in 2 Gigabyte große Teile, die es mit Endungen von ``.000'' an durchnumeriert.

Das als root gestartete Shell-Kommando sfdisk -d /dev/hda liest die Partitionierungstabelle der ersten IDE-Festplatte und gibt sie so aus, dass ein späterer Aufruf von sfdisk sie anstandslos restaurieren kann (Abbildung 3). Um herauszufinden, welche Festplatten überhaupt auf dem zu sichernden System installiert sind, hilft pbb der Aufruf von sfdisk -l, der alle Partitionen aller gefundenen Platten auflistet. Das Backup-Skript durchwandert diese und führt für alle im Array @ptypes aufgeführten Partitionstypen einen Backup durch. Wie Abbildung 4 zeigt, sichert pbb in der vorliegenden Fassung nur die Typen 7 (HPFS/NTFS) und 83 (Linux). So fallen nicht sicherungswürdige Swap-Partitionen elegant unter den Tisch. Wer andere Partitionstypen sichern möchte (W95 FAT32 hat zum Beispiel das Kürzel ``c''), braucht nur Zeile 12 im Listing anzupassen. Zwar ist laut partimage der Support fuer NTFS noch experimentell, durchgeführte Tests funktionierten allerdings tadellos.

Abbildung 3: Das Kommando sfdisk gibt die Partitionierungsdaten einer Festplatte aus.

Abbildung 4: Das Kommando 'l' im Programm fdisk gibt alle bekannten Partitionstypen aus.

Bevor das Skript ein neues Backup anlegt, schiebt es zunächst das alte Backup-Verzeichnis mit der Endung .old zur Seite. Schließlich soll der alte Backup bestehen bleiben, falls der neue schiefgeht oder die Platte ausgerechnet während des Backups den Geist aufgibt. Existiert allerdings schon ein .old-Verzeichnis, liegt wohl etwas im Argen und der User muss von Hand einschreiten, nachdem pbb mit einem Fehler abgebrochen hat.

pbb durchforstet die Ausgabe von sfdisk -l nach dem Muster ``Id='', das den Typ jeder gefundenen Partition enthält (z.B. ``83'' oder ``c''). Am Zeilenanfange steht dann der Device-Pfad (z.B. /dev/hda1), und daraus leitet pbb den Plattenpfad ab (/dev/hda). Für SCSI-Disks funktioniert das freilich nicht, das Skript lässt sich aber leicht erweitern.

Nach einem erfolgreichen Backup-Lauf entkoppelt sich das gesicherte System in autorun mit umount wieder vom NFS-Server, um sicherzustellen, dass die Backup-Daten vor dem Herunterfahren des Rechners intakt auf der anderen Seite angekommen sind.

Listing 2: pbb

    01 #!/usr/bin/perl -w
    02 use strict;
    03 use Pod::Usage;
    04 use Sysadm::Install qw(:all);
    05 use Log::Log4perl qw(:easy);
    06 use Log::Log4perl::Appender::Screen;
    07 
    08 Log::Log4perl->easy_init($DEBUG);
    09 
    10 my $MDIR      = "/mnt/backup/data";
    11 my %ptypes  = map { $_ => 1 }
    12          qw(83 7);
    13 my @machnames = qw(desktop1 
    14                    desktop2 laptop1);
    15 my %machnames = map { $_ => 1 } @machnames;
    16 
    17 my $mname = pick "Box", \@machnames, 1;
    18 
    19 my %drive_done;
    20 
    21 my $bdir    = "$MDIR/$mname";
    22 my $oldbdir = "$MDIR/$mname.old";
    23 
    24   # Move old backup aside
    25 if(-d $oldbdir) {
    26   LOGDIE "$oldbdir already exists";
    27 }
    28 mv $bdir, $oldbdir if -d $bdir;
    29 mkd $bdir unless -d $bdir;
    30 
    31     # Save the master boot record 
    32     # of the first IDE disk
    33 tap qw(dd if=/dev/hda),
    34     "of=$bdir/hda.mbr",
    35     qw(count=1 bs=512);
    36 
    37 my $sf = `sfdisk -d`;
    38 
    39 while($sf =~ /^(.*Id=\s*(\w+).*)/mg) {
    40   my($line, $id) = ($1, $2);
    41 
    42   next unless exists $ptypes{$id};
    43 
    44   my($path) = split ' ', $line, 2;
    45   (my $dev   = $path) =~ s#.*/##;
    46   (my $drive = $dev)  =~ s/\d//g;
    47 
    48     # Save partition drive's table
    49   if(!$drive_done{$drive}++) {
    50     sysrun "sfdisk -d /dev/$drive " .
    51            ">$MDIR/$mname/$drive.pt";
    52   }
    53 
    54     # Save partition
    55   sysrun "partimage -b -d -z1 -o save" .
    56          " /dev/$dev $bdir/$dev.img.gz";
    57 }
    58 
    59   # Remove old backup
    60 rmf $oldbdir if -d $oldbdir;
    61 
    62 =head1 NAME
    63 
    64 pbb - Partition Based Backup
    65 
    66 =head1 SYNOPSIS
    67 
    68     pbb
    69 
    70 =head1 DESCRIPTION
    71 
    72 Scans all IDE hard drives, and backs 
    73 them up by partiion.

Ernstfall

Tritt der Ernstfall ein und eine neu gekaufte Platte muss mit dem letzten Backup initialisiert werden, wird das zu restaurierende System wiederum mit der Rescue-CD gebootet und anschließend die gesicherte Partitionierungstabelle auf der neuen Platte eingespielt:

    # sfdisk </mnt/backup/data/laptop1/hda.pt

Handelt es sich, wie im Beispiel, um die Festplatte mit dem Master Boot Record, der in den ersten 512 Bytes gespeichert ist und für den Bootvorgang gebraucht wird, kommt dieser mit

    dd if=/mnt/backup/data/laptop1/hda.mbr of=/dev/hda

wieder zurück auf die zu restaurierende erste IDE-Festplatte hda. Um die Daten auf einer Partition zu restaurieren, startet man partimage am besten von der Kommandozeile, wählt im GUI Restore a partition from an image file aus und gibt den Pfad zu dem gesicherten Image mit /mnt/backup/data/laptop1/hda.img.gz.000 an. Die folgenden Teile sucht partimage sich anschließend im gleichen Verzeichnis selbst zusammen.

Abbildung 5: Die gesicherten Daten eines Laptops mit einer Festplatte

An den Haaren aus dem Sumpf

Auf der Rescue-CD ist zwar eine Perl-Installation enthalten, aber leider fehlen CPAN-Module wie die im Skript pbb verwendeten Helfer Sysadm::Install oder Log::Log4perl. Doch dank dem schon einmal in [4] vorgestellten Perl Archive Toolkit PAR wird aus dem Skript auf einem vollständig mit allen notwendigen CPAN-Modulen installierten und kompatiblen Linux-Rechner einfach ein Binärpaket pbb.bin geschnürt, das sowohl das Skript, als auch alle verwendeten Module (und obendrein einen Perl-Interpreter) enthält.

Zu beachten ist allerdings, dass das System, auf der das Binärpaket geschnürt wird, mit einer Version der libc läuft, die kleiner oder gleich 2.3.2 ist. Das mit sysresccd gebootete System läuft nämlich damit, und falls das Perl-Bündel mit einer älteren Version erzeugt wurde, kann es Kompatibilitätsprobleme geben.

Der Aufruf des PAR-Compilers mit pp -o ppb.bin ppb macht aus dem Perl-Skript pbb das Executable pbb.bin, wenn auf dem ausführenden System das Paket PAR vom CPAN installiert ist. Log::Log4perl::Appender::Screen zieht pbb übrigens extra herein, da pp es sonst vergäße. Log4perl zieht es zur Laufzeit heran, und pp ermittelt die Abhängigkeiten zur Compile-Zeit.

Backup Server installieren

Als Backup-Server wurde ein alter PC mit einigen alten 120-Gigabyte- Platten und einer neuen 400-GB-Platte zusammengeklopft. Als Operationssystem kam Debians ``Sarge''-Release zum Einsatz -- keine Gimmicks, nur ein leichtgewichtiges und stabiles System, das sich mit apt-get leicht aktualisieren lässt. Um einen großen zusammenhängenden Speicherbereich zu erhalten, wurden die Einzelpartitionen der verschiedenen Festplatten mit dem Linux Volume Manager (LVM) zusammengeschaltet. Um die Partition einer Festplatte (zum Beispiel /dev/hdc1) für den Gebrauch mit dem LVM herzurichten, ist der Aufruf pvcreate /dev/hdc1 erforderlich.

So erzeugte Physical Volumes fasst man anschließend zu einer Volume Group zusammen, die wiederum einem Logical Volume zugeordnet wird. Der Aufruf

    vgcreate giantvg /dev/hdc1 ...
    lvcreate -L 600G -n giantlv giantvg

erzeugt ein 600 Gigabyte großes virtuelles virtuelles Device, das unter /dev/giantvg/giantlv verfügbar ist. Mit mkfs.ext3 lässt sich dort ein ext3-Dateisystem installieren, das sich anschließend mit mount /dev/giantlv/giantvg /backup problemlos mounten lässt.

Die Root-Partition des Debian-Systems wurde mit 10 GB auf der ersten 120GB-Platte, angelegt, den verbleibenden Platz von 110 GB schlug eine LVM-Definition elegant dem großen Datenbereich für Backup-Zwecke zu. Der NFS-Server war nicht in der Grundinstallation dabei, er wurd einfach mit

    apt-get install nfs-kernel-server nfs-common portmap

vom Netz gezogen und installiert. Damit die Rechner im lokalen Netz auf das Verzeichnis /backup lesend und schreibend zugreifen können, ist der Eintrag

    /backup 192.168.0.*(rw,sync)

erforderlich. Das Kommando exportfs -a propagiert die Änderung.

Gepatchte Notfall-CD

Da die von sysresccd.org erhältliche Rescue-CD den Rechner bootet und die nach dem Booten sichtbaren Programme in einer sogenannten cloop einschließt, müssen beim Patchen einige vorgeschriebene Schritte gemäß der PDF-Anleitung auf [2] eingehalten werden. Das Shellskript in Listing mkcd holt die Datei autorun aus dem bin-Verzeichnis des gemounteten Backup-Servers und kopiert sie ins Root-Verzeichnis der neuen CD. mkcd muss auf einem mit sysresccd gebooteten System aufgerufen werden, damit es die aktive Rescue-CD zunächst in ein temporäres Verzeichnis kopiert, dann autorun hinzufügt und anschließend mit einem ebenfalls von der CD stammenden Skript eine modifizierte .iso-Datei erzeugt. Diese legt es im Root-Verzeichnis des Backup-Servers ab, und anschließend brennt man sie dort mit

    cdrecord dev=/dev/cdrom speed=4 sysresccd-new.iso

auf eine neue CD. Wer zwei Laufwerke eingestöpselt hat, kann dies auch mit einem einzelnen Rechner bewerkstelligen.

Listing 3: mkcd

    01 
    02 CUST=/usr/sbin/sysresccd-custom
    03 MNT=/mnt/backup
    04 OUT=/mnt/custom
    05 
    06 cd $MNT
    07 
    08 dd if=/dev/zero of=fsimage bs=1M count=1000
    09 mke2fs -F -q -N 50000 fsimage
    10 mount -t ext2 -o loop fsimage $OUT
    11 
    12 $CUST extract
    13 $CUST cloop 300 20000
    14 
    15 cp $MNT/bin/autorun $OUT/customcd/isoroot
    16 
    17 $CUST setkmap speakup
    18 $CUST isogen my_srcd
    19 
    20 cp $OUT/customcd/isofile/sysresccd-new.iso /mnt/backup

    http://www.partimage.org/forums/viewtopic.php?t=420

Vor dem Brennen der CD und dem Einsatz des Skripts sind die IP-Adresse des Backup-Servers in autorun, sowie die Rechnernamen in pbb anzupassen, und pbb ist zu kompilieren. Wer möchte, kann das Skript noch mit zusätzlichen Funktionen zur Datenrestaurierung erweitern und dem nächsten Festplattencrash gelassen entgegensehen.

Infos

[1]
Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2006/11/Perl

[2]
Download für die Rescue-CD von sysresccd: http://sysresccd.org

[3]
Dokumentation zu Partimage: http://partimage.org

[4]
Michael Schilli, ``Gepackte Koffer'', http://www.linux-magazin.de/Artikel/ausgabe/2004/09/perl/perl.html

Michael Schilli

arbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat "Goto Perl 5" (deutsch) und "Perl Power" (englisch) für Addison-Wesley geschrieben und ist unter mschilli@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com.