Aus Linux-Magazin 07/2012

Clonezilla und Perl-Skripte für Sicherung nutzen

© golffoto, photocase.com

Mit Clonezilla gehen Systembackups und Restores mit nur wenigen Tastendrücken elegant von der Hand. Eine selbst produzierte Lösung reduziert den Aufwand auf das Einlegen einer CD, auf die der Admin zuvor ein Perl-Skript gebrannt hat.

Leider steht in meinem Haushalt noch immer ein Rechner mit Windows 7 herum, auf dem meine Gattin die Steuererklärung anfertigt und mit Photoshop an digitalen Aufnahmen herumwerkelt. Um diesen PC zu sichern, drängte sich das in Windows 7 eingebaute Backup-programm auf. Doch als dieses Hausmittel mit den gesicherten Daten dann irgendwann keinen Restore mehr zusammenbrachte, mit kryptischen Fehlermeldungen um sich warf und dank des bekannten blickdichten Vorhangs keine Fehleranalyse zuließ, fiel schließlich die Entscheidung zugunsten einer handgestrickten Linux-Lösung.

Das freie Programm Clonezilla [2] liefert eine bootbare CD (alternativ einen USB-Stick), die auf einem beliebigen PC eine Debian-basierte Live-Distribution hochfährt (Abbildung 1). Der User hangelt sich dann durch ein Dutzend Menüs (Abbildung 2) und kann zügig zwischen Backup und Restore automatisch ermittelter Plattenpartitionen wählen. Die Daten sichert Clonezilla wahlweise auf einer eingestöpselten USB-Platte oder übers Netz per »ssh« auf einem anderen Rechner im Netzwerk.

Abbildung 1: Nach dem Einlegen der Clonezilla-CD erscheint das Bootmenü.

Abbildung 1: Nach dem Einlegen der Clonezilla-CD erscheint das Bootmenü.

Abbildung 2: Einer der Dialoge zur Konfiguration des Clonezilla-Backups, die der Benutzer abarbeitet.

Abbildung 2: Einer der Dialoge zur Konfiguration des Clonezilla-Backups, die der Benutzer abarbeitet.

Hass auf Handarbeit

Bei regelmäßig stattfindenden Backups nervt die ewig gleiche Handarbeit, daher erlaubt es Clonezilla, eigene Backupskripte mit auf CD zu brennen [3]. Diese steuern den Ablauf dann automatisch nach dem Booten. Die Backup- und Restore-Funktionen muss der Automatisierer nicht neu erfinden, er darf aus dem umfangreichen Clonezilla-Werkzeugkasten mit Shellskripten schöpfen.

In den Perlmeister-Studios nimmt die maßgeschneiderte Backup-CD zum Beispiel nach dem Einlegen über SSH Kontakt mit dem Backupserver im lokalen Netzwerk auf und beginnt die Partitionen der ersten gefundenen Festplatte des PC komprimiert zu übertragen. Dabei ist Clonezilla so schlau, nicht nur die Daten des jeweiligen Dateisystems festzuhalten, sondern schreibt auch gleich die ganze Partitionstabelle mit, damit der Restore später leichter abläuft.

Rank und schlank

Die Clonezilla-Suite versteht dank des ebenfalls frei verfügbaren Programms »partimage« [4] die gängigen Dateisysteme (etwa Ext [2-4], NTFS, FAT, HFS+, Reiser) und sichert nur tatsächlich benutzte Bereiche. Das ist bei nur teilweise genutzten Festplatten effizienter als eine bitweise Sicherung mit »dd« . Da manche Systeme fürs Speichern der Backupdaten mit antiken Dateisystemen aufwarten, die keine großen Files mögen, zerlegt Clonezilla die Sicherungsdateien auf Wunsch in handliche, optional auch komprimierte Brocken (Abbildung 3).

Abbildung 3: Clonezilla speichert die Backupdaten in komprimierten 2-GByte-Stückchen zusammen mit den Partitionsdaten der Festplatte.

Abbildung 3: Clonezilla speichert die Backupdaten in komprimierten 2-GByte-Stückchen zusammen mit den Partitionsdaten der Festplatte.

