Sicherung und Wiederherstellung

Was du sichern musst, wie du sicherst und in welcher Reihenfolge du wiederherstellst

Zielgruppe: Technische Administration

Überblick

Die Daten von oPBWeb liegen an zwei Stellen, die zusammengehören: In der Datenbank stehen alle Metadaten, im Objektspeicher die Dateiinhalte. Die Datenbank verweist über SHA-256-Prüfsummen und Schlüssel auf Objekte im Speicher (blobs/…, artifacts/…). Eine Sicherung ist nur brauchbar, wenn beide Teile aus demselben Zeitpunkt stammen und die passenden Secrets dabei sind.

Was du sicherst

WasWoSichernHinweis
DatenbankVolume opbweb_mariadb-dataja, als DumpPakete, Versionen, Benutzer, Jobs, Protokoll, Snippets, Configserver und Depots, Einstellungen, verschlüsselte opsi-Passwörter
Objektspeicher-MetadatenVolume opbweb_garage-metaja, bei gestopptem StackBucket, Schlüssel, Objektverzeichnis
Objektspeicher-DatenVolume opbweb_garage-dataja, bei gestopptem StackInhalte der Paketdateien und gebaute Pakete
Secretssecrets/jaohne opsi_key_private.pem ist das opsi-Passwort verloren, ohne die übrigen Secrets passen Datenbank und Objektspeicher nicht mehr zusammen
Konfiguration.envja
Zertifikatecerts/ (inkl. certs/ldap/)jaTLS-Zertifikat und Schlüssel, LDAP-CA
RedisVolume opbweb_redis-dataneinnur Warteschlange und kurzlebiger Status
S3-ZugangsdatenVolume opbweb_garage-credentialsneingarage-init schreibt sie neu

Merke dir außerdem den Versionsstand von oPBWeb (Git-Commit oder Versionen aus der Statusleiste). Eine Datenbank lässt sich nur mit derselben oder einer neueren oPBWeb-Version weiterverwenden.

Sicherung erstellen

Damit Datenbank und Objektspeicher denselben Stand haben, stoppst du zuerst die Dienste, die Daten verändern, sicherst dann die Datenbank und anschließend bei gestopptem Stack den Objektspeicher.

  1. Prüfe unter Jobs, dass keine Jobs laufen oder warten.

  2. Lege ein geschütztes Sicherungsverzeichnis an:

    mkdir -p -m 700 backup
    
  3. Stoppe Frontend, Worker und API. Datenbank und Objektspeicher laufen weiter:

    docker stop opbweb-frontend opbweb-worker opbweb-api
    
  4. Sichere die Datenbank:

    docker exec opbweb-db sh -c 'mariadb-dump -uroot -p"$(cat /run/secrets/db_root_password)" --single-transaction opbweb' > backup/opbweb.sql
    

    Das Root-Passwort liest der Befehl im Container aus dem Docker-Secret; es erscheint nicht auf der Kommandozeile des Hosts.

  5. Stoppe den Stack:

    ./stop.sh
    
  6. Sichere die beiden Garage-Volumes (Beispiel mit einem Alpine-Hilfscontainer):

    docker run --rm -v opbweb_garage-meta:/v:ro -v "$PWD/backup":/b alpine tar czf /b/garage-meta.tgz -C /v .
    docker run --rm -v opbweb_garage-data:/v:ro -v "$PWD/backup":/b alpine tar czf /b/garage-data.tgz -C /v .
    
  7. Sichere Secrets, Konfiguration und Zertifikate:

    tar czf backup/config.tgz secrets .env certs
    
  8. Starte den Stack wieder:

    ./start.sh
    

Übertrage den Inhalt von backup/ anschließend auf dein Sicherungsziel. Die Ausfallzeit hängt vor allem von der Größe des Objektspeichers ab.

Wenn eine kurze Unterbrechung des ganzen Stacks ohnehin möglich ist, kannst du statt des Dumps auch das Volume opbweb_mariadb-data bei gestopptem Stack genauso wie die Garage-Volumes sichern. Dann gehören zur Datenbank zwingend die Passwörter aus secrets/db_password.txt und secrets/db_root_password.txt, die im Volume hinterlegt sind.

Wiederherstellen

Die Reihenfolge ist wichtig: erst Secrets und Konfiguration, dann der Objektspeicher, dann die Datenbank, zuletzt der Start.

  1. Stack stoppen.

    ./stop.sh
    
  2. Programmstand bereitstellen. Checke dieselbe oPBWeb-Version aus, die zur Sicherung gehört (oder eine neuere). Verwendest du Images aus einer Registry, stehen deren Versionen in der gesicherten .env (BACKEND_IMAGE usw.).

  3. Secrets, .env und Zertifikate zurückspielen. Verwende die originalen Dateien aus der Sicherung, nicht neu erzeugte:

    tar xzf backup/config.tgz
    chmod 750 secrets && chmod 444 secrets/*
    

    Die Dateien brauchen die Rechte 444, damit die Prozesse in den Containern sie lesen können; start.sh setzt die Rechte über init-secrets.sh ohnehin bei jedem Start.

  4. Objektspeicher zurückspielen. Entferne die vorhandenen Garage-Volumes einschließlich der S3-Zugangsdaten und spiele die Sicherung ein:

    docker volume rm opbweb_garage-meta opbweb_garage-data opbweb_garage-credentials
    docker volume create opbweb_garage-meta
    docker volume create opbweb_garage-data
    docker run --rm -v opbweb_garage-meta:/v -v "$PWD/backup":/b alpine tar xzf /b/garage-meta.tgz -C /v
    docker run --rm -v opbweb_garage-data:/v -v "$PWD/backup":/b alpine tar xzf /b/garage-data.tgz -C /v
    

    Das Volume garage-credentials musst du entfernen, damit garage-init die Zugangsdaten aus dem zurückgespielten Schlüssel neu schreibt. Bleibt ein altes Volume liegen, passen die Zugangsdaten nicht zum Objektspeicher. Im Log von garage-init erscheint beim nächsten Start „Credential files missing, writing from existing key…“.

  5. Datenbank zurückspielen. Entferne das Datenbank-Volume, starte nur die Datenbank und spiele den Dump ein:

    docker volume rm opbweb_mariadb-data
    docker compose up -d db
    docker compose ps db        # warten, bis der Status "healthy" lautet
    docker exec -i opbweb-db sh -c 'mariadb -uroot -p"$(cat /run/secrets/db_root_password)" opbweb' < backup/opbweb.sql
    

    MariaDB legt beim ersten Start des leeren Volumes die Datenbank opbweb und den Anwendungsbenutzer mit den Passwörtern aus secrets/ an. Hast du das Volume statt eines Dumps gesichert, spielst du es wie die Garage-Volumes zurück.

  6. Stack starten.

    ./start.sh
    

    Die API führt fehlende Migrationen aus, falls der Programmstand neuer ist als die Sicherung. Ein erstes Administrator-Konto legt sie nicht an, weil die Benutzertabelle aus der Sicherung gefüllt ist.

  7. Prüfen.

    • Systemstatus: alle Dienste OK. Als Administrator prüfst du unter Objektspeicher, dass keine fehlenden Blobs gemeldet werden; fehlende Blobs deuten auf Datenbank und Objektspeicher aus unterschiedlichen Zeitpunkten hin.
    • Depots → Configserver: für jeden Configserver Verbindung testen. Schlägt die Anmeldung fehl, passt opsi_key_private.pem nicht zur Datenbank; trage dann das Passwort des technischen Benutzers neu ein.
    • Öffne ein Paket und lade eine Datei bzw. ein gebautes Paket herunter.

Jobs, die zum Zeitpunkt der Sicherung warteten oder liefen, setzt oPBWeb nach der Wiederherstellung nicht fort. Starte sie bei Bedarf neu.

Konsistenz

SituationFolge
Datenbank älter als Objektspeicherüberzählige Objekte; harmlos, Bereinigen … im Systemstatus entfernt sie
Datenbank neuer als Objektspeicherfehlende Blobs oder Build-Ergebnisse; betroffene Dateien lassen sich nicht öffnen, betroffene Versionen müssen neu gebaut werden
neues Schlüsselpaar opsi_key_*.pemopsi-Passwort nicht lesbar; neu eintragen
neue db_password.txt bzw. db_root_password.txt zu einem gesicherten Datenbank-VolumeAPI und Worker erreichen die Datenbank nicht
altes Volume garage-credentials zu zurückgespieltem ObjektspeicherZugriff auf den Objektspeicher scheitert; Volume entfernen und neu starten

Bei regelmäßigen Sicherungen hilft eine feste Reihenfolge in einem Skript, das alle Schritte des Abschnitts Sicherung erstellen nacheinander ausführt.