Files
FEDEO/docs/selfhost-updates.md

33 KiB
Raw Permalink Blame History

Vollständige Selfhost-Updates

scripts/selfhost-update.py ist der gemeinsame Update-Ablauf für die Kommandozeile und den optionalen Host-Dienst fedeo-updater.service. Beide laufen auf dem Docker-Host außerhalb der FEDEO-Container und verwenden dieselbe exklusive Sperre. Das Backend verbindet diese lokale Schnittstelle mit dem Update-Bereich unter Administration → Systemstatus.

Voraussetzungen und Umfang

  • Linux/amd64, Python ab 3.10, Docker Compose ab 2.24, tar und du.
  • Bestehendes Betriebsverzeichnis, standardmäßig /opt/fedeo, mit .env und docker-compose.yml; kein Git-Checkout.
  • Standard-Stack mit traefik, db, minio, createbuckets, backend, frontend und node-exporter. PostgreSQL und MinIO verwenden die lokalen Verzeichnisse postgres/ und minio/. Nach geprüfter Pilotübernahme ersetzt objectstore (SeaweedFS) die beiden MinIO-Dienste; dessen Daten liegen unter storage/.
  • Als root auf dem Server ausführen: Docker-Zugriff und Leserechte für die Daten- und Zertifikatsverzeichnisse werden benötigt. Ein entfernter Docker-Daemon wird abgewiesen.
  • Die öffentliche HTTPS-Adresse muss vom Host erreichbar sein und ein gültiges Zertifikat haben.
  • Eine Wartungsunterbrechung für alle Mandanten einplanen. Vor dem Backup werden alle laufenden Dienste außer PostgreSQL angehalten, auch der öffentliche Proxy und alle im Backend laufenden Hintergrundaufgaben. Eine separate Wartungsseite folgt mit der späteren Oberflächenintegration.

Der Updater verweigert externe Datenbanken, externen S3-/Seafile-Speicher, zusätzliche Dienste, Compose-Profile, geänderte Datenpfade und PostgreSQL-Imagewechsel. Dafür braucht es zunächst passende Backup-/Migrationsadapter. Eigene Einstellungen innerhalb der unterstützten Dienste können in docker-compose.override.yml oder docker-compose.override.yaml bleiben; der Updater verwendet diese Datei bei jedem Compose-Aufruf. Änderungen an dieser Override-Datei werden nicht überschrieben.

Eine gezielte Ausnahme ist die Stilllegung des entfernten alten Matrix-Stacks: matrix-db, matrix-synapse, matrix-redis, matrix-element, matrix-livekit, matrix-rtc-jwt, matrix-turn und matrix-well-known dürfen in der bestehenden Konfiguration vorkommen. Die Zielkonfiguration muss ausschließlich die FEDEO-Dienste des jeweiligen Speicherproviders enthalten, auch nach Zusammenführung mit einer Override-Datei. Matrix wird nicht in den neuen Stack übernommen. Bereits stillgelegte Matrix-Container bleiben erhalten und ihre lokalen Bind-Verzeichnisse werden weiter gesichert. Andere Zusatzdienste bleiben gesperrt; die Fehlermeldung nennt die konkreten Abweichungen. Ein Abbruch mit mutationStarted: false und recoveryRequired: false benötigt keine Wiederherstellung und keinen resolve-Aufruf.

Für diesen Übergang müssen die Matrix-Daten lokal unter matrix/ liegen, insbesondere matrix/postgres und matrix/synapse; symbolische Links, andere konfigurierte Datenpfade, benannte Volumes und spezielle Compose-Konfigurationen benötigen eine manuelle Stilllegung. Die tatsächlichen Bind-Mounts der alten Container müssen zur Compose-Datei passen. Der Plan nennt retiredServices und retainedDataPaths und berücksichtigt den zusätzlichen Backup-Platz. Alle Matrix-Container werden vor dem Backup gestoppt. Das komplette lokale matrix/-Verzeichnis wird bei gestoppter Matrix-Datenbank in files.tar gesichert. Erst nach erfolgreichem Backup setzt der Updater die Neustartrichtlinie der alten Matrix-Container auf no, damit sie auch nach einem Host-Neustart stillgelegt bleiben. Er löscht weder diese Container noch ihre Daten oder Volumes. Image-seitig angelegte anonyme Volumes und schreibbare Container-Schichten bleiben an den alten Containern erhalten; sie sind nicht Bestandteil von files.tar. Die alten Container daher für die Wiederherstellung behalten und nicht mit --remove-orphans oder einem Docker-Prune entfernen.

Die Stilllegung vor der Dateisicherung entspricht den Anforderungen an ein PostgreSQL-Dateisystem-Backup; die Container-Richtlinie wird mit Docker update --restart geändert.