Um dem User das Studium aller Parameter der mit Funktionen nur so gespickten Clonezilla-Skripte zu ersparen, gibt es nach einem per Menü konfigurierten Lauf – wie in Abbildung 4 gezeigt – die intern genutzten parametrisierten Funktionsaufrufe aus. Hat sich der User also einmal durch die Dialoge zum Anfertigen des Backups gehangelt, braucht er nur dieses Kommando auf CD zu brennen und spart sich künftig den Dialog-Dschungel.

Abbildung 4: Nach der Menü-Auswahl schlägt Clonezilla eine Kommandozeile vor, die das Backup nächstes Mal automatisch erledigt.

Abbildung 4: Nach der Menü-Auswahl schlägt Clonezilla eine Kommandozeile vor, die das Backup nächstes Mal automatisch erledigt.

Totaler Bedienluxus

Bevor das Kommando »ocs-sr« aber direkt nach dem Booten funktioniert (Abbildung 4), stehen weitere Konfigurationen an. Soll das Backup übers Netzwerk und SSH auf einen anderen Rechner erfolgen, muss das Bootskript zunächst eine IP-Adresse vom DHCP-Server holen und die Netzwerkverbindung initialisieren. Clonezilla bietet dafür zwar das Skript »ocs-live-netcfg« an, doch das nutzt ebenfalls Dialoge und weiß nichts von den Vorlieben des Users.

Statt dieses Skripts nimmt das hier vorgestellte Bootskript das Kommando »sudo dhclient eth0« . Es holt auf Debian-Derivaten eine IP-Adresse vom DHCP-Server und stellt – den zurückkommenden Netzwerkdaten entsprechend – DNS-Server, Netmask und Default Gateway ein.

Das Kommando »ocs-sr« zum Anwerfen des Backups schreibt die zu sichernden Dateien stets ins lokale Dateisystem unter dem angegebenen Verzeichnis, im Beispiel »2012-04-18-15-img« . Erfolgt das Backup aber nicht auf eine USB-Platte, die unter dem aktuellen Verzeichnis gemountet ist, sondern übers Netzwerk, nutzt Clonezilla das Programm »sshfs« , das sich per SSH mit einem entfernten Rechner verbindet und ein dort liegendes Verzeichnis mit »fuse« -Technik mountet. Das Backupprogramm »ocs-sr« glaubt also weiterhin, in einen lokalen Dateibaum zu schreiben, aber unter der Haube lotst »sshfs« die Daten transparent auf den Backupserver.

Schneckenrennen

Bei den heute erhältlichen Terabyte-großen Festplatten dauern Backups oft Stunden und blockieren entsprechend den PC. Verfügt die zu sichernde Platte über mehrere Partitionen, kann der Admin das Backup unterbrechen. Beim nächsten Lauf sollte das Skript aber nicht wieder von vorne anfangen, sondern sein Tun bei der ersten noch nicht gesicherten Partition fortsetzen. Außerdem sollte der Backup-Admin kein Passwort eingeben oder die beim »ssh« -Programm bei der ersten Verbindung zu einem noch unbekannten Host übliche Warnung bestätigen müssen. Die CD sollte das System nach dem Einlegen hochfahren, alles automatisch konfigurieren und nach Bestätigung loslegen.

Nun soll es noch Anhänger der Shellprogrammierung geben, die derartige Funktionen in irgendeinem Shelldialekt zusammenklopfen. Aber mir kommt das immer so vor, als hämmere jemand einen Nagel mit einem hart gewordenen Brotlaib in die Wand. Das Perl-Skript in Listing 2 implementiert die Features relativ übersichtlich. Da es einige CPAN-Module nutzt, stellt sich mir die Frage, wie man das Skript mit seinen Modulen auf die CD brennt.

Statisches Perl

Nutzt ein Perl-Skript CPAN-Module, läuft es nicht auf Anhieb auf einer Fremdumgebung wie im Fall der Clonezilla-Distribution. Das CPAN hält zur Abhilfe aber einige Lösungen zur Bündelung von Modul-Sets und Skripten parat, zum Beispiel »PAR« [5]. Kürzlich kam mit »App::staticperl« ein weiteres Framework hinzu. Es kompiliert erstaunlich kompakte, statische, von der Laufzeitumgebung relativ unabhängige Perl-Executables, die die verwendeten CPAN-Module bereits enthalten.

