6.1 Aufbau eines Stores#
Ein Store ist ein Verzeichnis <store>.cbs unter dem --out-Verzeichnis bzw. auf dem Server unter <storage>/<verzeichnis>/. Er enthält:
| Teil | Inhalt |
|---|---|
store.json | Art (block), ID-Hash, Verschlüsselung samt Schlüssel-Prüfwert und Chunk-Größen. Wird beim Anlegen geschrieben und danach nie geändert. |
packs/<xx>/<id>.pack | Die Daten: Chunks und Verwaltungsobjekte (Manifeste), je Pack etwa 64 MiB, jedes Objekt komprimiert, ggf. verschlüsselt und mit Prüfsumme. |
runs/<zeit>-<uuid>.run | Je Sicherung eine kleine JSON-Datei. Sie wird als Letztes geschrieben: erst dann gibt es den Run (Commit-Punkt). |
index.lmdb | Index aller Objekte (LMDB). Nur ein Cache: fehlt er oder ist er kaputt, wird er aus den Packs neu aufgebaut. |
Ein Run besteht aus einem Manifest: die Quelle in Segmenten zu 1 GiB, jedes Segment eine Liste von Chunks und Löchern. Zwei Runs, die dieselben Daten enthalten, verweisen auf dieselben Chunks. Deshalb ist jeder Run vollständig und trotzdem klein.
- Mehrere Backup-Namen (zum Beispiel mehrere Rechner) dürfen gleichzeitig in denselben Store schreiben; jeder Schreiber legt eigene Packs an.
- Wartung, die Daten umschreibt (
prune,delete,repair,reindex), braucht den Store für sich und überspringt ihn bzw. wartet sonst. - Ein abgebrochenes Backup hinterlässt keinen halben Run, höchstens Daten ohne Run. Die räumt der nächste
pruneweg (frühestens nach--gc-min-age, Standard 24 h), sofern sie bis dahin kein neuer Run nutzt.
6.2 Backup-Namen je Store#
Mehrere Rechner dürfen in denselben Store sichern; gemeinsame Daten liegen dort nur einmal. Damit sich ihre Sicherungen nie vermischen, gehört ein Backup-Name (der Profilname, z. B. system) in einem Store genau einer Quelle: bei Rechner- und M365-Sicherungen der Installation (Installations-ID I-…, sie bleibt bei einer Neuaktivierung desselben Rechners), bei VM-Sicherungen der VM (ihre UUID). Wem ein Name gehört, steht im Namensregister <store>.names neben dem Store und in jedem Lauf (owner). Restore „neuester Lauf“, Aufbewahrung und GFS rechnen je Name.
- Sichert ein Rechner unter einem Namen, der im Store schon einem anderen gehört, wird die Sicherung vor dem ersten Block abgelehnt (Agent und Target prüfen). Die Meldung nennt den anderen Rechner und schlägt einen freien Namen vor, meist mit dem Hostnamen (
system-fs01). - Ersetzt der Rechner den anderen wirklich (neue Hardware, neu installiert), übernimmt er den Namen bewusst:
bkp_agent … --adopt-namebzw. in der Verwaltungskonsole im Job-Menü „Sicherungen übernehmen…“. Die bisherigen Läufe zählen danach für ihn; das Target vermerkt die Übernahme im Prüfprotokoll. - Der Job-Planer prüft die Namen seiner Profile täglich, nach jeder Änderung und nach einer abgelehnten Sicherung. Ein Konflikt erscheint als Zustand „Name vergeben“ (API
NAME_TAKEN) mit einer Mail; die Konsole zeigt ihn schon beim Anlegen des Profils und bietet „Umbenennen in …“ oder die Übernahme an. - Ältere Läufe ohne Besitzer gehören dem Rechner mit ihrem Hostnamen. Builds ohne Lizenz prüfen nicht.
Namen ansehen
bkp_maintenance store-info --store /srv/backups/default.cbs --names # wem jeder Name gehört, welche Rechner Läufe haben
bkp_restore --sink rz1 --name system --check-name /tmp/name.json # prüfen, ohne zu schreiben (frei, eigen, vergeben)
In der Target-Konsole zeigt der Reiter „Daten“ in der Spalte „Rechner“, von welchem Rechner die Läufe stammen („mehrere“, wenn ein Name Läufe mehrerer Rechner hat; store-info --names sagt dann, was zu tun ist).
6.3 Generationen#
Weil Runs Chunks gemeinsam nutzen, trifft ein Schaden an einem oft verwendeten Chunk viele Runs. Wer eine physisch unabhängige Basis möchte (wie früher eine neue FULL), beginnt eine neue Store-Generation: einen eigenen Store <store>.g<JJJJMMTT>.cbs neben <store>.cbs, der keine Daten mit den älteren teilt.
--type fullbeginnt eine neue Generation (in allen Sinks des Laufs; bei Proxmox/Xen einmal für den ganzen VM-Run). Der erste Run darin wird wieder ganz gespeichert.--store-generation <n>d|<n>m(z. B.1m) beginnt sie automatisch, sobald die aktuelle älter ist.- Restore,
--list,pruneundmirrorsehen alle Generationen eines Stores als eine Zeitleiste;pruneentfernt eine alte Generation, sobald sie keine Runs mehr hat. - Eine neue Generation darf einen anderen ID-Hash (
--hash) und eine andere Chunk-Größe (--chunk-size) bekommen. So wechselt man beides ohne Bruch.
bkp_agent --source data.img --out backup --name data --type full --hash blake3
Ausgabe:
[bkp_agent] INFO started the new store generation default.g20261015 (--type full; the previous one is default)
[bkp_agent] INFO created the store backup/default.g20261015.cbs (id hash blake3, encryption none, ...)
[bkp_agent] INFO done: full run 20261015T121849Z-44fdc352-... in backup/default.g20261015.cbs: ... chunks 44, new 44 (0.0% deduplicated); ...
bkp_restore --store backup/default.cbs --list --name data
Ausgabe:
RUN CREATED NAME TYPE ... NEW STATUS STORE
20261015T121825Z-6aa5d6f2-... 2026-10-15 14:18:25 data Full ... 12.0 MiB ok default
20261015T121831Z-8c47f436-... 2026-10-15 14:18:31 data Incremental ... 2.2 MiB ok default
20261015T121849Z-44fdc352-... 2026-10-15 14:18:49 data Full ... 12.0 MiB ok default.g20261015
Tipp: Eine neue Generation kostet einmal Platz und Zeit wie eine vollständige Sicherung. Ob und wie oft man sie braucht, ist eine Abwägung: ohne Generationen ist der Store am kleinsten, mit einer Generation je Monat (store-generation=1m) hat man regelmäßig eine unabhängige Basis. Gegen Bitrot helfen ohnehin scrub und eine zweite Kopie (mirror oder ein zweiter Sink, Kapitel 10).
6.4 Verschlüsselung#
Der Agent kann Chunks verschlüsseln, bevor sie lokal geschrieben oder zum Server gesendet werden, unabhängig für jeden Sink (encryption=/key= im [sink:<name>]-Abschnitt, Kapitel 4). Zur Auswahl stehen AES-256-GCM und ChaCha20-Poly1305; beide erkennen einen falschen Schlüssel oder verfälschte Daten sicher.
Schlüssel erzeugen und verschlüsselt sichern
bkp_maintenance encrypt-init --key-file /etc/bkp/out.key # Schlüssel einmalig erzeugen
bkp_agent --source /dev/vg0/data --sink lokal --name data # [sink:lokal] mit encryption= und key=
- Der Store bekommt Verfahren und Schlüssel-Prüfwert beim Anlegen; ein Lauf mit anderem Verfahren oder Schlüssel wird abgewiesen, bevor etwas geschrieben wird.
- Die IDs werden mit einem aus dem Schlüssel abgeleiteten Schlüssel gebildet. Ohne Schlüssel verrät der Store nur Struktur und Größen, nie Inhalte.
- Der Schlüssel gilt für die Lebensdauer des Stores bzw. der Generation; ein neuer Schlüssel geht nur mit einem neuen Store oder
--type full. - Angabe wie beim API-Key:
file:<pfad>, der Schlüssel selbst (64 Hex-Zeichen, nur in Konfigurationsdateien) oder das reserviertekms:<url>. - Ohne Schlüssel arbeiten
prune,delete,mirror,export/importund einscrubder Prüfsummen. Der Server braucht den Schlüssel nie.
Wichtig: Es gibt keinen Passwort-Ersatz. Geht die Schlüsseldatei verloren, sind die damit verschlüsselten Daten verloren. Die Datei gehört auf jede Maschine, die sie braucht (Agent, Restore), und zusätzlich an einen sicheren Ort außerhalb des gesicherten Systems.
6.5 S3-Objektspeicher#
Ein Store kann in einem S3-kompatiblen Objektspeicher liegen (AWS S3, Wasabi, MinIO und andere). Dahin kommen Sicherungen auf drei Wegen: der Agent schreibt direkt (Sink type=s3, Linux und Windows), das Target kopiert jede eingegangene Sicherung (Ziel [dest:<name>] kind=s3 und ein Job maint-mirror mit dest=<name>, in der Target-Konsole die Aktion „Kopie nach S3“), und Restore, Wartung und bkp_dump nehmen einen Store als s3:<name>/<pfad> (<name> = Abschnitt mit den S3-Einstellungen, --s3-config <datei>).
Ein S3-Sink in sinks.cfg
[sink:wasabi1]
type=s3
s3-endpoint=https://s3.eu-central-2.wasabisys.com
s3-bucket=aegisgrid-backup
s3-region=eu-central-2
s3-prefix=kunde1
s3-access-key=file:/etc/bkp/wasabi1.access
s3-secret-key=file:/etc/bkp/wasabi1.secret
encryption=aes-256-gcm
key=file:/etc/bkp/wasabi1.key
- Was nach S3 geht, ist immer verschlüsselt; ein
type=s3-Sink ohneencryption=/key=wird beim Laden abgewiesen. Unverschlüsselt eingegangene Stores verschlüsselt das Target beim Kopieren mit demkey=des Ziels, ohne ihn kopiert es sie nicht. - Zugangsschlüssel nur als
file:oderkms:. Die Konsolen legen sie als Dateien ab (nur für Administratoren lesbar) und zeigen sie nie wieder an. bkp_agent --s3-check <sink>bzw.bkp_maintenance s3-check s3:<name>prüft Verbindung, Zertifikat, Schlüssel, Bucket, Uhrzeit, bedingte Schreibzugriffe, Versionierung, Object Lock und ein Testobjekt; jede Stufe nennt den nächsten Schritt. Die Konsolen zeigen dasselbe unter „Verbindung prüfen“.- Der Index liegt lokal (
/var/cache/aegisgrid/s3/<store-uuid>, Windows%ProgramData%\AegisGrid\cache\s3\<store-uuid>); fehlt er, entsteht er aus den Pack-Footern neu. - Nur ein Schreiber: eine Lease im Bucket (
locks/, 10 Minuten, laufend erneuert); eine abgelaufene übernimmt das nächste Programm mit Warnung. - Vorübergehende Fehler (5xx, 429, abgebrochene Verbindung) werden bis zu 6-mal wiederholt; endgültige kommen mit Grund und nächstem Schritt.
- WORM:
worm=extendsperrt Packs und Runs per Object Lock (worm-mode=governanceodercompliance). Der Bucket braucht Object Lock ohne Standard-Aufbewahrung; Löschversuche auf gesperrte Objekte sind INFO-Zeilen.
Einzelheiten und alle Schlüssel: README, Abschnitt „S3-Objektspeicher“; die Abbildung im Bucket: docs/store-format.txt 2.4.
6.6 Store und Runs ansehen: bkp_dump#
bkp_dump backup/default.cbs
Ausgabe:
=== store backup/default.cbs ===
format : 1
uuid : e694d0f7-9e67-4409-a3c1-6c44a3a842a2
kind : block
encryption : none
key_check : (none)
id_hash : blake3
segment_size : 1073741824
chunker : fastcdc 65536 / 262144 / 1048576 (min / avg / max)
objects : 56
stored_bytes : 14849939
packs : 2
index : backup/default.cbs/index.lmdb
=== runs (2, oldest first) ===
run created kind backup_name type status source_size logical_bytes sent_bytes new_bytes expires
20261015T121825Z-6aa5d6f2-... 2026-10-15T14:18:25+02:00 block data Full ok 16777216 13631488 12587566 12587566 never
20261015T121831Z-8c47f436-... 2026-10-15T14:18:31+02:00 block data Incremental ok 16777216 13631488 2262373 2262373 never
Mit --run <run> zeigt bkp_dump zusätzlich den Run (Zeitpunkt, Rechner, Größen, Aufbewahrung, run_group), die Quelle und die Segmente; --extents listet jeden Chunk und jedes Loch (--limit <n>, Standard 50, 0 = alle). Bei verschlüsselten Stores braucht das Manifest --decrypt-key. Einen Überblick mit Deduplizierung, letzter Bereinigung und letztem Scrub gibt bkp_maintenance store-info (Kapitel 10).
bkp_dump backup/default.cbs --run 20261015T121831Z-8c47f436-cdc7-4638-a3f8-d347e0c5ba7c --extents --limit 3
Ausschnitt
=== segments (1) ===
segment offset length chunks holes data_bytes id
0 0 16777216 44 1 13631488 edcc0ef0d0bd68e2...
0 328147 data 79596f0301091b2334ddb6ead02f207789986b4a2003f5bc4d3a263c926614aa
328147 281294 data 1e5cc22f23588a0318012478db8c7e83b6b05dfa8d98c1541c5f50d5415d177c
609441 328454 data 5a40c945daf7bea90ee554230ac3a7d81cb5083dee156ceb7840305e8b34f9e1
... (more extents not shown; use --limit 0 for all)
total: 44 chunks, 13631488 data bytes, 1 holes, 3145728 hole bytes
6.7 Stores sicher verwalten#
- Lösche oder kopiere nie einzelne Dateien in einem Store. Runs löscht
bkp_maintenance prunebzw.delete, Kopien machtmirror, einzelne Runs schreibtexportals Archiv (Kapitel 10). - Lass
scrubregelmäßig laufen und halte eine zweite Kopie (zweiter Sink oder Spiegel) bereit, aus derrepairSchäden ersetzen kann.