Die Zielversion muss die Backend-/Frontend-Healthchecks enthalten; bei weiterhin aktivem MinIO zusätzlich feste MinIO-/mc-Digests. Ältere Releases bleiben über den in docs/releases.md beschriebenen manuellen Ablauf installierbar. Ein Versionswechsel des Betriebssystems oder der Docker Engine gehört nicht zu diesem Ablauf.

Bereits auf SeaweedFS umgestellte Instanzen

Speicherumstellung und Anwendungsupdate bleiben getrennte Wartungsschritte. Für weitere Installer-Instanzen zuerst den Migrationsablauf mit Kopie, vollständiger Prüfung und echtem Restore durchführen. Er verwendet die vorhandenen MinIO-Images und benötigt keinen funktionierenden MinIO-Download. Der normale apply-Befehl startet keine verdeckte Speichermigration. Der neue Standardinstaller und Setup-Assistent erkennen vorbereitete bzw. durchgeführte Speicherumstellungen und verweigern dort das Überschreiben der Konfiguration oder ein pauschales Entfernen des Stacks. Alte Skriptstände besitzen diesen Schutz nicht und dürfen auf umgestellten Instanzen nicht mehr ausgeführt werden.

Nach Installation der vier zusammengehörigen neuen Host-Dienstdateien übernimmt der neue Updater einen vollständig abgeschlossenen Pilot:

sudo python3 /usr/local/lib/fedeo-updater/selfhost-update.py adopt-storage --directory /opt/fedeo
sudo python3 /usr/local/lib/fedeo-updater/selfhost-update.py check --directory /opt/fedeo

Das neue Pilotpaket verbindet Dienstinstallation und Übernahme als pilot.py adopt-updater. Die Übernahme verändert keine Anwendungsimages und stoppt keine FEDEO-Dienste. Sie prüft Migrations-/Restore-Nachweise, Originalzustand der Anwendung, aktiven Speicher und S3-Lesezugriff und schreibt erst dann .updates/storage-provider.json. Die alte Sperre wird als letzter Schritt freigegeben. Bei Abbruch kann derselbe Befehl wiederholt werden. resolve verweigert ausdrücklich die Freigabe einer Speichermigration. Bei Installation aus dem Pilotpaket die CLI unter /usr/local/lib/fedeo-updater/ verwenden. Eventuell noch vorhandene ältere Kopien unter /opt/fedeo/scripts/ werden durch die Dienstinstallation nicht ersetzt.

Weitere Anwendungsupdates erzeugen das Release-Compose mit dem übernommenen SeaweedFS-Dienst. Image, Mounts, Startkonfiguration, interner Alias und Zugangsdaten bleiben erhalten; MinIO und mc werden weder geladen noch gestartet. Das bei der Pilotmigration festgehaltene PostgreSQL-Image bleibt ebenfalls erhalten. Eine geänderte PostgreSQL-Referenz im Release blockiert die Anwendung bis zur separaten Datenbankmigration. Ein Anwendungsupdate aktualisiert nicht die SeaweedFS-Version.

Das Backup enthält den Datenbankdump und die bei gestopptem SeaweedFS gesicherte vollständige Ablage storage/ in files.tar, zusätzlich storage-image.tar und config/.updates/storage-provider.json. Der Platzbedarf berücksichtigt das Image. Vor den SQL-Migrationen wird das neue Backendimage mit seinem tatsächlichen SDK gegen S3 geprüft (PUT/HEAD/GET/DELETE, Streaming, MIME, 24-Stunden-Signatur und anonymer Zugriffsschutz). Ein unterbrochener Test protokolliert seinen eindeutigen Prüfschlüssel; resolve bereinigt ausschließlich diesen mit passender Prüfmetadatenmarkierung, nachdem zurückgebliebene Prüfcontainer entfernt wurden und die Anwendung wieder erreichbar ist. Unbekannte Dateien werden nicht gelöscht.

Die Oberfläche neuer FEDEO-Releases zeigt den erkannten Speicher im Updateplan und unterscheidet die ausstehende Speicherübergabe von einem fehlgeschlagenen Anwendungsupdate. Ältere Backends können den neuen Host-Dienst weiterhin nutzen; zusätzliche Planinformationen werden dort ausgeblendet. Nach einem Apprelease mit dem neuen Systemstatus ersetzt ein authentifizierter S3-Bucket-Check den MinIO-spezifischen Health-Endpunkt.

Bereitstellung

Neue versionierte Installer laden das Skript und diese Anleitung bereits ins Betriebsverzeichnis und berücksichtigen Python 3 bei den Basispaketen. Bestehende Installationen können selfhost-update.py und SELFHOST-UPDATES.md aus den Assets eines entsprechenden veröffentlichten Releases übernehmen. Zuerst mit dessen SHA256SUMS prüfen, anschließend das Skript unter /opt/fedeo/scripts/selfhost-update.py ablegen. Für diese erstmalige Bereitstellung ist noch ein Serverzugriff erforderlich.

