Backup

Einleitung

Das immer wieder verschobene und heruntergespielte Thema Backup ("Also mir geht keine Festplatte hopps!") hat es doch endlich auf diese Seiten geschafft.

Fehlende Datensicherung ist schlichtweg grob fahrlässig, oder? ;-)

« zurück (Gesammelte Anleitungen)

Inhalt

Grundgedanken

Die Festplattenkapazitäten steigen und man kauft sich mal eben eine externe Festplatte mit 250 GB. Dann rippt man seine CD-Sammlung, was einen Haufen an Zeit in Anspruch nimmt und hofft, dass nichts mit der Platte passiert. Klar, die Originale hat man ja noch, aber das ganze nochmal von vorne anfangen? Nein danke!

Mails, was für eine Unmenge an Mails! Zum Glück liegen die auf dem hiesigen IMAP-Server... aber der ist ja auch schon etwas betagt. Und dann die Konfiguration der beiden Systeme... das alles wieder von Null an einrichten? Oje...

Zugegeben, mir ist noch keine Festplatte abgeraucht. Toi! Toi! Toi! Aber muss man es erst aus Schaden klug werden? :?

Wo sichert man diese Unmenge an Daten hin? DVD sind mit ihrer ~5 GB Kapazität nicht geeignet. Also muss eine weitere externe Festplatte her, die die angesammelten Daten speichern kann.

Eine reine Datenspiegelung ist nett, was aber ist mit versehentlich gelöschten oder korrupten Dateien? Ein Rücksprung auf ältere Versionen ist schon wünschenswert. Aber wenn man mehrere Versionen vorhält, sichert man auch wieder viele Daten doppelt und dreifach?

Fragen über Fragen... aber erstmal wollen die Festplatten richtig ins System eingebunden werden, also fangen wir doch damit an.

« nach oben

Externe Festplatten einhängen mit Labels

Mit zwei externen Festplatten kommt dann auch schon das erste Problem. Je nachdem, welche der Platten zuerst eingeschaltet wird, bekommt die Gerätedatei sda zugewiesen, die andere sdb. Woher weiß ich denn jetzt, welche der Partitionen ich unter /backup und welche ich unter /data einbinden muss? :rolleyes:
Eine Möglichkeit der Unterscheidung ist es, den sich auf der Festplatte befindenden Dateisystemen sogenannte Labels zu verpassen.

Ein Label ist eine Bezeichnung, die auf Dateisystemebene vergeben wird. Labels können bis zu 16 Zeichen (xfs: 12 Zeichen) lang sein und werden von den gängigen Dateisystemen ext2, ext3, reiserfs, xfs und jfs unterstützt. Labels können beim Anlegen des Dateisystems oder mit den Managementprogrammen auch nachträglich vergeben werden. Des Setzen der Labels funktioniert (zumindest bei xfs) nicht im laufenden Betrieb, was bei einer externen Datenplatte aber kein Problem darstellt, da man diese problemlos kurz aushängen kann. Für ein xfs-Dateisystem kann man das Label mit dem Programm xfs_admin setzen:

# xfs_admin -L '/backup' /dev/sda1
# xfs_admin -L '/data' /dev/sdb1

In dem obigen Fall hat die erste Partition der eingebundenen USB-Festplatte ein XFS-Dateisystem, das nun das Label "/backup" trägt. Die andere Festplatte ist für Daten jeglicher Art gedacht und trägt das Label "/data". Die Bezeichnungen der Labels leitet sich von den zukünftigen Mountpoints ab, die im nächsten Schritt in der Datei /etc/fstab angegeben werden:

# /etc/fstab
#
...       weitere Einhaengepunkte       ...
... unter anderem die Systempartitionen ...

LABEL=/backup /backup xfs ro,noauto   0 0
LABEL=/data   /data   xfs user,noauto 0 0

