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 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.
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.
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.
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.
Online PLUS
In einem Screencast demonstriert Michael Schilli das Beispiel: https://www.linux-magazin.de/plus/2012/07
Infos
- Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2012/07/Perl
- Clonezilla: http://clonezilla.org
- Clonezilla live: http://clonezilla.org/customized-clonezilla-live.php
- Partimage:http://www.partimage.org/Main_Page
- PAR – Perl Archive Toolkit: http://search.cpan.org/~rschupp/PAR-1.005/