Ein bereits heruntergeladener Updater aus Release 3.1.0 enthält die Matrix-Stilllegung noch nicht. Dafür das Hostskript durch den korrigierten Stand aus einem neueren Release oder dem geprüften Repository-Commit ersetzen. Dieser kann weiterhin 3.1.0 als Zielrelease verwenden; dessen veröffentlichte Assets werden nicht verändert. Ein erneuter Download des alten 3.1.0-Updater-Assets liefert weiterhin den alten Stand. Der Updater ersetzt sich beim Anwenden nicht selbst.

Downloads erfolgen ausschließlich vom konfigurierten FEDEO-Repository über HTTPS. Die Dateiprüfsummen werden gegen SHA256SUMS, das Manifest gegen den Git-Tag geprüft. Die Prüfsummen sind keine unabhängige Signatur; das Vertrauen liegt beim Gitea-Server und dessen Release-Veröffentlichung. Falls das Repository privat ist, FEDEO_RELEASE_TOKEN mit Leserechten nur für den Aufruf setzen. Registry-Anmeldung bei Bedarf vorher über docker login git.federspiel.tech im Konto des Updaters durchführen. Der Updater speichert den Release-Token nicht in Statusdateien und gibt ihn bei Weiterleitungen an andere Hosts nicht weiter.

Prüfen, anwenden und Status lesen

Neueste stabile Version suchen oder eine bestimmte Version prüfen:

sudo python3 /opt/fedeo/scripts/selfhost-update.py check
sudo python3 /opt/fedeo/scripts/selfhost-update.py check --version 3.1.0

3.1.0 ist ein Beispiel und muss durch einen tatsächlich veröffentlichten Zielrelease ersetzt werden. Ein anderes Betriebsverzeichnis wird mit --directory /pfad/zur/instanz angegeben.

Die Prüfung lädt die Betriebsdateien und erstellt einen Plan einschließlich compose.diff und Release Notes unter /opt/fedeo/.updates/<Auftrag>/. Sie verändert die laufende Installation nicht und lädt noch keine Docker-Images. Die JSON-Ausgabe nennt Zielversion, Commit, betroffene Dienste, geschätzten Backup-Platz und die Pfade der Vorschau. updateAvailable: false bedeutet, dass die geprüfte Version nicht neuer als die installierte ist. Unveröffentlichte Entwürfe und Vorabversionen werden ignoriert.

Beim ersten Update kennt der Updater die Herkunft der vorhandenen Compose-Datei noch nicht. Die erzeugte compose.diff prüfen und eigene Anpassungen in die Override-Datei übertragen. Dann den Austausch ausdrücklich akzeptieren:

sudo python3 /opt/fedeo/scripts/selfhost-update.py apply --version 3.1.0 --accept-compose-replacement

Für spätere Updates unveränderter, vom Updater verwalteter Compose-Dateien:

sudo python3 /opt/fedeo/scripts/selfhost-update.py apply --version 3.2.0
sudo python3 /opt/fedeo/scripts/selfhost-update.py status

Eine explizite Zielversion ist beim Anwenden erforderlich. apply prüft die Release-Dateien und die tatsächliche Installation nochmals. Beim Anwenden gleicher oder älterer stabiler Zielversionen wird abgebrochen. Änderungen an .env, Basis-Compose oder der Override-Datei während des Downloads führen ebenfalls vor der Wartungsphase zum Abbruch.

Direkte CLI-Aufrufe in einer persistenten Terminalsitzung ausführen. Alternativ übernimmt der folgende Host-Dienst die von der Verbindung unabhängige Ausführung. Ein Neustart des FEDEO-Stacks beendet diese Host-Prozesse nicht. Ein erzwungener Host-Neustart kann sie unterbrechen; beim normalen Dienst-Stop wartet der Dienst auf den laufenden Auftrag.

Host-Dienst installieren

Benötigt zusätzlich einen Linux-Host mit systemd und Docker als docker.service. Die Dateien selfhost-update.py, selfhost-update-service.py, selfhost-update-service-install.sh und fedeo-updater.service müssen aus demselben geprüften Stand im selben Verzeichnis liegen, beispielsweise /opt/fedeo/scripts/. Neuere Installer laden sie dorthin; neuere Releases enthalten alle vier Dateien samt Prüfsummen. Release 3.1.0 enthält den Dienst noch nicht. Zum Nachrüsten können die vier Dateien aus dem geprüften Repository-Commit kopiert werden, ohne die laufende FEDEO-Version zu ändern.

sudo bash /opt/fedeo/scripts/selfhost-update-service-install.sh --directory /opt/fedeo
sudo systemctl status fedeo-updater.service
sudo curl --unix-socket /run/fedeo-updater/control.sock http://localhost/v1/status

Der Installer legt die Python-Module root-eigen unter /usr/local/lib/fedeo-updater/ ab, installiert die systemd-Unit und aktiviert den Dienst beim Systemstart. Bestehende FEDEO-Container werden durch die Dienstinstallation nicht neu gestartet. Bei einer erneuten Dienstinstallation wartet ein normales systemctl stop einen laufenden Auftrag ab; ein aktiver CLI-Updater blockiert den Dateiaustausch. Die Unit kann vorab ohne Installation angezeigt werden:

bash /opt/fedeo/scripts/selfhost-update-service-install.sh --directory /opt/fedeo --print-unit

Der Dienst läuft wegen Docker und der Backups als root. Seine HTTP-Schnittstelle lauscht ausschließlich auf /run/fedeo-updater/control.sock, nicht auf einem TCP-Port. Verzeichnis und Socket gehören root:fedeo-updater mit 0750 bzw. 0660. Zugriff auf diese Gruppe erlaubt instanzweite Updates; nur vertrauenswürdigen Host-Prozessen Zugriff geben. Die Selfhost-Compose-Datei bindet /run/fedeo-updater schreibgeschützt unter demselben Pfad im Backend ein. Das Verzeichnis statt der einzelnen Socket-Datei bleibt auch bei einem Socket-Austausch durch Dienstneustarts nutzbar. Die Standard-Backend-Container laufen als root; bei einer eigenen unprivilegierten Konfiguration benötigt der Backend-Prozess zusätzlich die Host-GID von fedeo-updater. Es wird kein Docker-Socket in Backend oder Frontend eingebunden. Ohne installierten Dienst bleibt die Anwendung nutzbar; der Update-Bereich meldet den Dienst als nicht erreichbar.

Registry-Anmeldung bei privaten Images als root durchführen. Für private Releases kann /etc/fedeo/updater.env root-lesbar (0600) FEDEO_RELEASE_TOKEN=... enthalten; danach den Dienst neu starten. Dieser Token wird nicht an API-Clients ausgegeben. Die Unit verwendet /root als Home-Verzeichnis für die Docker-Anmeldung. Der Dienst ersetzt sich bei einem FEDEO-Update nicht selbst; neue Dienstdateien zusammen bereitstellen und den Dienstinstaller erneut ausführen.

Updates im Frontend und einmaliger Übergang

Systemadministratoren öffnen Administration → Systemstatus → FEDEO-Updates. „Nach Updates suchen“ prüft den neuesten stabilen Release. Die Oberfläche zeigt den laufenden Backend-Stand, die geprüfte Zielversion, den Commit, den geschätzten Backup-Platz und gegebenenfalls stillzulegende Matrix-Dienste. „Update auf … installieren“ öffnet die Bestätigung für die Wartungsunterbrechung aller Mandanten. Erst „Jetzt installieren“ nach Bestätigung startet den Auftrag.

Der Fortschritt wird automatisch abgefragt. Während des Stack-Neustarts ist die Verbindung vorübergehend unterbrochen; der Host arbeitet weiter. Nach Erfolg lädt „Neue Version laden“ die Oberfläche neu. Auftrags-IDs bleiben im Browser gespeichert und der Dienst liefert auch nach seinem Neustart den letzten Auftrag. Geht die Startantwort verloren, fragt die Oberfläche zuerst dieselbe ID ab. „Auftrag erneut senden“ verwendet dieselbe ID und denselben Inhalt; es wird kein zweites Update gestartet. Nach einer erneuten Anmeldung die Systemstatus-Seite wieder öffnen. Auch ohne Browser-Speicher lässt sich der aktuelle Auftrag über den Dienststatus verfolgen.

Für eine bestehende Instanz auf 3.1.0 ist noch ein einmaliger Übergang nötig, nachdem ein Release mit diesem Update-Bereich veröffentlicht wurde:

  1. Die vier zusammengehörigen Host-Dateien aus dessen geprüften Release-Assets nach /opt/fedeo/scripts/ übernehmen: selfhost-update.py, selfhost-update-service.py, selfhost-update-service-install.sh, fedeo-updater.service.

  2. Den Dienstinstaller erneut ausführen, damit auch /usr/local/lib/fedeo-updater/ den aktuellen Stand erhält.

  3. Einmal per CLI auf diesen Release aktualisieren. X.Y.Z durch die veröffentlichte Version ersetzen:

    sudo bash /opt/fedeo/scripts/selfhost-update-service-install.sh --directory /opt/fedeo
    sudo python3 /opt/fedeo/scripts/selfhost-update.py check --version X.Y.Z
    sudo python3 /opt/fedeo/scripts/selfhost-update.py apply --version X.Y.Z
    

Der aktuelle Updater erlaubt dabei gezielt das zusätzliche, schreibgeschützte Standard-Socket-Verzeichnis am Backend. Änderungen an bestehenden Daten-Mounts sowie abweichende oder schreibbare neue Kontroll-Mounts bleiben gesperrt. Ältere Updater besitzen diese Übergangsregel noch nicht. Ein bereits erfolgreich verwalteter Compose-Stand benötigt keine erneute --accept-compose-replacement-Freigabe. Falls der Prüfplan sie verlangt, zunächst die Compose-Differenz auf dem Host prüfen wie oben beschrieben.

Danach laufen weitere Anwendungs-Releases einschließlich Compose und Migrationen über den Button. Änderungen am Host-Dienst selbst benötigen weiterhin die gemeinsame Aktualisierung der Host-Dateien und den Dienstinstaller.

Die Backend-Routen /api/admin/updates/status, /api/admin/updates/requests/:id, /api/admin/updates/requests/:id/logs, /api/admin/updates/check und /api/admin/updates/apply prüfen bei jeder Anfrage die aktuellen globalen Administratorrechte aus der Datenbank. Mandantenadministratoren haben keinen Zugriff. Startanfragen benötigen zusätzlich den bereits von der Authentifizierung geprüften Bearer-JWT; Cookie-Anmeldung allein kann keine Hostaktion auslösen. Das Backend verwendet ausschließlich den festen Unix-Socket, begrenzt Antwortgröße und Wartezeit und liefert nur erlaubte Status-/Planfelder und bereinigte Protokollauszüge aus. CLI-Wiederherstellung, Übernahme fremder Compose-Dateien, Shell-Befehle und frei wählbare Download-Adressen bleiben auf dem Host.

Update-Protokoll in der Oberfläche

Unter FEDEO-Updates → Update-Protokoll anzeigen sehen Systemadministratoren die Fehlerdetails des Host-Dienstes, den Update-Verlauf und die Werkzeugausgaben (beispielsweise Docker-Pull- oder Migrationsfehler). Bei fehlgeschlagenen oder unterbrochenen Aufträgen öffnet sich die Ansicht automatisch. Solange sie geöffnet ist, wird sie zusammen mit dem Auftragsstatus aktualisiert; „Protokoll aktualisieren“ fragt sie zusätzlich sofort ab. Während der Wartungsunterbrechung bleibt die letzte geladene Ausgabe sichtbar.

Pro Quelle werden höchstens die letzten 6000 UTF-8-Bytes angezeigt; gekürzte Ausgaben sind markiert. Die Bereinigung erfolgt auf dem Host vor der Übertragung: erkannte Kennwörter, Tokens, Authentifizierungsheader und URL-Zugangsdaten sowie bekannte geheime Werte aus der Umgebung und den aktuellen/gesicherten Konfigurationsdateien werden ersetzt. Die Originalprotokolle bleiben unverändert geschützt auf dem Host. Nicht als Zugangsdaten erkennbare Anwendungsdaten können weiterhin enthalten sein.

Bestehende Installationen benötigen für diese Ansicht auch einen aktualisierten Host-Dienst, zusätzlich zu Backend und Frontend. Die vier zusammengehörigen Host-Dateien aus einem geprüften Stand bereitstellen und selfhost-update-service-install.sh erneut ausführen, wie unter „Host-Dienst installieren“ beschrieben. Ein Anwendungsupdate allein ersetzt den Host-Dienst nicht. Die Oberfläche erkennt ältere Dienste und zeigt dafür einen konkreten Hinweis. Bereits vorhandene Aufträge bleiben lesbar; ältere Protokolle werden anhand der gespeicherten Auftrags-ID zugeordnet. Nach Aktualisierung des Host-Dienstes lässt sich auch vor einem Anwendungsupdate direkt GET /v1/requests/<requestId>/logs über den Unix-Socket verwenden.

Lokale Dienst-API

Alle Antworten sind JSON mit Cache-Control: no-store. Mutationen benötigen Content-Type: application/json, höchstens 4096 Byte und eine vom Client erzeugte requestId (8–80 Zeichen, Buchstaben/Ziffern/Unterstrich/Bindestrich). Für jede neue Aktion eine neue ID verwenden; bei einem Verbindungsfehler dieselbe ID und denselben Inhalt wiederholen. Das liefert denselben Auftrag statt eines zweiten Updates, auch nach einem Dienstneustart. Eine andere Anfrage mit derselben ID wird mit 409 REQUEST_CONFLICT abgelehnt.

Aufruf Bedeutung
GET /v1/status Installierter Stand, Zustand der Update-Engine und aktueller Dienstauftrag
POST /v1/check Asynchrone Prüfung; requestId, optional version ohne v
GET /v1/requests/<requestId> Auftrag, bereinigter Prüfplan und aktueller Fortschritt
GET /v1/requests/<requestId>/logs Bereinigte, begrenzte Auszüge aus Dienst-, Ablauf- und Werkzeugprotokoll; nur für diesen Auftrag
POST /v1/apply Asynchrones Update; requestId, feste version und erfolgreiche checkRequestId