Listing 1 zeigt das Shellkommando, das aus dem Perl-Skript »run-me« das Executable »run-me-clonezilla« erzeugt. Das Tool filzt die verwendeten CPAN-Module nach Abhängigkeiten und fügt sie hinzu. Beim Erkennen der im Applikationsskript benutzten Module hapert es, der Entwickler muss sie rausfieseln und mit »-M« -Optionen manuell angeben.

Listing 1

build.sh

1 staticperl mkapp run-me-clonezilla --boot \
2  run-me -MFile::Basename -MFile::Temp \
3  -MFile::Glob -MSysadm::Install \
4  -MLog::Log4perl \
5  -MLog::Log4perl::Appender::Screen

Gleiches gilt für dynamisch geladene Module. So holt Log::Log4perl zum Beispiel zur Laufzeit ein Modul mit dem Screen-Appender, sobald seine Konfiguration dies verlangt. App::staticperl kann dies durch rein statische Analyse allein unmöglich herausfinden und benötigt deswegen manuelle Unterstützung. Außerdem verlangt Staticperl, dass der User alle später einkompilierten Module mit dem Aufruf »staticperl instcpan [Modulname]« über eine CPAN-Shell in Staticperls lokalem Repository installiert.

Die CD als Schlüssel

Zur passwortlosen Authentisierung auf dem Backupserver enthält das Skript einen Private Key ohne Passphrase, den »ssh-keygen -t rsa« in einer Datei »id_rsa« generiert hat. Ab Zeile 137 steht ein Here-Document mit allen Zeilen des Private Key (in Listing 2 aus Sicherheitsgründen ausge-xt). Der zugehörige Public Key (in »id_rsa.pub« ) wandert in die Datei »~/.ssh/authorized_keys« auf dem Server unter der User-ID des Backup-Users. Wer also die CD (oder das ISO-Image) in Händen hält, besitzt den Schlüssel zum Backupserver und braucht weder Passwort noch Passphrase.

Beim ersten Verbinden mit dem Server von der Kommandozeile fragt »ssh« , ob dies der richtige Host ist, und fügt dessen Signatur in die Datei »~/.ssh/known_hosts« ein. Der Eintrag wandert ab Zeile 130 in das Here-Document im Perl-Skript, damit die automatische Verbindungsaufnahme später keine Bestätigung fordert.

Listing 2

run-me