Die Backup-Platte kann nur von root eingebunden werden und dann auch nur im schreibgeschützten Modus. Sie wird automatisch vor Beginn der Backupjobs zum Schreiben gemountet und danach wieder schreibgeschützt einhängt. Die am Ende stehende 0 sorgt dafür, dass diese Partitionen nicht von fsck geprüft werden, da die Geräte zu diesem Zeitpunkt evtl. noch gar nicht eingeschaltet sind.

Damit sind die Einträge unabhängig von den Gerätenamen. Das kann man natürlich auch für die ganzen Systempartitionen machen:

# /etc/fstab
#
LABEL=/       /     reiserfs notail                                    0 1
LABEL=/usr    /usr  xfs      ro                                        0 2
LABEL=/var    /var  reiserfs defaults                                  0 2
LABEL=/home   /home xfs      defaults                                  0 2
LABEL=schwapp none  swap     sw                                        0 0
proc          /proc proc     defaults                                  0 0
tmpfs         /tmp  tmpfs    rw,size=64M,mode=1777,nodev,nosuid,noexec 0 0

...       weitere Einhaengepunkte       ...

Wichtig bei einer solchen Systemkonfiguration mit Labels ist aber, dass diese eindeutig bleiben, wenn man neue Geräte einhängt (z.B. um von diesen Platten Daten zu retten). Das Label der Swap-Partition kann mit

# mkswap -L 'schwapp' /dev/hda6

beim Anlegen gesetzt werden.

Die externen Platten sind eingehängt... es kann losgehen! :)

« nach oben

dirvish - ein Backuptool

Grundsätzliches

Bevor man sich selbst an die Arbeit macht und eine größere Skriptlösung für eine Problemstellung erstellt, die mit Sicherheit schon jemand programmiert hat, sieht man sich mal nach bestehenden Lösungen um. Ein mögliches Backuptool ist dirvish. Dieses nutzt rsync zum Abgleich der zu sichernden Verzeichnisse und kopiert dabei nur die Daten, die sich seit dem vorherigen Backupjob geändert haben. Die ungeänderten Daten werden als Hardlinks angelegt und somit hat man immer einen kompletten Datenbestand als Sicherung, die alle unabhägig voneinander gelöscht werden können, wenn sie veraltet sind.

Hardlinks contra symbolische Links

Symbolische Links beinhalten einen Pfad, der auf eine Datei oder ein Verzeichnis zeigt. Ein symbolischer Link zeigt also auf den Pfadnamen einer Datei oder eines Verzeichnisses und hat sonst keinen weiteren Inhalt. Kopiert man einen symbolischen Link, kopiert man nur den Pfadnamen von der Datei, auf den der Link zeigt.

Hardlinks beinhalten einen Namen und einen Dateideskriptor, die sogenannte Inode.

Hardlinks können die Grenze eines Dateisystems nicht überschreiten, da Inodes in jedem angelegten Dateisystem unabhängig voneinander gezählt werden. Es kann somit in zwei verschiedenen Dateisystemen die Inode mit der Nummer 13544 geben, die natürlich auch unterschiedliche Dateien repräsentieren.

Hinter jeder Inode verbirgt sich ein Datenbereich im Dateisystem, zu dem die Eigenschaften wie die Größe, Besitzer und Zugriffsrechte, Erstellungsdatum, etc. und auch die Anzahl der auf sie zeigenden Hardlinks beinhaltet. Legt man einen neuen Hardlink an, wird diese Anzahl um eins erhöht. "Löscht" (unlink) man einen dieser Links, verringert sich diese Zahl um eins. Wenn die Anzahl der auf eine Inode zeigenden Hardlinks auf 0 steht, wird der von der Inode reservierte Datenbereich freigegeben.

Das Löschen einer Datei mit rm entspricht also lediglich dem Entfernen eines Hardlinks von einer Datei. In der Systemprogrammierung findet man deswegen auch keine Funktion rm() oder remove(), sondern unlink().

Wird nun eine veraltete Datensicherung gelöscht, geschieht das unabhängig von den anderen Datenbeständen. Der Hauptvorteil bei der Verwendung von Hardlinks liegt darin, dass gleiche Daten nur einmal auf der Platte landen. Ein weiterer Hardlink darauf macht nur wenige weitere Bytes aus. Damit kann man eine große Anzahl an Tagesständen sichern, zu denen man immer zurückkehren oder einzelne Dateien daraus wiederherstellen kann.

Globale Konfiguration

Vorher noch ein paar Überlegungen:

  • Sollen auch Daten von anderen Hosts gesichert werden?
  • Was soll überhaupt gesichert werden?
  • Was soll nicht gesichert werden?

Um verschiedene Szenarien abzudecken, hier die Konfiguration für zwei Hosts, auf denen diverse Datenbereiche separat gesichert werden sollen. Die Hostnamen sind iridium und selenium, die jeweils als eine eigene bank definiert werden. In so einer Bank liegen nun mehrere vaults (engl: vault = Tresor), in denen die Dateien und Statistiken der Backupjobs abgelegt werden. Jedes zu sichernde Verzeichnis bekommt somit einen eigenen Tresor zugewiesen. Über die Tresornamen werden auch die bei einem run-all auszuführenden Backupjobs angesprochen, gelistet unterhalb der Option Runall.

Beispiel der globalen Konfigurationsdatei /etc/dirvish/master.conf:

bank:
        /backup/iridium
        /backup/selenium
xdev: 1
log: gzip
index: gzip
image-default: %Y%m%d

exclude:
        lost+found/
        core
        *~
        .nfs*

Runall:
        iridium-data
        iridium-etc
        iridium-home
        iridium-root
        selenium-etc
        selenium-home
        selenium-root
        selenium-var_lib_cvs
        selenium-var_spool_cyrus
        selenium-var_spool_sieve

expire-default: +15 days
expire-rule:
# MIN HR    DOM MON       DOW  STRFTIME_FMT
  *   *     *   *         1    +3 months
# ^--- Sonntags ausgefuehrte Backups haben
#      eine laengere Aufbewahrungszeit

Die Optionen aus der Konfigurationsdatei im einzelnen:

  • bank
    Definiert die Wurzelverzeichnisse für die Datensicherung. Hier wurden für zwei Hosts jeweils ein eigenes Verzeichnis angelegt. Darunter liegen dann die Vaults, in denen die Sicherungjobs abgelegt werden.
  • xdev: 1 oder 0
    1 = nicht über Partitonsgrenzen hinweg sichern (keine Symlinks verfolgen)
  • log, index: gzip oder bzip2
    Von jeder Sicherung wird je ein Index und ein Logfile erstellt. Mit dieser Option werden diese Textdateien mit dem angegebenen Packprogramm komprimiert.
  • image-default: Datumsformat
    Legt das Format für den Verzeichnisnamen der jeweiligen Sicherung fest. Bei der obigen Konfiguration (%Y%m%d) zum Beispiel werden die Sicherungen dann wie folgt abgelegt:
    /backup/iridium/iridium-etc/20070427
    /backup/iridium/iridium-etc/20070428
    ...
    
  • exclude: File Pattern
    Globale Ausnahmen, die nicht mitgesichert werden sollen. Diese können noch in den einzelnen Sicherungsjobs erweitert werden.
  • Runall: Job List
    Die Sicherungsjobs werden beim Aufruf von dirvish-runall ausgeführt. Hinter den Jobs kann auch noch eine Zeitangabe stehen, z.B.
    iridium-root 23:00
    
    die aber rein kosmetischer Natur ist. Der Backup trägt dann den angegebenen Zeitstempel, z.B. aus Konsistenzgründen.
  • expire-default: Time Value (Format von Time::ParseDate Perl Modul)
    Default Zeitraum, nachdem ein Backup ungültig, sprich gelöscht, wird.
  • expire-rule:
    Regeln, um bestimmten Backups ein anderes Verfallsdatum, als das unter dem Default Zeitraum eingestellten, zu verpassen. Hier wird z.B. jedes am Sonntag erstellte Backup auf 3 Monate eingestellt (Day Of Week = 1 = Sonntag).
    # MIN HR    DOM MON       DOW  STRFTIME_FMT
       *   *     *   *         1    +3 months
    