Beispiel für eine Prüfung des neuesten Releases:

CHECK_ID="$(python3 -c 'import uuid; print(uuid.uuid4())')"
curl --unix-socket /run/fedeo-updater/control.sock \
  -H 'Content-Type: application/json' \
  -d "{\"requestId\":\"$CHECK_ID\"}" http://localhost/v1/check

curl --unix-socket /run/fedeo-updater/control.sock \
  "http://localhost/v1/requests/$CHECK_ID"

Neue Aufträge antworten sofort mit 202. queued und running bedeuten, dass die Arbeit noch läuft; checked bedeutet erfolgreiche Prüfung und up_to_date, dass keine neuere Version vorliegt. Der bereinigte Plan enthält Version, Commit, Platzbedarf und stillzulegende Dienste. Vollständige Release Notes und Compose-Diff bleiben auf dem Host, da insbesondere bestehende Compose-Dateien Geheimnisse enthalten können.

Nach checked, updateAvailable: true und Prüfung des Plans eine konkrete Zielversion einsetzen:

APPLY_ID="$(python3 -c 'import uuid; print(uuid.uuid4())')"
TARGET_VERSION=X.Y.Z
curl --unix-socket /run/fedeo-updater/control.sock \
  -H 'Content-Type: application/json' \
  -d "{\"requestId\":\"$APPLY_ID\",\"version\":\"$TARGET_VERSION\",\"checkRequestId\":\"$CHECK_ID\"}" \
  http://localhost/v1/apply

curl --unix-socket /run/fedeo-updater/control.sock \
  "http://localhost/v1/requests/$APPLY_ID"

succeeded bestätigt den Abschluss. Der Dienst bindet den Start an genau den geprüften Release und die geprüften Konfigurationsdateien. Bei zwischenzeitlichen Änderungen bricht er mit PLAN_CHANGED vor Image-Pull/Wartungsphase ab. requiresComposeAdoption: true benötigt zunächst eine manuell geprüfte Übernahme über die CLI; die API bietet dafür keinen Freigabeschalter. Ebenso bleiben resolve, freie Shell-Befehle, alternative Betriebsverzeichnisse und Download-Adressen außerhalb der API. Ein zweiter Auftrag bzw. ein laufender CLI-Updater führt zu 409 BUSY, ein offener Wiederherstellungsfall zu 409 RECOVERY_REQUIRED.

Aufträge liegen dauerhaft und root-lesbar unter .updates/service/. Nach einem harten Dienstabbruch werden offene Aufträge als interrupted markiert und nicht automatisch erneut gestartet. Bei normalem Stop/Restart nimmt der Dienst keine neue Arbeit mehr an und lässt den aktiven Auftrag fertiglaufen (KillMode=mixed, TimeoutStopSec=infinity). Auch ein reguläres Herunterfahren des Hosts kann dadurch bis zum Auftragsende warten. Nach erzwungenem Abbruch oder Host-Neustart den Status prüfen; unterbrochene Updates folgen den bestehenden Wiederherstellungsprüfungen. Auftragsspezifische Fehlerdetails stehen in .updates/service/<requestId>.log, Werkzeugfehler weiterhin im geschützten commands.log des Engine-Auftrags. Über die API werden nur feste Fehlermeldungen und erlaubte Statusfelder ausgegeben, keine Rohlogs, Konfiguration, Dateipfade oder Prüffingerprints.

Ablauf und Speicherung

  1. Exklusive Host-Sperre erwerben; offene Wiederherstellungsfälle blockieren neue Updates.
  2. Release samt Prüfsummen laden, Manifest/Commit prüfen und die FEDEO-Images auf die exakten Digests setzen.
  3. Aktuelle und neue Compose-Konfiguration mit Docker Compose validieren. Projektname, Container-Identitäten, Mounts, Netzwerke und Zugangsdaten erhalten. Die Shell-Umgebung überschreibt dabei keine Werte aus der Instanz-.env.
  4. Speicherplatz prüfen: mindestens 5 GiB frei am Docker-Datenverzeichnis vor dem Pull sowie geschätzte Backup-Größe plus Reserve im Betriebsverzeichnis. Images mit exakt gepinntem SHA-256-Digest nur laden, wenn sie lokal fehlen (pull --policy missing); vorhandene Tags ohne passenden Digest reichen dafür nicht aus. Bewegliche Infrastruktur-Tags weiterhin aktualisieren (pull --policy always). Ein fehlendes, nicht herunterladbares Image beendet den Auftrag vor der Wartung. Backup-Platz erneut prüfen. Während der anschließenden Infrastrukturstarts und Migrationen erfolgt kein weiterer Pull (up/run --pull never), auch nicht bei einer abweichenden Pull-Policy in einer Override-Datei.
  5. Schreibende Dienste und Proxy anhalten. PostgreSQL bleibt für pg_dump aktiv.
  6. Konfiguration, Container-Metadaten, PostgreSQL-Dump im Custom-Format, globale PostgreSQL-Rollen, den gestoppten Dateispeicher und Zertifikate sichern. Bei SeaweedFS gehören dessen vollständige Ablage, Konfiguration und Image dazu. Dump und TAR auf Lesbarkeit prüfen und SHA-256-Prüfsummen schreiben. backup/complete.json markiert ein vollständig geschriebenes Backup; ein Restore-Probelauf auf einer getrennten Instanz wird dadurch nicht ersetzt. Beim Übergang vom alten Matrix-Stack enthält das TAR zusätzlich matrix/. Container-Metadaten enthalten die ursprünglichen Image-IDs, Mounts und Neustartrichtlinien; complete.json nennt die stillgelegten Dienste und erhaltenen Container. Vor dem Dateiaustausch wird deren automatischer Neustart deaktiviert. Das Zielrelease enthält keine Matrix-Dienste und keine Backend-Abhängigkeit auf Synapse mehr.
  7. Compose-Datei und .env einzeln atomar ersetzen. In .env wird ausschließlich FEDEO_VERSION verändert; .env.example und Setup-Skript werden erneuert. Den laufenden Updater ersetzt dieser Vorgang nicht.
  8. Infrastruktur starten, Bucket-Einrichtung ausführen und Migrationen explizit in einem benannten Einmalcontainer starten. Beim anschließenden regulären Backend-Start läuft dessen bestehende Migrationsprüfung nochmals; bereits angewendete Migrationen werden dabei übersprungen.
  9. Stack mit up --wait starten. Backend-/Frontend-Image-IDs und Healthchecks sowie öffentlich gemeldete Version und Commit prüfen. Erst dann den Release als installiert speichern.

Status und Phasen werden atomar in .updates/status.json und pro Auftrag in status.json gespeichert. events.jsonl enthält den Verlauf, commands.log Fehlermeldungen der Werkzeuge. Das Verzeichnis hat Modus 0700; Status- und Konfigurationsdateien werden mit 0600 angelegt. Backups und Werkzeugausgaben enthalten vertrauliche Daten und dürfen nicht ungefiltert an eine Oberfläche ausgeliefert werden. Backups werden nicht automatisch gelöscht.

Fehler und Wiederherstellung

Bei einer nicht erreichbaren Registry können bereits lokal vorhandene, exakt passende Digest-Images weiterverwendet werden. Das hilft beispielsweise bei einem 401 Unauthorized der MinIO-Registry, wenn sowohl MinIO als auch mc mit den Ziel-Digests bereits auf diesem Host liegen. Der Host-Updater muss diese Pull-Logik bereits enthalten; bestehende Dienstinstallationen nach Austausch des Hostskripts mit dem Dienstinstaller aktualisieren. Veröffentlichte Release-Assets werden nicht nachträglich verändert. Für Instanzen ohne diese Images bleibt eine geprüfte Bezugsquelle notwendig. Der lokale Cache ersetzt weder Sicherheitsupdates noch eine dauerhafte Versorgung mit gepflegten Images.

  • Download, Konfiguration oder Pull fehlgeschlagen: Der laufende Stack bleibt bestehen.
  • Backup oder Stop fehlgeschlagen: Der Updater versucht, die zuvor laufenden Container wieder zu starten. Gelingt das nicht, bleibt der Wiederherstellungsstatus gesetzt.
  • Ab Austausch der Dateien/Infrastruktur: Keine automatische Rückkehr zu älteren Images. Bei einem Fehler werden Backend, Frontend und Proxy nach Möglichkeit angehalten. Das Datenbankschema oder das Speicherformat könnten bereits verändert sein.
  • Prozess hart beendet oder Host neu gestartet: status erkennt einen zurückgelassenen laufenden Auftrag als interrupted. Eine vor Beginn der Wartung gespeicherte Wiederherstellungssperre bleibt erhalten. Abgeschlossene Teiloperationen werden nicht als erfolgreiches Update ausgegeben.

Zur Diagnose status und die geschützten Auftragsdateien lesen. Falls ein benannter fedeo-update-<Auftrag>-Migrationscontainer zurückgeblieben ist, dessen Zustand und Logs zuerst prüfen. Er kann unabhängig vom abgebrochenen Compose-Prozess weiterlaufen; erst nach geklärtem Zustand anhalten/entfernen.