001 #!/usr/local/bin/perl -w
002 use strict;
003 use File::Temp qw( tempfile );
004 use File::Basename;
005 use Log::Log4perl qw(:easy);
006 use Sysadm::Install qw( :all );
007
008 Log::Log4perl->easy_init($DEBUG);
009
010 my $ip      = "192.168.0.111";
011 my $user    = "mschilli";
012 my $mnt_dir = "/home/partimag";
013
014 if( ! -d $mnt_dir ) {
015   mkdir $mnt_dir;
016 }
017
018 network();
019 mount();
020 backup_all();
021 unmount();
022
023 1;
024
025 ###########################################
026 sub network {
027 ###########################################
028   sysrun "sudo", "dhclient", "eth0";
029 }
030
031 ###########################################
032 sub unmount {
033 ###########################################
034   sysrun "fusermount", "-u", $mnt_dir;
035 }
036
037 ###########################################
038 sub mount {
039 ###########################################
040   DEBUG "Writing private key";
041   my $privkey_file = (tempfile())[1];
042   blurt privkey(), $privkey_file;
043
044   DEBUG "Writing known hosts";
045   my $kh_file = (tempfile())[1];
046   blurt known_hosts(), $kh_file;
047
048   my $rc = sysrun( "sudo", "sshfs",
049     "$user\@$ip:/backup/clonezilla",
050     $mnt_dir, "-o",
051     "ssh_command=ssh -i $privkey_file " .
052     "-o BatchMode=yes " .
053     "-o GlobalKnownHostsFile=$kh_file" );
054
055   if( $rc ) {
056     die "sshfs failed (backup host down?)";
057   }
058 }
059
060 ###########################################
061 sub backup_all {
062 ###########################################
063   my $last_backup_path =
064     ( reverse sort <$mnt_dir/[0-9]*> )[0];
065
066   my $continue_with;
067
068   my @drives = < /dev/sda[0-9]* >;
069
070   if( defined $last_backup_path and
071       ! -f "$last_backup_path/DONE" ) {
072     $continue_with = (
073       sort { -M $a <=> -M $b }
074       < $last_backup_path/*gz* > )[0];
075     $continue_with =
076       basename $continue_with;
077     $continue_with =~ s/\..*//;
078     DEBUG "Continue: $continue_with";
079   }
080
081   my $not_yet;
082
083   if( defined $continue_with ) {
084     $not_yet = 1;
085   }
086
087   my ( $sec, $min, $hour, $mday, $mon,
088        $year ) = localtime( time );
089
090   my $date =
091    sprintf "%04d-%02d-%02d-%02d-%02d-%02d",
092     $year + 1900, $mon+1, $mday, $hour,
093     $min, $sec;
094
095   my @parts = ();
096
097   for my $part ( sort @drives ) {
098
099     my $base = basename $part;
100
101     if( $base eq $continue_with ) {
102       $not_yet = 0;
103     }
104
105     next if $not_yet;
106
107     push @parts, basename $part;
108   }
109
110   backup( $date, @parts );
111 }
112
113 ###########################################
114 sub backup {
115 ###########################################
116     my( $date, @parts ) = @_;
117
118     DEBUG "Backing up @parts";
119     sysrun qw( sudo /opt/drbl/sbin/ocs-sr
120       -b -q2 -c -j2 -z1 -i 2000 -sc -p true
121       savedisk ), "$date-img", @parts;
122
123     blurt "", "$mnt_dir/$date-img/DONE";
124 }
125
126 ###########################################
127 sub known_hosts {
128 ###########################################
129     return <<'EOT'
130 XXX
131 EOT
132 }
133
134 ###########################################
135 sub privkey {
136 ###########################################
137     return <<'EOT'
138 -----BEGIN RSA PRIVATE KEY-----
139 YYY
140 -----END RSA PRIVATE KEY-----
141 EOT
142 }

In Perl gegossen

Zeile 10 legt die IP-Adresse des Backupservers fest, dies muss der Benutzer, wie die verwendete User-ID in Zeile 11, an die lokalen Gegebenheiten anpassen. Die Funktion »network()« initialisiert den mit der selbst gebrannten CD gebooteten Rechner im Netzwerk. Die ab Zeile 38 definierte Funktion »mount ()« ruft »sshfs« auf, um das lokale Verzeichnis »/home/partimag« mit dem Verzeichnis »/backup/clonezilla« auf dem Backupserver zu verbandeln. Die hierfür genutzte Funktion »sysrun()« stammt aus dem Fundus des CPAN-Moduls Sysadm::Install und führt die ihr übergebenen Shellkommandos in einem »system()« -Befehl aus, nachdem sie eine entsprechende Nachricht an das im Skript ebenfalls aktivierte Log4perl-Framework geschickt hat.

Die Option »ssh_command« des »sshfs« -Programms erlaubt es, zusätzliche SSH-Parameter anzugeben. Die Option »-i« bestimmt die Lage des private Key, den Zeile 41 vorher in einer temporären Datei abgelegt hat. Die Option »BatchMode=yes« stellt dem User keine Fragen, sondern bricht ab, falls etwas nicht automatisch klappt. Und die Option »GlobalKnownHostsFile« gibt die Datei an, die die Signaturen bekannter Rechner enthält. Zuvor hat das Skript die Ausgabe der Funktion »known_hosts()« (Zeile 127) in dieser temporären Datei abgelegt.

Unterbrechen erlaubt

Damit sich ein Lauf notfalls unterbrechen lässt, sucht die Funktion »backup_all()« ab Zeile 61 das Verzeichnis der letzten Sicherung heraus. Sie legt das Skript jeweils mit aktuellem Datumsstempel an, also führt »reverse sort« zu einer Liste, deren erstes Element das jüngste Backup ist. Innerhalb dieses Verzeichnisses sucht Zeile 70 nach einer Datei namens »DONE« , die das Backupskript anlegt, sobald eine Sicherung komplett abgeschlossen ist. Fehlt diese Datei, wurde das Backup unterbrochen. Zeile 71 findet in diesem Fall eine angefangene Partition, und die For-Schleife ab Zeile 97 setzt das Backup dort fort.

Listing 3

prepare.sh

01 sudo fdisk /dev/sda <<EOT
02 n
03 p
04 1
05
06 +500MB
07 n
08 p
09 2
10
11 +500MB
12 w
13 EOT
14
15 sudo mkfs.ext3 /dev/sda1
16 sudo mkfs.ext3 /dev/sda2
17
18 sudo umount /tmp
19 sudo mount /dev/sda2 /tmp
20 sudo mount /dev/sda1 /home/partimag

Backe, backe Kuchen

Um das statisch kompilierte Perl-Skript als Bootskript in ein Clonezilla-Image einzubacken, bootet der User das heruntergeladene ISO-Image in einer virtuellen Maschine, initialisiert das Netzwerk und selektiert die Option »Command line prompt« , sobald die hochgefahrene Clonezilla-Distribution dies in einem Dialog anbietet.

Dann wechselt der User ins Arbeitsverzeichnis, kopiert das erzeugte Perl-Executable hinein und führt »ocs-iso« aus:

cd /home/partimag
sudo scp user@xxx:/tmp/run-me-clonezilla .
sudo cp run-me-clonezilla custom-ocs
sudo /opt/drbl/sbin/ocs-iso?
 \-g en_US.UTF-8 -k NONE -s -m ./custom-ocs

Das klappte in einer Virtualbox-VM wegen Speichermangels nicht sofort. Der Kasten: “Virtuelle Maschine vorbereiten” erläutert die nötigen Schritte.

Virtuelle Maschine vorbereiten

Der Aufruf von »ocs-iso« in einer virtuellen Maschine stieß bei einem Testlauf an die Grenzen des verwendeten Dateisystems, da weder das Ablageverzeichnis »/home/partimag« noch der temporäre Arbeitsbereich »/tmp« über ausreichenden Speicherplatz verfügten.

Führt der User aber nach dem Hochfahren der VM mit dem ISO-Image von der Clonezilla-Webseite [2] die im Shellskript »prepare.sh« aufgezeigten Schritte zum Anlegen zweier Festplattenpartitionen à 500 MByte aus, erzeugt der Befehl »ocs-iso« das gewünschte ISO-Image mit dem eingebrannten Bootskript, ohne zu murren.

Resultat ist ein ISO-Image mit Clonezilla und einem Perl-Skript zum Booten (Abbildung 5). Zum Testen des fertigen ISO-Image bietet sich ebenfalls eine virtuelle Maschine an, um den Verbrauch an CD-Rohlingen zu beschränken. Enthält die virtuelle Umgebung noch keine Festplattenpartitionen, lassen sich diese mit »fdisk« und »mkfs.ext3« schnell probeweise einrichten.

Abbildung 5: Das ISO-Image mit dem handgestrickten Backupskript ist fertig.

Abbildung 5: Das ISO-Image mit dem handgestrickten Backupskript ist fertig.

Verläuft der VM-Test erfolgreich, bleibt nur noch übrig, das erzeugte ISO-Image auf eine CD zu brennen. Der Befehl

sudo cdrecord -v speed=4 dev=/dev/?
cdromclonezilla-img.iso

erledigt dies auf einer ins Laufwerk eingelegten CD. Wie Abbildung 6 zeigt, schnappt sich das Skript die Partitionen, die ein Backup benötigen.

Abbildung 6: Test in einer VM: Das ISO-Image mit dem eingebrannten Perl-Skript beraumt ein Backup aller Partitionen an und holt eine Bestätigung des Users ein.

Abbildung 6: Test in einer VM: Das ISO-Image mit dem eingebrannten Perl-Skript beraumt ein Backup aller Partitionen an und holt eine Bestätigung des Users ein.

Online PLUS

In einem Screencast demonstriert Michael Schilli das Beispiel: https://www.linux-magazin.de/plus/2012/07

Der Autor

Michael Schilli arbeitet als Software-Engineer bei Yahoo in Sunnyvale, Kalifornien. In seinen seit 1997 erscheinenden Snapshots forscht er jeden Monat nach praktischen Anwendungen der Skriptsprache Perl. Unter mailto:mschilli@perlmeister.com beantwortet er gerne Fragen.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 5 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben