Files
FEDEO/docs/minio-umstellung-pilot.md

256 lines
14 KiB
Markdown

# MinIO → SeaweedFS: betreuter Pilot auf einer Installer-Instanz
Stand: 28. September 2026. Dieser Ablauf ergänzt das
[Austauschkonzept](minio-austausch-konzept.md) um ausführbare Werkzeuge.
Er übernimmt den Speicher einer vorhandenen Installation, beispielsweise 3.3.0,
mit unveränderten Anwendungsimages und ohne Datenbankschemamigration.
**Vor dem ersten Wartungsfenster nur `load-images` und `plan` ausführen.**
Die Vorprüfung ermittelt die bislang unbekannten Größen und liefert eine
kompakte Ausgabe zum gemeinsamen Prüfen. Sie stoppt keine Anwendungscontainer.
Die fachliche Abnahme erfolgt zusätzlich auf der konkreten Instanz.
## Was der Pilot leistet und wo seine Grenze liegt
- Vorhandenes MinIO verwenden; kein Abruf von `minio/minio` oder `mc` erforderlich.
- SeaweedFS 4.47 mit dokumentierter FEDEO-Metadatenkorrektur; Offline-Images,
SHA-256-geprüftes Paket.
- Alle Objekte des einzigen FEDEO-Buckets übernehmen, inklusive Exporte und
Objekte ohne aktuellen Datenbankverweis. Schlüssel und Metadaten bleiben erhalten.
- Alle bekannten Schreiber anhalten, ihre automatischen Neustarts sperren,
PostgreSQL dumpen und MinIO kalt sichern. Die alten Daten bleiben erhalten.
- Kopie, vollständigen Inhaltsvergleich und tatsächlichen SeaweedFS-Restore in
ein frisches Verzeichnis prüfen. Unbekannte Zielobjekte werden nicht gelöscht.
- Den S3-Vertrag zusätzlich mit dem **tatsächlich installierten Backendimage**
ausführen. Dabei startet nur das Prüfprogramm, kein FEDEO-Backend.
- Erst nach diesen Prüfungen den Alias `minio` exklusiv an SeaweedFS vergeben
und die unveränderte Anwendung wieder starten.
**Der Pilot ist noch kein neuer Standardinstaller und kein reguläres
FEDEO-Release.** Der bisherige Anwendungs-Updater kennt nur MinIO. Seine Aufträge
bleiben nach der Umstellung bewusst über `recoveryRequired` gesperrt, bis ein
getesteter Provider-Adapter installiert wird. Diesen Zustand nicht mit dem alten
`resolve` oder durch Löschen der Statusdatei aufheben. Ein alter Installer oder
ein altes Release-Compose darf die umgestellte Installation nicht überschreiben.
FEDEO 3.3.0 kann im Systemstatus weiterhin den MinIO-spezifischen Health-Endpunkt
abfragen und dadurch den Dateispeicher als gestört anzeigen. Die tatsächliche
Funktionsprüfung erfolgt im Pilot über signierte S3-Operationen. Herstellerneutrale
Oberflächenchecks, eine Migrationskarte in der Oberfläche, automatische Updates
auf SeaweedFS und der Standardinstaller sind nachfolgende Arbeitspakete.
Wer diese Einschränkungen noch nicht im Betrieb tragen möchte, führt zunächst
nur die Vorprüfung durch und bleibt mit der Instanz auf MinIO.
### Warum das Pilotimage eine gezielte Korrektur enthält
Das unveränderte SeaweedFS 4.47 entfernt beim Speichern den expliziten MIME-Typ
`application/octet-stream`. Bei einem `.pdf`-Schlüssel liefern HEAD und GET
dadurch später `application/pdf`. Diese Abweichung wurde beim ersten betreuten
Versuch durch den strengen Metadatenvergleich erkannt; die Instanz wurde vor
Schreibfreigabe erfolgreich auf MinIO zurückgeführt.
`scripts/storage/Dockerfile.seaweedfs` baut deshalb die feste Herstellerrevision
`c5073360007d28385a33426a42ac3e4ec504c5a3` mit
`preserve-s3-content-type.patch` als `4.47-fedeo.1`. Die Korrektur bewahrt den
expliziten Typ für S3-Einträge; die Normalisierung gewöhnlicher Dateisystemeinträge
bleibt erhalten. Quellarchiv, Go-Buildimage und Hersteller-Basisimage sind per
SHA-256 festgelegt. Gezielte Go-Tests laufen beim Build; das Paket enthält den
Buildplan und Patch mit Prüfsummen. Der S3-Vertrag prüft den generischen MIME-Typ
zusätzlich mit HEAD, GET und dem Original-Backend-SDK.
Dies ist eine eigene Buildvariante. Bei einem späteren SeaweedFS-Update muss die
Korrektur weitergeführt oder durch einen nachgewiesenen Herstellerfix ersetzt
werden; das ungeänderte Herstellerimage ist für diese 1:1-Übernahme nicht freigegeben.
## Voraussetzungen, die der Plan prüft
Linux amd64, Python ab 3.10, lokaler Docker-Daemon, Docker Compose und `tar`/`du`.
Die Installation muss laufen und aus dem Installer stammen: lokale Verzeichnisse
`postgres/` und `minio/`, interner Endpunkt `http://minio:9000`, S3-Zugang wie beim
Installer aus `MINIO_ROOT_*`, keine externen Secret-Provider, keine zusätzlichen
MinIO-Ports, Datenmounts oder unbekannten Container im internen Netz.
Bekannte lokale Matrix-Dienste werden erhalten, während der Kopie angehalten und
mit ihren Daten kalt gesichert. Andere Zusatzdienste/Compose-Overrides blockieren
den Pilot und benötigen einen angepassten Plan.
Bereits durch ein früheres Update stillgelegte Matrix-Container dürfen weiterhin
zum Compose-Projekt gehören, obwohl sie nicht mehr in dessen Konfiguration stehen.
Der Pilot akzeptiert sie nur gestoppt und mit Neustartrichtlinie `no`, erhält ihre
Container und Images und nimmt sie nicht wieder in Compose auf. Ihre lokalen
Matrix-Bind-Verzeichnisse werden ebenfalls kalt gesichert. Die alten anonymen
Redis-/Coturn-Volumes bleiben unverändert an ihren stillgelegten Containern;
sie gehören nicht zum neuen Speicherdienst oder dessen Restore-Test.
Der S3-Prüfer blockiert zusätzliche Buckets, Versionierung einschließlich alter
Versionen/Delete-Marker, Object Lock, konfigurierte Serververschlüsselung,
Objekt-/Bucket-Tags, eigene Policies/ACLs, Lifecycle, Replikation, Benachrichtigungen,
CORS und offene Multipart-Uploads. Unklare S3-Fehler werden nicht als „nicht vorhanden“
gewertet. Datei-/Verzeichniskonflikte und normalisierungsgefährdete Schlüssel wie
`a//b`, `a/../b` und Verzeichnismarker blockieren ebenfalls.
Die bekannten lokalen MinIO-Metadaten werden zusätzlich geprüft (`xl-single`,
Metadatenformat 3). MinIO kann bei gleichzeitigem `a` und `a/b` einen Schlüssel
aus der S3-Liste verbergen, obwohl er per GET erreichbar bleibt. Bei gestopptem
MinIO muss deshalb die Menge lokaler `xl.meta`-Objektpfade exakt mit dem S3-Inventar
übereinstimmen. Andere Speicherformate oder Abweichungen blockieren die Umschaltung.
Getestete Pilotgrenzen: **200.000 Objekte, höchstens 1 GiB je Objekt**.
Die Kapazitätsabschätzung berücksichtigt Quellsicherung, neues und wiederhergestelltes
Ziel, Metadatenreserve pro Objekt, DB-Dump, Offline-Images, Spool und 5 GiB Reserve.
Nach dem Schreibstopp wird das Inventar erneut ermittelt. Es gibt keine Annahme,
dass eine unbekannte freie Kapazität ausreichend ist.
Externe Schreiber lassen sich nicht allein anhand von Docker erkennen. Vor
`migrate --writers-exclusive` muss feststehen, dass keine anderen Anwendungen,
direkten DB-/S3-Clients oder manuellen Compose-Aufträge parallel schreiben.
## Paket erstellen und auf den Host übertragen
Im Entwicklungscheckout mit Docker:
```sh
bash scripts/storage/build-pilot.sh
```
Ergebnis: `.release/storage-pilot.tar.gz` samt `.sha256` und entpacktem Paket.
Das Archiv enthält Hostprogramme, Dokumentation und beide benötigten Zielimages.
Es enthält keine Instanz-Zugangsdaten, keine Kundendateien und kein neues MinIO.
Die Build-Phase darf Images herunterladen; alle Schritte auf dem Zielhost starten
Container mit `--pull never`.
Archiv und Prüfsumme über den üblichen Administrationsweg auf den Docker-Host
kopieren. Dort die tatsächliche Prüfsumme mit der mitgelieferten vergleichen,
beispielsweise bei Ablage unter `/root`:
```sh
cd /root
sha256sum storage-pilot.tar.gz
tar -xzf storage-pilot.tar.gz
cd storage-pilot
sudo python3 pilot.py load-images
sudo python3 pilot.py plan --directory /opt/fedeo
```
Die Ausgabe von `plan` kann in den Supportdialog kopiert werden. Sie enthält
Phase, Anwendungsversion, Objektanzahl, Objektbytes und benötigten/verfügbaren
Platz; keine Passwörter oder Dateinamen. Falls der Installer in ein anderes
Verzeichnis installiert wurde, bei jedem Befehl denselben Pfad angeben.
Ein Plan verändert keine Quelldateien oder fachlichen Daten. Er legt geschützte
Migrationsdateien unter `.updates/storage-migration/` und einen lokalen Image-Tag
zur Aufbewahrung des Hilfsimages an. Die `storage/`-Datenablage entsteht erst beim
Migrationslauf. Das Paket bleibt bis zum Abschluss verfügbar; nicht mitten im
Auftrag neu bauen oder austauschen.
## Wartungsfenster: kopieren, prüfen, dann freigeben
Erst nach Prüfung der Planausgabe und Abstimmung des Wartungsfensters:
```sh
sudo python3 pilot.py migrate --directory /opt/fedeo --writers-exclusive
sudo python3 pilot.py status --directory /opt/fedeo
```
`migrate` endet bei `phase: verified`. Die Anwendung ist dann **weiter angehalten**.
Es hat noch keine fachlichen Schreibzugriffe auf SeaweedFS gegeben.
Der Lauf besitzt dieselbe exklusive Sperre wie der Host-Updater.
Die Umschaltung ist ein eigener Befehl:
```sh
sudo python3 pilot.py activate --directory /opt/fedeo
```
`activate` liest Quelle und Ziel nochmals vollständig, stoppt MinIO, entfernt
dessen internen Netzwerkanschluss, sichert SeaweedFS kalt und startet einen
separaten Restore-Container mit frisch entpackten Daten. Alle Objekt-Hashes und
Metadaten müssen dort stimmen. Danach erhält das aktive Ziel allein den Alias
`minio`, und die S3-Vertragstests laufen erneut, auch mit dem Original-Backend-SDK.
**Vor dem Start irgendeines fachlichen Schreibers** persistiert das Programm
`writesReleased: true`. Erst danach werden Backend/Hintergrunddienste und zuletzt
der öffentliche Proxy gestartet. Ein Fehler beim Neustart führt nicht zu einem
automatischen Rückfall auf den nun möglicherweise veralteten Quellspeicher.
Anschließend auf der Instanz prüfen: Anmeldung, bestehender Download, PDF-Vorschau,
neuer Upload mit erneutem Download, WebDAV, DATEV/SEPA und Mandantenexport/-import.
Bei zwei Testmandanten auch die unveränderten Zugriffsgrenzen kontrollieren.
Bereits ausgegebene S3-Links sind zusätzlich über ihren tatsächlichen Zugriffsweg
zu prüfen; ein interner Docker-Alias macht interne URLs nicht öffentlich erreichbar.
## Fehler und Wiederaufnahme
| Zustand | Vorgehen |
| --- | --- |
| `planned` | Instanz läuft noch; Wartungsfenster vorbereiten. |
| `freezing`, `backing_up`, `backed_up`, `copying`, `verifying`, `verified` | `migrate --writers-exclusive` setzt fort. Quelle, Schreibstopp, Backups und Inhalte werden erneut geprüft. |
| `cutover`, `restore_testing` | `activate` setzt die noch nicht freigegebene Umschaltung fort; alternativ Rückkehr. |
| `released` nach fehlgeschlagenem Start | `resume-start` versucht denselben Zielstand erneut. Keine einfache Rückkehr mehr. |
| `complete` | SeaweedFS aktiv; alte Daten und Backups weiter aufbewahren. |
| `rolled_back` | MinIO wieder aktiv. Vor einem neuen Versuch einen neuen betreuten Plan anlegen; bestehende Beweise nicht löschen. |
Vor der Schreibfreigabe ist die Rückkehr ausführbar:
```sh
sudo python3 pilot.py rollback --directory /opt/fedeo
```
Sie stoppt das Ziel, stellt Compose, den alten exklusiven Netzwerkanschluss und
die ursprünglichen Neustartrichtlinien wieder her und startet die vorher laufenden
Container. Quelldaten und DB bleiben unverändert. Nach `writesReleased: true`
verweigert das Programm diesen Befehl. Dann braucht eine Rückkehr eine gesonderte
Rückmigration einschließlich Löschungen oder die bewusste Wiederherstellung eines
zusammengehörigen Backups.
## Protokolle, Sicherungen und Betriebsdaten
`status` ist die kompakte Ausgabe ohne Geheimnisse. Geschützte Einzelheiten liegen
unter `/opt/fedeo/.updates/storage-migration/`:
- `state.json`: Phase, Container-/Image-Identitäten und dauerhafte Schreibgrenze.
- `commands.log`, `progress.jsonl`: Hostfehler und letzter Werkzeugfortschritt.
- `copy/inventory.json`, `copy/objects.jsonl`, `copy/verified.json`: vollständiges
Inventar und überprüfte Objekt-Hashes. Diese Dateien enthalten Dateinamen/Metadaten.
- `backup/database.dump`, `globals.sql`, `files.tar`, `images.tar`, `complete.json`:
zusammengehörige Quellsicherung mit Prüfsummen. Der DB-Dump wird mit `pg_restore --list`
geprüft; ein vollständiger fachlicher DB-Restore bleibt eine gesonderte DR-Prüfung.
- `backup/seaweedfs.tar`: kalt gesicherter neuer Speicher samt Konfiguration;
sein SHA-256 und erfolgreicher echter Restore werden im Zustand festgehalten.
Die neue persistente Ablage ist `storage/seaweedfs/`, die geschützte Konfiguration
`storage/config/`. SeaweedFS bindet Verwaltung, Filer und Volume-APIs an Loopback
im Container; im internen Docker-Netz liegt ausschließlich S3 auf Port 9000.
Ein Startwrapper verweigert fehlende oder veränderte Zugangskonfiguration.
Die Anwendungsidentität erhält nur Lese-, Schreib- und Listenrechte für ihren Bucket.
Für spätere Sicherungen **SeaweedFS anhalten und `storage/` vollständig sichern**,
einschließlich Filer-Metadaten, Masterzustand, Objektdaten, Konfiguration und passendem
Image. Die DB-Sicherung muss zum selben Schreibstopp gehören. Die Sicherungen auf
demselben Host anschließend auf das vorgesehene externe Backupziel übernehmen.
MinIO-Daten, alte Container, Test-Restores und Offline-Images werden vom Pilot
nicht automatisch gelöscht.
## Nachgewiesene Tests und ausstehende Freigaben
Der lokale S3-Test verwendet das offizielle MinIO-Release-Binary vom 7. September
2025 und SeaweedFS 4.47 mit der dokumentierten MIME-Korrektur. 1.005 Objekte / 1.073.752.750 Bytes,
einschließlich 1-GiB-Grenzdatei, Pagination, Sonderzeichen, Metadaten, leeren
Dateien, Streaming, 24-Stunden-Signaturen, fremdem Bucket und ungültigen Zugängen
werden geprüft. Beschädigte Zielobjekte werden erkannt und beim Fortsetzen
erneut kopiert; der kalte Restore wird vollständig gelesen und verglichen.
Testhost: Linux, 16 logische CPUs, rund 29 GiB RAM für Docker, lokaler NVMe-Speicher.
Die Laufzeit hängt von Objektanzahl, Datenmenge und Host ab.
Das Hilfs-Lockfile enthält den übernommenen vollständigen SDK-Abhängigkeitsbaum
des Backends, nicht nur dieselbe oberste Versionsnummer. Beim Pilot wird außerdem
das konkrete installierte Backendimage gegen das Ziel geprüft.
Die Host-Integrationstests verwenden echte Speicher- und PostgreSQL-Container,
aber künstliche Anwendungsprozesse. Rückkehr vor Schreibfreigabe sowie vollständige
Umschaltung mit Restore und gesperrter Rückkehr nach Schreibfreigabe wurden erfolgreich
durchlaufen. Die fachliche Abnahme von FEDEO auf der
konkreten Instanz, ein physischer Hostneustart während jeder Phase, das reguläre
Anwendungsupdate auf SeaweedFS und die vollständige Wiederherstellung auf einem
anderen Host sind damit noch nicht nachgewiesen. Deshalb bleibt dieser Stand ein
betreuter Pilot; die allgemeinen Freigabekriterien des Konzepts gelten weiter.