Mitlerweile gibt es auch fertige Pakete die man installieren kann: http://www.rsnapshot.org



Unkomplizierte automatische Schnappschuss-Sicherungen mit Linux und dem rsync-Kommando

Zusammenfassung

Dieses Dokument beschreibt eine Methode, automatisch zyklische Sicherungen im "Schnappschuss"-Stil auf Unix-basierten Systemen zu erzeugen, mit spezifischen Beispielen aus der GNU/Linux-Erfahrung des Autors. Schnappschuss-Sicherungen sind ein Merkmal von High-End-Servern; sie erzeugen den Eindruck von vielfachen Vollsicherungen (bis hin zu Besitztum/Rechten) je Tag ohne den Overhead von Platz und Prozessresourcen. All diese Schnappschüsse sind schreibgeschützt, und sie sind von den Benutzern direkt zugreifbar über spezielle Sytemverzeichnisse. Es ist oft möglich, den Zustand von mehreren Stunden, Tagen, ja sogar Wochen mit etwas mehr als dem zweifachem Platzbedarf zu speichern. Auch wenn diese Methode nicht so platzsparend ist wie einige proprietäre Technologien (die, da sie spezielle copy-on-write-Dateisysteme verwenden, mit nur wenig mehr als dem einfachen Platzbedarf operieren, so benutzt sie dafür nur Standard-Dateiutilities und das allgemein bekannte rsync-Programm, das auf den meisten Linux-Distributionen von Haus aus installiert ist. Richtig konfiguriert kann die Methode gegen Festplattenfehler und "root compromises" (vermutlich: Angriff mit den Rechten des Systemadministrators) schützen, oder sogar ein Netzwerk auf unterschiedlichen Arbeitsplätzen automatisch sichern.

Motivation

Hinweis: Es folgt das Orginal der SGVLUG-DEFSIG-Verlautbarung.

Hast Du jemals versehentlich eine Datei in Arbeit gelöscht oder überschrieben? Schon mal Daten durch einen Festplattenausfall verloren? Oder kann es sein, dass Du Verzeichnisse an deine Windows benutzende Freunde freigegeben hast, die sich laufend Outlook-Viren einfangen, die an ein oder zwei Ziffern in deren .xls-Dateien herumfummeln? Wäre es nicht schön, wenn ein Schnappschussverzeichnis gäbe, auf das Du zurückgehen könntest, das ein komplettes Abbild des Dateisystems in Halbstunden-Intervallen für jeden Tag hätte, ausserdem einen täglichen Schnappschuss für mehrere zurückliegende Tage und es gäbe noch einen wöchentlichen Schnappschuss? Wie wäre es, wenn jeder Benutzer in ein magisches Verzeichnis gehen könnte und von dort gelöschte oder überschriebene Dateien seiner Wahl ohne jede Hilfe von Dir in die "Realität" kopieren könnte? Und wie wäre es, wenn das /snapshot-Verzeichnis wie eine CD-ROM schreibgeschützt wäre, so dass nicht dies "anfassen" könnte (ausser der Sytemadministrator, und auch der nicht direkt)?

Das Beste von allem, was wäre, wenn Du das alles automatisch erledigen könntest, indem Du einfach eine eigene, etwas größere Festplatte verwendest? (Oder eine eigene Partition, die dann gegen alles schützt außer Festplattendefekt).

In meinem Labor haben wir einen eigenen NetApp-Dateiserver, der diese Art von Funktionalität für den Endbenutzer zur Verfügung stellt. Er bietet noch eine Menge anderer Dinge zusätzlich, aber er kostet auch soviel wie ein luxuriöser Geländewagen.

Ich werde Dir zeigen, wie ich auf meiner gebrauchten 80$-Linux-Kiste (die auch eine Datei-, Web- und Mail-Server darstellt) automatisch rotierende Schnappschüsse konfiguriert habe, indem ich nur ein paar einseitige Scripts und ein paar Standard-Linux-Utilities benutze, die Du vielleicht sowieso schon verwendest.

Ich werde ebenso eine verwandte Strategie vorschlagen, die einen (oder zwei, für die klugerweise Paronoiden) zusätzlichen Billigrechner für eine vollstänige, verantwortliche, automatische Sicherungsstrategie anwenden, die Bänder und Handarbeit nicht brauchen und dafür sorgen, dass das Zurückspielen von Dateien so leicht wird wie "cp".

Verwenden von rsync zum Erstellen einer Sicherung

Das Werkzeug rsync ist ein wohlbekanntes Stück Software unter der GPL, ursprünglich von Andrew Tridgell und Paul Mackerras geschrieben. Wenn Du eine bekannte Linux- oder Unix-Variante hast, dann hast Du es wahrscheinlich schon installiert; wenn nicht, kannst Du den Quellcode von rsync.samba.org herunterladen. Eine Besonderheit von rsync ist das effiziente Synchronisieren von Dateibäumen über ein Netzwerk, aber es funktioniert auch prima auf einem Einzelrechner.

Grundsätzliches

Angenommen Du hast ein Verzeichnis namens quelle, und Du willst es in ein Zielverzeichnis sichern. Um das durchzuführen benutzt Du:

rsync -a quelle/ ziel/

(Beachte: Ich füge auch noch das -v ("verbose", ausführlich)-Flag hinzu, so dass rsync mir mitteilt, was er gerade treibt. Dieses Kommando ist gleichbedeutend mit

cp -a quelle/* ziel/

außer, dass es viel effizienter ist, wenn es nur wenige Unterschiede gibt.

Um deinen Appetit anzuregen, hier ist ein Weg, das gleiche aus dem obigen Beispiel zu erledigen, aber mit einem Ziel auf einer entfernten Rechner, über eine sichere Shell:

rsync -a -e ssh quelle/ username@ferner.rechner.com:/pfad/zum/ziel/

Abschliessende Schrägstriche bedeuten was... Manchmal

Dies ist nicht wirklich ein Artikel über rsync, aber ich möchte diesen Umweg hier benutzen, eine möglicherweise verwirrende Einzelheit über seine Verwendung klarzustellen. Du bist möglicherweise von Kommandos gewohnt, dass sie gegenüber abschließenden Schrägstrichen unempfindlich sind. Zum Beispiel, wenn a und b zwei Verzeichnisse sind, dann ist cp -a a b gleichbedeutend mit cp -a a/ b/. Jedoch rsync beachtet den abschliessenden Schrägstrich, aber nur beim Quellargument. Beispiel: Seien a und b zwei Verzeichnisse, mit Datei foo anfangs enthalten in Verzeichnis a. Dann erzeugt das folgendes Kommando

rsync -a a b

die Datei b/a/foo, während das Kommando

rsync -a a/ b

die Datei b/foo erzeugt. Das Vorhandensein/Nichtvorhandensein eines abschließenden Schrägstrichs im Zielverzeichnis (in diesem Fall b) hat keine Wirkung.

Anwendung des --delete-Flags

Wenn eine Datei ursprünglich in beiden Verzeichnissen quelle/ und ziel/ war (z.B. aus dem früheren rsync-Aufruf), möchtest Du vielleicht diese aus ziel\ beim nächsten rsync löschen. Das voreingestellte Verhalten ist jedoch, die Kopie auf ziel\ dort zu belassen. Wenn Du rsync dazu bewegen willst, jede Datei, von ziel\ zu löschen, die nicht in quelle\ existiert, musst Du das Flag --delete benutzen.

rsync -a --delete quelle/ ziel/

Sei faul: Verwende cron

Eines der schwierigsten Hindernisse einer guten Sicherungsstrategie ist die menschliche Natur; wenn es irgendwie mit Arbeit verbunden ist, gibt es eine hohe Wahrscheinlichkeit, dass Sicherungen nicht stattfinden. (Eigenes Beispiel: Wie selten wurde der PC meines Mitbewohners gesichert bevor ich dieses System erstellt habe). Glücklicherweise gibt es einen Weg, sich gegen menschliche Faulheit zu wappnen: Bringe cron dazu, die Arbeit zu erledigen.

Um z.B. das rsync-mit-sicherung-Kommando aus dem früheren Abschnitt jeden Morgen um 4:20 Uhr laufen zu lassen, editiert root die cron-Tabelle: (als root)

crontab -e

Dann füge die folgende Zeile hinzu:

20 4 * * * rsync -a --delete quelle/ ziel/

Zuletzt sichere die Datei und verlasse das Programm. Die Sicherung wird jeden Morgen genau um 4:20 Uhr losgehen, und root wird die Ausgabe per EMail erhalten. Kopiere das Beispiel nicht wörtlich, denn: Du solltest die vollständigen Pfadbezeichnungen (so wie /usr/bin/rsync und /home/source) benutzen, damit jede Zweideutigkeit ausgeschlossen ist.

Inkrementelle Sicherungen mit rsync

Da das Anfertigen einer vollständige Kopie eines großen Dateisystems ein zeitfressender und teurer Prozeß sein kann, ist es üblich, eine Vollsicherung nur einmal je Woche oder je Monat zu machen und an den anderen Tagen nur Änderungen zu speichern. Diese Technik wird "Erstellen von Zuwachssicherungen" (incremental backup) genannt und wird von den ehrwürdigen, alten Werkzeugen dump und tar unterstützt, zusammen mit vielen anderen.

Wenn Du aber keine Bänder als Sicherungsmedium hat, ist beides möglich und erheblich effizienter, Zuwachssicherungen mittels rsync durchzuführen.

Die gebräuchlichste Art, dies zu machen, ist es, rsync mit der Kombination -b --backup-dir= zu benützen. Ich habe einige Beispiele für diese Nutzung hier gesehen, aber ich werde sie nicht weiter besprechen, da es eine bessere Art gibt. Wenn Du nicht mit Hardlinks vertraut bist, solltest Du mit der folgenden Besprechung anfangen.

Besprechung der "Hardlinks"

Normalerweise denken wir bei Dateinamen, dass diese die Datei selber sind, aber in Wirklichkeit ist der Name ein Hardlink ("direktcodierter Verweis", Anm.d.Ü.). Eine gegebene Datei kann mehr als einen Hardlink auf sich selber haben --zum Beispiel, ein Verzeichnis hat mindestens zwei Hardlinks: Den Verzeichnisnamen und . (gilt, wenn Du drinnen bist). Es hat außerdem einen Hardlink von jedem seiner Unterverzeichnisse (die ..-Datei innerhalb jedes einzelnen). Wenn Du ein stat-Werkzeug auf Deiner Maschine installiert hast, kannst Du herausfinden, wie viele Hardlink eine Datei besitzt (zusammen mit einem Haufen anderer Informationen) mit dem Kommando:

stat filename

Hardlinks gibt es nicht nur für Verzeichnisse -- Du kannst auch mehr als einen Link auf normale Dateien setzen. Zum Beispiel, wenn Du eine Datei a hast, dann erzeugst Du einen Link genannt b:

ln a b

Jetzt sind a und b zwei Namen für die gleiche Datei, wie Du Dich vergewissern kannst, denn sie befinden sich in der gleichen Inode (Anm.d.Ü: durch Nummer identifizierte Speichereinheit des Filesystems) (die Inode-Nummer wird auf Deinem Rechner verschieden sein).

ls -i a
  232177 a
ls -i b
  232177 b

Also ln a b ist annähernd gleich zu cp a b, aber es gibt einige wichtige Unterschiede:

  1. Der Inhalt der Datei ist nur einmal gespeichert, also benötigst Du nicht den doppelten Platz.
  2. Wenn Du a änderst, änderst Du b, und umgekehrt.
  3. Wenn Du die Rechte oder den Besitz von a änderst, änderst Du dies genauso bei b, und umgekehrt.
  4. Wenn Du sie überschreibst, indem Du eine dritte Datei an den Anfang von ihr kopierst, wirst Du ebenso b überschreiben, außer Du sagst cp, es solle vor dem Überschreiben löschen ("unlink")!! Beachte (hinzugefügt 2002.Apr.10): Die vorige Aussage bezieht sich nur auf Änderungen im Dateiinhalt, nicht auf Rechte oder Besitz.

Das wirft eine interessante Frage auf. Was passiert, wenn Du einen der Links löschst ("rm")? Die Antwort ist, dass rm ("remove", entfernen, Anm.d.Ü.) eine falsche Benennung ist; es löscht eine Datei nicht wirklich, es entfernt gerade mal einen Link darauf. Der Dateiinhalt wird nicht tatsächlich gelöscht bis die Zahl der Links darauf Null erreicht. Im nächsten Augenblick werden wir diese Tatsache ausnützen, aber vorher noch ein Wort über cp.

Nutzung von cp -al

Im vorangehenden Abschnitt wurde erwähnt, dass das Hard-Linking von Dateien dem Kopieren gleich kommt. Deshalb sollte es keine Überaschung sein, dass das Standard GNU fileutils Kommando cp einen -l Schalter besitzt, welcher das Erzeugen von Hardlinks anstatt des Kopierens der Dateien bewirkt. (allerdings verlinkt cp -l keine Verzeichnisse, was seine guten Gründe hat; Diese kann man sich leicht selbst überlegen). Ein anderer geschickter Schalter ist -a (archive), welcher das cp Kommand dazu veranlasst, Verzeichnis rekursiv zu kopieren und - soweit möglich - die Besitzer, die Zeitstempel und die Zugriffsrechte der Datei zu erhalten.

Zusammen bewirkt die Kombination cp -al scheinbar die vollständige Kopie eines Verzeichnisbaumes, aber das ist in Wirklichkeit nur eine Illusion, die eigentlich keinen Speicherplatz verbraucht. Wenn wir unsere Operation auf der Kopie auf das Hinzufügen oder Entfernen von Dateien beschränken, also keine Änderungen erlauben, so ist die Illusion einer vollständigen Kopie perfekt. Die einzigen Unterschiede, die sich einem End-Benutzer offenbaren, sind die Tatsachen, dass diese Pseudo-Kopie keinen Speicherplatz verbraucht und nahezu keine Zeit zum Erzeugen benötigt.

Alles zusammenwerfen

Wir können rsync und cp -al kombinieren, um das zu erstellen, was als mehrfache Vollsicherungen eines Dateissystems erscheint, ohne den mehrfachen Platzbedarf. Und zwar so, in Kurzform:

rm -rf backup.3
mv backup.2 backup.3
mv backup.1 backup.2
cp -al backup.0 backup.1
rsync -a --delete source_directory/  backup.0/

Verbesserung (im Orginal 2003.04.23):

Seit rsync-2.5.6 ist die Option --link-dest verfügbar. Damit kann die Funktionalität von cp -al .. und rsync ... ersetzt werden, das Script lautet nun:

rm -rf backup.3
mv backup.2 backup.3
mv backup.1 backup.2
mv backup.0 backup.1
rsync -a --delete --link-dest=../backup.1 source_directory/  backup.0/

Wenn die obigen Kommandos jeden Tag ausgeführt werden, dann erscheinen backup.0, backup.1, backup.2 und backup.3 jede für sich als Vollsicherung von source_directory/, wie es heute, gestern, vorgestern und 3 Tage davor jeweils vorhanden war -- vollständig, jedoch werden Rechte und Besitzer in alten Schnappschüssen die jeweils neuesten Werte besitzen (Dank an J.W. Schultz für den Hinweis). In Wirklichkeit wird der zusätzliche Speicherplatz gleich der aktuellen Größe des source_directory/ und der gesamten Größe der Änderungen über die letzten drei Tage -- genau der Platz, den eine Vollsicherung und täglicher inkrementeller Sicherung mit dump oder tar benötigt hätten.

Vorschlag: Das Löschen des ältesten Backups (backup.3) nimmt reichlich Zeit in Anspruch, und das Erzeugen des neuen Backups (backup.0) ebenso. Dabei sind die Inhalte ja meistens fast identisch! Rasend schnell wird die Sache, wenn man das letzte Backup recycelt und als Vorlage nimmt, anstatt es zu löschen, die Links sind dann praktischerweise meistens schon da:

mv backup.3 backup.tmp
mv backup.2 backup.3
mv backup.1 backup.2
mv backup.0 backup.1
mv backup.tmp backup.0
rsync -a --delete source_directory/  backup.0/

Ich bin dump und tar gewohnt. Das Ganze erscheint rückständig!

Die Werkzeuge dump und tar wurden ursprünglich dafür ausgelegt, auf Bänder zu schreiben, das nur auf eine Datei zu einem Zeitpunkt zugreifen kann. Wenn Du ihre Art der inkrementellen Sicherung gewohnt bist, könnte rsync als rückständig erscheinen. Ich hoffe, das folgendes Beispiel wird helfen, die Unterschiede klarer herauszustellen.

Angenommen, auf einem bestimmten System werden Sicherungen Montag Nacht, Dienstag Nacht und Mittwoch Nacht gefahren. Und jetzt ist Donnerstag.

Mit dump oder tar ist die Montagssicherung die Aufwendige ("voll"). Es enthält alles im Dateisystem, was gesichert wurde. Die Dienstag- und Mittwoch-Incrementsicherungen werden viel kleiner sein, da sie nur die Änderungen seit dem letzten Tag enthalten. Zu bestimmten Zeitpunkten (vermutlich nächsten Montag) wird der Administrator eine weitere Vollsicherung planen.

Mit rsync dagegen ist die Mittwochssicherung das "dicke Ding". Tatsächlich ist die Vollsicherung immer die zuletzt erstellte. Das Dienstagsverzeichnis enthält nur die Daten der Dateien, die sich zwischen Dienstag und Mittwoch geändert haben; das Montagsverzeichnis wird nur die Daten enthalten, die zwischen Montag und Dienstag geändert wurden.

Ein kleines Argument könnte Dich überzeugen, dass die rsync-Art viel besser für Netzwerk-basierte Sicherungen ist, da nur noch einmal eine Vollsicherung notwendig ist, statt jede Woche. Danach müssen nur noch die Änderungen kopiert werden. Leider kann rsync nicht auf Bänder kopieren, und das ist vielleicht der Grund, warum die dump-und-tar-Incrementsicherungsmodelle noch so beliebt sind. Aber nach der Meinung des Autors sollten sie nicht mehr für Netzwerk-basierte Sicherungen genutzt werden, da jetzt rsync verfügbar ist.

Trennung der Sicherung vom Rest des Systems

Wenn Du es Dir einfach machst und Deine Sicherung in einem anderen Verzeichnis auf dem gleichen Dateisystem hältst, dann gibt es eine gute Chance, dass das, was auch immer Deine Daten beschädigt, auch Deine Sicherungen zerstört. In diesem Abschnitt zeigen wir ein paar Wege, das Risiko zu vermindern, indem die Sicherung getrennt gehalten wird.

Die einfache (schlechte) Art und Weise

Im vorigen Abschnitt behandelten wir /destination/ so, als ob es lediglich ein anderes Verzeichnis im gleichen Dateisystem wäre. Wollen wir das den leichten (schlechten) Ansatz nennen.

Glücklicherweise gibt es etliche einfache Arten, eine Sicherung widerstandsfähiger zu machen.

Halte es auf einer getrennten Partition

Wenn Dein Sicherungsverzeichnis auf einer getrennten Partition liegt, wird jede Zerstörung im Haupt-Dateisystem normalerweise die Sicherung nicht betreffen. Wenn der Sicherungsprozess keinen Plattenspeicher mehr hat, wird er missglücken, aber er wird nicht den Rest des Systems auch mitreißen. Wichtiger ist, dass Du, wenn Du die Sicherungen auf einer getrennten Partition hälts, sie schreibgeschützt mounten kannst.

RAID ist gut unterstützt unter Linux, und die in diesem Dokument beschriebenen Methoden können genauso genutzt werden, rotierende Schnappschüsse auf einem RAID-System zu erstellen.

Halte die Partition auf einer getrennten Platte

Wenn Deine Sicherungspartition auf einen anderen Platte liegt, bist Du auch vor Hardwaredefekten sicher. Das ist sehr wichtig, da Festplatten immer irgendwann einmal kaputt gehen und dann Deine Daten mitreißen. Es hat sich eine ganze Industrie gebildet, die den Bedarf befriedigt, der aus defekten Festplatten resultiert, die wichtige Daten enthalten und nicht richtig gesichert wurden.

Wichtig: Beachte aber, dass Du im Falle eines Festplattenfehlers immer noch alle Änderungen seit der letzten Sicherung verlierst. Für Privatanwender oder kleine Firmen (SoHo), deren Sicherungen täglich oder sogar stündlich wie in diesem Dokument beschrieben gesichert werden, ist das vermutlich in Ordnung, aber in Situationen, wenn jeder Datenverlust ein schwerwiegendes Problem ist (z.B. wenn finanzielle Transaktionen betroffen sind), ist ein RAID-System mehr angemessen.

Halte diese Platte auf einem getrennten Rechner

Wenn Du einen Reserverrechner hast, auch einen sehr Leistungschwachen, kannst Du ihn in einen reservierten Sicherungsserver umwandeln. Mach ihn eigenständig ("stand-alone"), setze ihn an einen physisch getrennten Platz -- ein anderer Raum oder gar ein anderes Gebäude. Schalte jeden einzelne Netzwerk-Dienst auf dem Sicherungsserver aus und verbinde ihn nur mit einem eigenständigen Netzwerkinterface an den Quellrechner.

Exportiere auf dem Quellrechner die Verzeichnisse, die Du mittels schreibgeschütztem NFS sichern willst, an die reservierte Schnittstelle. Der Sicherungsserver kann die exportierten Netwerkverzeichnisse anmelden und die in diesem Artikel besprochenen Schnappschuss-Routinen so laufen lassen, als wären sie lokal. Wenn Du für diesen Ansatz aufgeschlossen bist, wirst Du nur aus der Ferne verwundbar, falls:

  1. Ein root-Sicherheitsloch ("remote root hole") im read-only-NFS gefunden wurde, und
  2. der Quellrechner schon kompromittiert ist.

Ich halte das für einen "ziemlich guten" Schutz, aber wenn Du (in weiser Voraussicht) paranoid bist, oder Dein Job auf dem Spiel steht, baue zwei Sicherungsserver. Dann kannst Du sicherstellen, dass mindestens einer immer nicht am Netz ist.

Wenn Du einen ausgelagerten Sicherungsserver benutzt und Du keine eigenständige Leitung zu ihm hast (besonders, wenn die Information über irgendwas Unsicheres wie das öffentliche Internet läuft), solltest Du den NFS-Ansatz nicht anwenden und dafür rsync -e ssh benützen.

Es wurde mir mitgeteilt, dass rsync weit effizienter im Servermode arbeitet als über NFS. Wenn daher die Verbindung zwischen Quelle und Sicherungsserver der Flaschenhals wird, solltest Du überlegen, ob der Sicherungsrechner nicht als rsync-Server konfiguriert wird statt NFS zu benützen. Der Nachteil ist, dieser Ansatz ist etwas weniger für Benutzer durchschaubar als NFS -- Schnappschüsse erscheinen nicht als eingehängte Systemverzeichnisse, außer NFS wird in dieser Richtung benutzt, was sicherlich eine andere Möglichkeit ist (die ich noch nicht ausprobiert habe). Dank an Martin Pool, einem Hauptentwickler von rsync, der mich auf diese Möglichkeit hingewiesen hat.

Hier kommt noch ein anderes Beispiel für das Werkzeug dieses Ansatzes -- eines, das ich benutze. Wenn Du einen Haufen Windows-Arbeitsplätze in einem Labor oder Büro hast, ist es eine einfache Möglichkeit, diese alle gesichert zu halten, die entsprechenden Dateien (schreibgeschützt) freizugeben und alle auf dem reservierten Sicherungsserver mittels SAMBA einzuhängen. Der Sicherungsjob kann mittels Samba eingehängte Freigaben wie normale lokale Verzeichnisse behandeln.

Sicherungen möglichst schreibschützen

In den vorigen Abschnitten erläuterten wir Wege, Deine Sicherungsdaten physisch getrennt von den zu sichernden Daten zu halten. In diesem Abschnitt sprechen wir über die andere Seite der Medallie -- Benutzerprozesse sollen davon abgehalten werden, die Sicherungen, die sie einmal gemacht haben, zu ändern.

Wir wollen vermeiden, ein Schnappschuss-Sicherungsverzeichnis schreib/lesbar allgemein zugänglich angemeldet zu lassen. Leider funktioniert es nicht in jedem Fall, es die ganze Zeit schreibgeschützt angemeldet zu halten -- der Sicherungsprozess benötigt Schreibzugriff. Es wäre ideal für Sicherungen, wenn sie an einem öffentlichen Platz schreibgeschützt, aber gleichzeitig in einem privaten Verzeichnis nur für root, z.B. als /root/snapshot, zugänglich wäre.

Es ist verlockend, die Sicherungspartition schreibgeschützt als /snapshot die meiste Zeit anzumelden und während des kurzen Zeitraums, in der der Schnappschuss erzeugt wird, sie als schreibbar umzumelden ("remount"). Widerstehe der Versuchung!

Schlecht: mount/umount

Ein Dateisystem kann nicht abgemeldet werden, wenn es belegt ("busy") ist, wenn also manche Prozesse es benützen. Der "störende" Prozess muss nicht root gehören um eine Abmeldeanforderung zu blockieren. Also wenn Du vorhast, die schreibgeschützte Sicherungskopie abzumelden und es irgendwann wieder read-write anzumelden, mach es nicht -- jeder Benutzer kann versehentlich (oder absichtlich) die Sicherung verhindern. Außerdem, auch wenn blockierende umounts nicht der Hauptgrund sind, dieser Ansatz würde kurze Zeiträume einführen, während denen die Sicherungen als verschwunden erscheinen, was die Benutzer vewirren könnte.

Better: mount read-only most of the time

A better but still-not-quite-satisfactory choice is to remount the directory read-write in place:

Ein besserer, aber immer noch nicht ganz zufriedenstellender Weg ist das remounten des Verzeichnisses für Schreib-/Lesezugriff am selben Ort.

mount -o remount,rw /snapshot
[ run backup process ]
mount -o remount,ro /snapshot

So wird jeder Prozess, der auf /snapshot arbeitet, während das Backup startet nicht davon abgehalten, seine Transaktionen durchzuführen. Unglücklicherweise öffnet dieser Effekt ein neues Problem - es entsteht ein kurzes Zeitfenster, in dem das System verletzungsanfällig ist: Während das Backup im Gange ist könnte ein Benutzerprozess in das Backup-Verzeichnis schreiben. Mehr noch! Wenn ein Benutzerprozess eine Datei im Backup-Verzeichnis für einen Schreibzugriff geöffnet hat während das Medium wieder im Nur-Lesezugriff gemountet werden soll, so ist ein remount nicht möglich und das Verzeichnis bleibt auf unbestimmte Zeit verletzungsanfällig.

Der erste Satz in diesem Absatz ist etwas konfus - also bitte nochmal anschauen!

Verlockend, aber scheinbar nicht funktionierend: "mount --bind" mit dem 2.4-Kernel

Seit der 2.4-Serie des Linux-Kernels ist es möglich, ein Dateisystem gleichzeitig an zwei verschiedenen Stellen einzuhängen. "Aha!" wirst Du denken, wie ich auch. "Dann können wir die Sicherungen schreibgeschützt in /snapshot und schreibbar in /root/snapshot zur gleichen Zeit einhängen".

Leider nein. Sagen wir, Deine Sicherungen sind auf der Partition /dev/hdb1. Wenn Du das Kommando

mount /dev/hdb1 /root/snapshot
mount --bind -o ro /root/snapshot /snapshot

gibst, wird mount (mindestens wie im 2.4.9-Linux-Kernel) melden, dass /dev/hdb1 schreibbar in /root/snapshot und schreibgeschützt in /snapshot eingehängt ist, wie Du es gefordert hast. Lass Dich vom System nicht in die Irre führen!

Es scheint so, mindestens auf meinem System, das schreibbar/schreibgeschützt eine Eigenschaft des Dateisystems, nicht des Mountpoints ist, so dass weder /etc/mtab noch /proc/mounts diesen Wechsel anzeigen.

In dem obigen Beispiel wird der zweite mount-Aufruf für beide mounts den Schreibschutz bewirken, und der Sicherungsprozess kann nicht laufen. Streich also diesen Versuch.

Update: Ich habe aus ziemlich gut unterrichteten Kreisen erfahren, dass dieses Verhalten als Fehler im Linux-Kernel angesehen wird, der korrigiert wird, so bald jemand dazukommt. Wenn Du der Kernel-Verantwortliche bist und mehr darüber weißt oder Du am Korrigieren bist, würde ich mich freuen, von Dir zu hören.

Meine Lösung: NFS auf localhost benutzen

Dies ist ein bisschen komplizierter, aber bis Linux "mount --bind" mit verschiedenen Zugriffsrechten an verschiedenen Orten zulässt, ist es anscheinend die beste Wahl. Melde die Partition, wo die Sicherungen irgendwo gespeichert sind, nur von root zugreifbar per mount an, z.B. als /root/snapshot. Dann exportiere dieses schreibgeschützt mittels NFS, aber nur auf dem gleichen Rechner. Das ist so einfach, wie folgende Zeile in /etc/exports einzufügen:

/root/snapshot 127.0.0.1(secure,ro,no_root_squash)

Dann starte nfs und portmap von /etc/rc.d/init.d/. Zuletzt hänge das exportierte Verzeichnis schreibgeschützt, z.B. in /snapshot, ein:

mount -o ro 127.0.0.1:/root/snapshot /snapshot

Und versichere Dich, dass alles funktioniert:

mount
...
/dev/hdb1 on /root/snapshot type ext3 (rw)
127.0.0.1:/root/snapshot on /snapshot type nfs (ro,addr=127.0.0.1)

An diesem Punkt haben wir den gewünschten Effekt: Nur root kann auf die Sicherung schreiben (indem er über /root/snapshot geht). Die anderen Benutzer werden nur das schreibgeschützte /snapshot-Verzeichnis sehen. Für einen kleinen Zusatzschutz kannst Du die Sicherung die meiste Zeit read-only in /root/snapshot angemeldet halten und sie nur dann schreibbar ummelden, wenn die Sicherung läuft.

Erweiterungen: Stündliche, tägliche und wöchentliche Schnappschüsse

Mit ein bisschen Optimierung machen wir rotierende Schnappschüsse für mehrere Ebenen. Auf meinem System, zum Beispiel, halte ich die letzten vier "stündliche" Schnappschüsse (die alle 4 Stunden gezogen werden) genau so wie die letzten drei Tagesschnappschüsse, die jeden Tag um Mitternacht erfolgen. Vielleicht willst Du Wochen- oder Monatsschnappschüsse genauso halten, abhängig von Deinen Bedürfnissen und Deinem vorhanden Platz.

Halte ein eigenes Skript für jede Ebene

Dies ist wahrscheinlich der einfachste Weg, dies zu tun: Ich habe ein Skript, das alle vier Stunden läuft um die stündlichen Schnappschüsse zu erzeugen und zu rotieren, und ein anderes Skript, das einmal am Tag läuft um den täglichen Schnappschuss zu rotieren. Es gibt keinen Grund, rsync für die Schnappschüsse der höheren Ebenen zu benützen; kopiere einfach mit cp -al die passende Stunde.

Starte alles mit cron

Damit die automatischen Schnappschüsse aktiviert werden, habe ich folgende Zeilen in roots crontab-Datei eingetragen:

0 */4 * * * /usr/local/bin/make_snapshot.sh
0 13 * * *  /usr/local/bin/daily_snapshot_rotate.sh

Diese bewirken, dass make_snapshot.sh alle 4 Stunden und dayly_snapshot_rotate.sh jeden Tag um 13:00 Uhr laufen. Ich habe die Skripts im Anhang eingefügt.

Wenn es dich stört, EMail vom cron-Prozess alle vier Stunden zu bekommen mit den Details, was gesichert wurde, dann kannst Du ihm mitteilen, dass er die Ausgabe von make_snapshot.sh nach /dev/null schicken soll, etwa so:

0 */4 * * * /usr/local/bin/make_snapshot.sh >/dev/null 2>&1

Understand, though, that this will prevent you from seeing errors if make_snapshot.sh cannot run for some reason, so be careful with it. Creating a third script to check for any unusual behavior in the snapshot periodically seems like a good idea, but I haven't implemented it yet. Alternatively, it might make sense to log the output of each run, by piping it through tee, for example.

Aber sei Dir klar darüber, das dies Dich davon abhält, Fehler zu erkennen, wenn make_snapshot.sh aus irgendeinem Grund nicht laufen kann, sei also vorsichtig damit. Ein drittes Skript zu erzeugen, das in den Schnappschüssen auf jedes ungewöhnliche Verhalten testet, scheint eine gute Idee, aber ich habe es noch nicht erstellt. Alternativ hat es einen Sinn, die Ausgabe jedes Laufs zu protokollieren, z.B. indem man die Ausgabe durch tee zusätzlich in eine Datei schreibt.

Anhang: meine aktuelle Konfiguration

Ich weiß, die Auflistung meiner aktuellen Sicherungskonfiguration ist ein Sicherheitsrisiko; bitte sei anständig und nutze diese Information nicht, in meiner Seite einzudringen. Ich bin kein Sicherheitsexperte, also wenn Du irgendwelche Schwachstellen in meinem Aufbau siehst, begrüße ich Deine Hilfe sehr, diese zu verbessern. Danke!

Zur Zeit benütze ich zwei Skripte, eines für alle vier Stunden ("stündlich"), eines für die jeden-Tag-Schnappschüsse ("täglich"). Ich füge nur die Teile des Skripts ein, die mit der Sicherung von /home zusammenhängen, wenn diese zu dem hier gesagten relevant sind.

Ich benutze den NFS-auf-localhost-Trick, /root/snapshot schreibgeschützt als /snapshot zu exportieren, wie oben ausgeführt.

Dieses System läuft ohne Probleme seit Monaten.

Listing eins: make_snapshot.sh

# ----------------------------------------------------------------------
# mikes handy rotating-filesystem-snapshot utility
# ----------------------------------------------------------------------
# RCS info: $Id: rsync_2fSnapshotBackups,v 1.16 2003/01/16 02:43:23 linuxwiki_de Exp $
# ----------------------------------------------------------------------
# this needs to be a lot more general, but the basic idea is it makes
# rotating backup-snapshots of /home whenever called
# ----------------------------------------------------------------------

# ------------- system commands used by this script --------------------
ID=/usr/bin/id;
ECHO=/bin/echo;

MOUNT=/bin/mount;
RM=/bin/rm;
MV=/bin/mv;
CP=/bin/cp;
TOUCH=/bin/touch;

RSYNC=/usr/bin/rsync;


# ------------- file locations -----------------------------------------

MOUNT_DEVICE=/dev/hdb1;
SNAPSHOT_RW=/root/snapshot;
EXCLUDES=/usr/local/etc/backup_exclude;


# ------------- the script itself --------------------------------------

# make sure we're running as root
if (( `$ID -u` != 0 )); then { $ECHO "Sorry, must be root.  Exiting..."; exit; } fi

# attempt to remount the RW mount point as RW; else abort
$MOUNT -o remount,rw $MOUNT_DEVICE $SNAPSHOT_RW ;
if (( $? )); then
{
        $ECHO "snapshot: could not remount $SNAPSHOT_RW readwrite";
        exit;
}
fi;


# rotating snapshots of /home (fixme: this should be more general)

# step 1: delete the oldest snapshot, if it exists:
if [ -d $SNAPSHOT_RW/home/hourly.3 ] ; then                     \
$RM -rf $SNAPSHOT_RW/home/hourly.3 ;                            \
fi ;

# step 2: shift the middle snapshots(s) back by one, if they exist
if [ -d $SNAPSHOT_RW/home/hourly.2 ] ; then                     \
$MV $SNAPSHOT_RW/home/hourly.2 $SNAPSHOT_RW/home/hourly.3 ;     \
fi;
if [ -d $SNAPSHOT_RW/home/hourly.1 ] ; then                     \
$MV $SNAPSHOT_RW/home/hourly.1 $SNAPSHOT_RW/home/hourly.2 ;     \
fi;

# step 3: make a hard-link-only (except for dirs) copy of the latest snapshot,
# if that exists
if [ -d $SNAPSHOT_RW/home/hourly.0 ] ; then                     \
$CP -al $SNAPSHOT_RW/home/hourly.0 $SNAPSHOT_RW/home/hourly.1 ; \
fi;

# step 4: rsync from the system into the latest snapshot (notice that
# rsync behaves like cp --remove-destination by default, so the destination
# is unlinked first.  If it were not so, this would copy over the other
# snapshot(s) too!
$RSYNC                                                          \
        -va --delete --delete-excluded                          \
        --exclude-from="$EXCLUDES"                              \
        /home/ $SNAPSHOT_RW/home/hourly.0 ;

# step 5: update the mtime of hourly.0 to reflect the snapshot time
$TOUCH $SNAPSHOT_RW/home/hourly.0 ;

# and thats it for home.

# now remount the RW snapshot mountpoint as readonly

$MOUNT -o remount,ro $MOUNT_DEVICE $SNAPSHOT_RW ;
if (( $? )); then
{
        $ECHO "snapshot: could not remount $SNAPSHOT_RW readonly";
        exit;
} fi;

Wie oben zu sehen ist, habe ich eine exclude-Liste zu dem rsync Aufruf hinzugefügt. Das dient dazu, das System davon abzuhalten, Datenmüll wie z.B. Caches von Browsern, der sich laufend ändert ab bei einem Datenverlust keine Rolle spielt, zu sichern.

Listing zwei: daily_snapshot_rotate.sh

# ----------------------------------------------------------------------
# mikes handy rotating-filesystem-snapshot utility: daily snapshots
# ----------------------------------------------------------------------
# RCS info: $Id: rsync_2fSnapshotBackups,v 1.16 2003/01/16 02:43:23 linuxwiki_de Exp $
# ----------------------------------------------------------------------
# intended to be run daily as a cron job when hourly.3 contains the
# midnight (or whenever you want) snapshot; say, 13:00 for 4-hour snapshots.
# ----------------------------------------------------------------------

# ------------- system commands used by this script --------------------
ID=/usr/bin/id;
ECHO=/bin/echo;

MOUNT=/bin/mount;
RM=/bin/rm;
MV=/bin/mv;
CP=/bin/cp;

# ------------- file locations -----------------------------------------

MOUNT_DEVICE=/dev/hdb1;
SNAPSHOT_RW=/root/snapshot;

# ------------- the script itself --------------------------------------

# make sure we're running as root
if (( `$ID -u` != 0 )); then { $ECHO "Sorry, must be root.  Exiting..."; exit; } fi

# attempt to remount the RW mount point as RW; else abort
$MOUNT -o remount,rw $MOUNT_DEVICE $SNAPSHOT_RW ;
if (( $? )); then
{
        $ECHO "snapshot: could not remount $SNAPSHOT_RW readwrite";
        exit;
}
fi;


# step 1: delete the oldest snapshot, if it exists:
if [ -d $SNAPSHOT_RW/home/daily.2 ] ; then                      \
$RM -rf $SNAPSHOT_RW/home/daily.2 ;                             \
fi ;

# step 2: shift the middle snapshots(s) back by one, if they exist
if [ -d $SNAPSHOT_RW/home/daily.1 ] ; then                      \
$MV $SNAPSHOT_RW/home/daily.1 $SNAPSHOT_RW/home/daily.2 ;       \
fi;
if [ -d $SNAPSHOT_RW/home/daily.0 ] ; then                      \
$MV $SNAPSHOT_RW/home/daily.0 $SNAPSHOT_RW/home/daily.1;        \
fi;

# step 3: make a hard-link-only (except for dirs) copy of
# hourly.3, assuming that exists, into daily.0
if [ -d $SNAPSHOT_RW/home/hourly.3 ] ; then                     \
$CP -al $SNAPSHOT_RW/home/hourly.3 $SNAPSHOT_RW/home/daily.0 ;  \
fi;

# note: do *not* update the mtime of daily.0; it will reflect
# when hourly.3 was made, which should be correct.

# now remount the RW snapshot mountpoint as readonly

$MOUNT -o remount,ro $MOUNT_DEVICE $SNAPSHOT_RW ;
if (( $? )); then
{
        $ECHO "snapshot: could not remount $SNAPSHOT_RW readonly";
        exit;
} fi;

Beispielausgabe mit ls -l von /snapshot/home

total 28
drwxr-xr-x   12 root     root         4096 Mar 28 00:00 daily.0
drwxr-xr-x   12 root     root         4096 Mar 27 00:00 daily.1
drwxr-xr-x   12 root     root         4096 Mar 26 00:00 daily.2
drwxr-xr-x   12 root     root         4096 Mar 28 16:00 hourly.0
drwxr-xr-x   12 root     root         4096 Mar 28 12:00 hourly.1
drwxr-xr-x   12 root     root         4096 Mar 28 08:00 hourly.2
drwxr-xr-x   12 root     root         4096 Mar 28 04:00 hourly.3

Beachte, dass der Inhalt jedes Unterverzeichnisses von /snapshot/home ein komplettes Abbild von /home zu dem Zeitpunkt ist, an dem der Schnappschuss gemacht wurde. Trotz des w in den Verzeichniszugriffsrechten kann niemand -- auch root nicht -- in dieses Verzeichnis schreiben. Es ist schreibgeschützt angemeldet.

Bugs

Wie beschrieben behandelt das Schnappschusssystem alte Besitz- und Zugriffsrechte nicht korrekt; Wenn ein Dateibesitz oder -recht am Ort geändert wird, wird das neue Besitz-/Zugriffsrecht in alten Schnappschüssen genauso erscheinen. Danke an J.W. Schultz für den Hinweis. Das ist für mich kein Problem, aber es sind etwas kompliziertere Workarounds möglich.

Anscheinend veranlasst ein Fehler in einigen Linux-Kerneln zwischen 2.4.4 und 2.4.9 mv dazu, Zeitstempel zu aktualisieren; das kann zur Folge haben, dass ungenaue Zeitstempel in Schnappschussverzeichnissen auftauchen. Danke an Claude Felizardo für den Hinweis. Er konnte eine Lösung anbieten, indem der mv-Befehl durch folgendes Skript ersetzt wird:

MV=my_mv;
...
function my_mv() {
   REF=/tmp/makesnapshot-mymv-$$;
   touch -r $1 $REF;
   /bin/mv $1 $2;
   touch -r $REF $2;
   /bin/rm $REF;
}

Referenzen

rsync/SnapshotBackups (zuletzt geändert am 2013-03-07 12:38:21 durch pc03-175)