Handbuch · Kapitel 6

Store und Runs

Zum Inhaltsverzeichnis

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:

TeilInhalt
store.jsonArt (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>.packDie Daten: Chunks und Verwaltungsobjekte (Manifeste), je Pack etwa 64 MiB, jedes Objekt komprimiert, ggf. verschlüsselt und mit Prüfsumme.
runs/<zeit>-<uuid>.runJe Sicherung eine kleine JSON-Datei. Sie wird als Letztes geschrieben: erst dann gibt es den Run (Commit-Punkt).
index.lmdbIndex 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 prune weg (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-name bzw. 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 full beginnt 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, prune und mirror sehen alle Generationen eines Stores als eine Zeitleiste; prune entfernt 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 reservierte kms:<url>.
  • Ohne Schlüssel arbeiten prune, delete, mirror, export/import und ein scrub der 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 ohne encryption=/key= wird beim Laden abgewiesen. Unverschlüsselt eingegangene Stores verschlüsselt das Target beim Kopieren mit dem key= des Ziels, ohne ihn kopiert es sie nicht.
  • Zugangsschlüssel nur als file: oder kms:. 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=extend sperrt Packs und Runs per Object Lock (worm-mode=governance oder compliance). 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 prune bzw. delete, Kopien macht mirror, einzelne Runs schreibt export als Archiv (Kapitel 10).
  • Lass scrub regelmäßig laufen und halte eine zweite Kopie (zweiter Sink oder Spiegel) bereit, aus der repair Schäden ersetzen kann.