Für die Rückkehr zum alten Stand in einem geplanten Wartungsfenster:

  1. Alle schreibenden Dienste und den Proxy angehalten lassen; keinen neuen Update-Auftrag starten.
  2. Prüfsummen aus backup/complete.json prüfen. Ursprüngliche Compose-Datei, .env und gegebenenfalls Override aus backup/config/ wiederherstellen. backup/containers.json dokumentiert die ursprünglichen Image-IDs; insbesondere bewegliche Infrastruktur-Tags vor dem Start auf die gesicherten Image-Stände festlegen.
  3. Falls Migrationen/Infrastrukturänderungen bereits begonnen haben: PostgreSQL und Dateispeicher aus dem zusammengehörigen Backup wiederherstellen. Der PostgreSQL-Dump ist für pg_restore geeignet; globals.sql enthält Rollen und Kennwörter und muss beim Wiederaufbau der Datenbank berücksichtigt werden. MinIO bzw. die vollständige SeaweedFS-Ablage storage/ und Zertifikate bei gestoppten Diensten aus files.tar wiederherstellen. Bei SeaweedFS auch die Speicherbeschreibung aus backup/config/.updates/storage-provider.json zurückspielen und das gesicherte Image mit docker image load -i backup/storage-image.tar laden. Die konkrete Rücksicherung bestehender Daten erfolgt bewusst manuell und ersetzt Daten. Der vor der Speicherumstellung erhaltene MinIO-Bestand gehört nicht zu einem aktuellen Anwendungsbackup; ihn keinesfalls als Abkürzung reaktivieren.
  4. Wiederhergestellten Stack mit dessen Compose-Dateien starten und Funktionen prüfen. Alternativ den Fehler der Zielversion beheben und diese erfolgreich starten.
  5. Erst nach erfolgreicher Wiederherstellung die Sperre aufheben:
sudo python3 /opt/fedeo/scripts/selfhost-update.py resolve --version 3.0.0

Bei Rückkehr zum alten Matrix-Stack dessen ursprüngliche Compose-Datei aus demselben Backup verwenden. Falls nötig, das vollständige matrix/-Verzeichnis aus files.tar bei gestoppten Matrix-Diensten wiederherstellen, insbesondere den gesamten PostgreSQL-Cluster mit dem ursprünglichen Datenbank-Image. Vorhandene Container-Schichten und anonyme Volumes bleiben an den behaltenen Containern erhalten. Für jeden betroffenen Container die ursprüngliche HostConfig.RestartPolicy aus backup/containers.json wieder setzen, beispielsweise docker update --restart=unless-stopped CONTAINER_ID, wenn genau diese Richtlinie gespeichert wurde. Danach die zuvor laufenden Matrix-Dienste mit der ursprünglichen Compose-Konfiguration starten und prüfen. resolve für den alten Stand prüft auch deren Image, Laufzustand und Neustartrichtlinie. resolve für den Zielrelease verlangt weiterhin gestoppte Matrix-Container mit deaktiviertem automatischem Neustart. Es führt diese Schritte nicht selbst aus.

resolve prüft die angegebene Backend-Version, Backend-Erreichbarkeit, Frontend-Erreichbarkeit, laufende Kerndienste, passende Anwendungs-Images und das Fehlen eines zurückgebliebenen Migrationscontainers. Es stellt selbst keine Daten wieder her. Bei alten Entwicklungsinstallationen die tatsächlich von /backend/version gemeldete Entwicklungsversion angeben. Ein späteres Update kann nach einer manuellen Compose-Wiederherstellung erneut --accept-compose-replacement erfordern.

Entwicklung und Tests

npm test
npm run commits:check
cd backend && node --import tsx --test tests/selfhostUpdates.test.ts tests/systemStatusStorage.test.ts
cd ../frontend && node --test tests/selfhost-updates.test.cjs

Die Update-Tests verwenden den echten Compose-Parser und einen simulierten Docker-Daemon. Sie prüfen u. a. Erfolg, Prüfsummen, Release-Auswahl, unveränderte Konfiguration, Speicherplatz, parallele Aufträge, Backupfehler, Migrationsfehler, falsche laufende Versionen und unterbrochene Aufträge. Die Matrix-Tests prüfen Stilllegung, Daten-/Container-Erhalt, Backup vor Änderung der Neustartrichtlinien, Fehler und Unterbrechungen sowie die weitere Ablehnung unbekannter Dienste. Ein vollständiger Test mit realem PostgreSQL-/MinIO-/Matrix-Restore auf einer separaten Selfhost-Testinstanz ist vor dem Produktionseinsatz zusätzlich erforderlich.

python3 -B scripts/update/tests/host_storage_integration.py prüft zusätzlich MinIO-Migration, Speicherübernahme, zwei Anwendungsupdates und Restore der regulären SeaweedFS-Updatesicherung mit echten Docker-Containern. Anwendung und Release-/HTTP-Antworten sind isolierte Testdaten. Benötigte Images und Aufbau stehen in scripts/storage/README.md. Die fachliche Abnahme des veröffentlichten FEDEO-Releases auf einer Testinstanz bleibt zusätzlich erforderlich.