Weitere, hier nicht verwendete Optionen:

  • rsh: Remote Shell (z.B. ssh -c arcfour)
  • image-perm: Oktalwert (z.B. 700)
    Rechte, mit denen die erstellten Backupverzeichnisse angelegt werden.
  • meta-perm: Oktalwert (z.B. 600)
    Rechte, mit denen die erstellten Indexe (Liste der gesicherten Daten) angelegt werden.

Backup Job Konfiguration

In jedem Vault muss ein Verzeichnis dirvish angelegt werden, das eine eigene Konfigurationsdatei mit dem Namen default.conf hat. Hier ein Beispiel für diese Datei:

# /backup/iridium/iridium-home/dirvish/default.conf
client: iridium
tree: /home/
exclude:
        *.bak
        .googleearth/Cache/*
        .gftp/cache/*
        .java/deployment/cache/*
        .kde/share/apps/kmail/dimap/*
        .kde/share/apps/kmail/imap/*
        .kde/share/apps/nsplugins/cache/*
        .kde/share/apps/RecentDocuments/*
        .kde/share/config/session/*
        .macromedia/*
        .mcop/trader-cache/*
        .mozilla/firefox/default/*/Cache/*
        .mozilla-thunderbird/*/ImapMail/*
        .netbeans/*/var/cache/*
        .opera/cache4/*
        .opera/cacheOp/*
        .opera/images/*
        .thumbnails/*

Verwendete Optionen:

  • client: Hostname
    Definiert, auf welchem Host die zu sichernden Daten liegen.
  • tree: Wurzelverzeichnis
    Definiert das zu sichernde Verzeichnis.
  • exclude:
    Erweiterung der globalen Ausnahmen speziell für diesen Sicherungsjob.

Es werden also auf dem Rechner iridium alle Heimverzeichnisse, abgesehen von den definierten Ausnahmen, gesichert. Die obige Konfiguration ist nicht weiter kompliziert und sollte klar sein.

« nach oben

Tresor Initialisierung

Bevor man dirvish nun im regelmäßigen Betrieb einsetzen kann, müssen die Tresore einmalig initialisiert werden. Hierzu werden alle Daten aus den zu sichernden Verzeichnissen in die Tresore kopiert, was je nach Datenmenge eine Weile dauern kann. Außerdem erzeugen dirvish-Läufe hohe Festplattenlast, was im Falle des Einsatzes in Produktivumgebungen zu beachten ist.

Die Initialisierung der Tresore erfolgt durch sequentielles Aufrufen von dirvish mit der Option --init:

# dirvish --vault iridium-data --init
# dirvish --vault iridium-etc --init
# dirvish --vault iridium-home --init
etc.

Nach der Initialisierung sind bereits alle zu sichernden Verzeichnisse zusätzlich innerhalb der Tresore gespeichert. Beim nächsten, zeitgesteuerten Aufruf von dirvish wird bereits der erste Abgleich damit durchgeführt. Während die Datenmenge nach der Initialisierung noch genauso groß wie die der zu sichernden Verzeichnisse ist, wird bei den Folgesicherungen nur noch der Teil an Speicherplatz zusätzlich belegt, den die seitdem geänderten Dateien einnehmen. Dennoch werden alle Dateien und Verzeichnisse in der Hierarchie vorhanden sein. Die ungeänderten Dateien belegen dabei aber kaum zusätzlichen Platz (zur Erinnerung: siehe Hardlinks im Kasten oben).

« nach oben

Einbinden der Backupjobs in Cron

Definition Cronjob

Ein Cronjob ist bei debian bereits vorkonfiguriert und liegt unter /etc/cron.d/dirvish bereit:

# /etc/cron.d/dirvish
# run every night
4 22 * * *     root     /etc/dirvish/dirvish-cronjob

Der Backupjob wird jeden Tag um 22:04 Uhr gestartet. Ich persönlich bevorzuge es, wenn der Job direkt in der Datei /etc/crontab gelistet ist, am besten noch mit einer Kontrolle, ob das Skript existiert:

# /etc/crontab
#
# [... weitere Eintraege (z.B. anacron) ...]

# run a backup using dirvish
4 22 * * *     root     test -x /etc/dirvish/dirvish-cronjob && /etc/dirvish/dirvish-cronjob

Jetzt fehlt nur noch das dazu gehörende Shellskript.

Das auszuführende Skript

Wenn man es sich ganz einfach machen will, reicht ein Einzeiler:

#!/bin/bash

/usr/sbin/dirvish-expire --quiet && /usr/sbin/dirvish-runall --quiet

Es wird zuerst ein dirvish-expire ausgeführt, um veraltete Backups zu löschen. Die Skripte dirvish-runall und dirvish-expire sollten nie zusammen (sprich: parallel) ausgeführt werden, da dirvish-expire sehr rechenintensiv arbeitet und der Backupvorgang dadurch sehr verlangsamt würde.

Bei diesem Skript muss allerdings gewährleistet sein, dass unter /backup permanent das Backuplaufwerk eingehängt ist!

Es folgt ein Skript, das auf dem mitgelieferten Standardskript von debian basiert. Die darin enthaltene Funktion mount_check() ist für mich etwas ungüstig, da der Mountcheck nur mit ext2 bzw. ext3 Dateisystemen funktioniert. Da ich aber XFS benutze, habe ich die Funktion so umgeschrieben, dass nach der bank /backup/iridium gesucht wird, die in jedem Fall existieren muss, wenn das Backuplaufwerk gemountet ist.

Außerdem soll eine Benachrichtigung erfolgen, bevor dirvish loslegt!

Hierfür wird mit dem Programm kdialog direkt bei dem angemeldeten Benutzer nachgefragt, ob es losgehen kann. Außdem wird nochmal auf das Einhängen der Festplatten aufmerksam gemacht, worum sich das Skript nicht kümmert.

Hinweis: Für einen automatisch ohne Nachfragen zu startenden Backupjob ist dieses Skript nicht zu gebrauchen, da es auf Interaktion wartet.

« nach oben

Clientspezifische Einstellungen

Man kann die Einstellungen für jeden zu sichernden Client überschreiben. Dazu legt man eine Datei mit dem Hostnamen unterhalb von /etc/dirvish ab, z. B.: /etc/dirvish/iridium, wenn der Rechner iridium heißt. In der Manpage dirvish.conf(5) wird das mit dem Namen client[.conf] abgehandelt.

Eine mögliche Anwendung wäre z. B. die Verwendung eines speziellen Backupusers an Stelle von root. Dieser muss natürlich (Lese-)Zugriff auf die zu sichernden Daten haben. Um das zu erreichen, überschreiben wir einfach die Remote-Shell für den Rechner iridium:

# /etc/dirvish/iridium
rsh: ssh -l backupuser

Damit das ohne Passwortabfrage funktioniert, muss natürlich wieder der öffentliche SSH-Schlüssel des Benutzers kopiert werden, der dirvish auf dem Backupserver ausführt. Normalerweise ist das root (via Cron). Informationen zu der SSH-Authentifizierung via Public Key habe ich hier beschrieben: Authentisierung mit PublicKey-Verfahren und SSH-Agent.

Grundsätzlich kann man natürlich auch alle anderen Konfigurationsparameter für einen Client überschreiben.

Und jetzt: Back it up! }:-)

« nach oben

Weiterführende Links

Weiteres zu dem Programm dirvish gibt es natürlich auch noch auf anderen Seiten:

« nach oben

« zurück (Gesammelte Anleitungen)