PostgreSQL-Major-Upgrade in Docker durchführen

PostgreSQL-Major-Upgrade in Docker durchführen
Photo by Markus Winkler / Unsplash

Paperless-ngx ist eine beliebte Open-Source-Lösung, um Dokumente zu digitalisieren, automatisch zu indexieren und langfristig durchsuchbar zu archivieren. Gerade im Selfhosting-Umfeld läuft Paperless-ngx häufig als Docker-Setup mit mehreren Containern, darunter Webserver, Broker, Redis und PostgreSQL als Datenbank.

Solange alles läuft, denkt man über die Datenbankversion meist wenig nach. Spätestens bei einem größeren Paperless-ngx-Upgrade kann PostgreSQL aber plötzlich zum entscheidenden Thema werden.

Ein konkreter Anlass für diesen Beitrag war ein Paperless-ngx-Upgrade. Mit Paperless-ngx 2.18.0 wurde PostgreSQL ≥ 14 verbindlich vorausgesetzt. In meinem Fall lief die Datenbank noch auf PostgreSQL 13, sodass ein Upgrade des PostgreSQL-Containers notwendig wurde. Da ich ohnehin migrieren musste, habe ich direkt auf PostgreSQL 15 aktualisiert.

PostgreSQL ist robust, zuverlässig und in vielen Docker-Setups schnell eingerichtet. Spätestens beim Wechsel auf eine neue Major-Version merkt man aber: Ein PostgreSQL-Upgrade ist nicht einfach nur ein neues Docker-Image in der docker-compose.yml.

Dieser Beitrag beschreibt, wie du eine bestehende PostgreSQL-Datenbank, die in einem Docker-Container läuft, von einer Major-Version auf eine neue Version migrierst. Der Fokus liegt auf einem pragmatischen Vorgehen per Dump und Restore.

Der Ablauf eignet sich besonders für kleinere bis mittlere Anwendungen, Homelab-Setups und Selfhosting-Umgebungen, bei denen eine kurze Downtime akzeptabel ist.


Ausgangssituation

In diesem Beispiel gehen wir von folgendem Setup aus:

  • PostgreSQL läuft in Docker.
  • Die Container werden mit Docker Compose verwaltet.
  • In der docker-compose.yml gibt es einen Service mit dem Namen db.
  • Der Service verwendet ein offizielles PostgreSQL-Image.
  • Der laufende Container heißt beispielhaft paperless-postgress.
  • Die Anwendung und die Datenbank heißen beispielhaft paperless.

Das Ziel ist ein Upgrade von PostgreSQL Major-Version X auf Major-Version Y, zum Beispiel von PostgreSQL 13 auf PostgreSQL 15.

Im konkreten Paperless-ngx-Beispiel wurde das notwendig, weil Paperless-ngx ab Version 2.18.0 mindestens PostgreSQL 14 voraussetzt. Wer vorher noch einen PostgreSQL-13-Container betrieben hat, muss die Datenbank daher vor oder spätestens mit dem Paperless-Upgrade aktualisieren.

Wichtig: Bei PostgreSQL sind Major-Versionen nicht automatisch dateikompatibel. Es reicht daher nicht aus, einfach das Docker-Image von postgres:14 auf postgres:15 zu ändern und den Container neu zu starten. Im schlimmsten Fall startet PostgreSQL dann nicht mehr oder du beschädigst deine bestehende Datenbankstruktur.


Grober Ablauf

Der sichere Weg besteht aus drei Schritten:

  1. Bestehende Datenbank exportieren
  2. Neue PostgreSQL-Version mit leerem Datenverzeichnis starten
  3. Daten in die neue Datenbank importieren

Vor jedem Upgrade gilt: Erstelle ein Backup und prüfe, ob es lesbar ist. Ein Backup, das nie getestet wurde, ist nur eine Hoffnung.


1. Bestehende Daten exportieren

Zuerst sollte sichergestellt werden, dass während des Exports keine Anwendung mehr auf die Datenbank schreibt.

Verbinde dich per SSH mit dem Server und stoppe die Anwendung:

docker-compose down

Anschließend startest du nur den Datenbank-Container:

docker-compose up -d db

Nun wird ein Dump der gewünschten Datenbank erzeugt. Dafür verwendest du pg_dump und gibst die Datenbank explizit an:

docker exec -it application_database pg_dump -U paperless -d paperless > /tmp/backup-paperless.sql

Damit wird nur die Datenbank paperless exportiert und nicht die komplette PostgreSQL-Instanz mit allen Rollen, globalen Objekten und weiteren Datenbanken.

Danach solltest du prüfen, ob die Datei erstellt wurde und plausiblen Inhalt enthält:

ls -lh /tmp/backup-paperless.sql
less /tmp/backup-paperless.sql

Wenn der Dump erfolgreich erstellt wurde, stoppst du den Datenbank-Container wieder:

docker stop paperless-postgres

2. PostgreSQL-Version in Docker Compose aktualisieren

Jetzt wird die docker-compose.yml angepasst.

Wichtig ist dabei nicht nur das neue PostgreSQL-Image, sondern auch ein neues Datenverzeichnis. Die Dateien einer alten PostgreSQL-Major-Version sollten nicht direkt mit einer neuen Major-Version weiterverwendet werden.

Beispiel für PostgreSQL 15:

db:
  image: postgres:15-alpine
  ports:
    - "5432:5432"
  volumes:
    - /opt/docker/volumes/paperless/postgres_15:/var/lib/postgresql/data
  environment:
    - POSTGRES_PASSWORD
    - POSTGRES_DB
    - POSTGRES_USER
  restart: always

Das neue lokale Datenverzeichnis wird anschließend erstellt:

mkdir -p /opt/docker/volumes/paperless/postgres_15

Danach startest du nur den Datenbank-Container:

docker-compose up -d db

Docker lädt nun bei Bedarf das neue PostgreSQL-Image herunter und initialisiert ein neues, leeres Datenverzeichnis.

Anschließend kannst du prüfen, ob die neue PostgreSQL-Version läuft:

docker exec -it paperless-postgres psql -U paperless -c "select version();"

Die Ausgabe sollte die neue PostgreSQL-Version anzeigen.


3. Daten in die neue PostgreSQL-Version importieren

Jetzt wird der zuvor exportierte Dump in die neue Datenbank importiert.

Jetzt wird der zuvor exportierte Datenbank-Dump in die neue PostgreSQL-Instanz importiert:

cat /tmp/backup-paperless.sql | docker exec -i paperless-postgres psql -U paperless -d paperless

Nach dem Import solltest du kontrollieren, ob die Datenbank vorhanden ist und Tabellen enthält:

docker exec -it paperless-postgres psql -U paperless -d paperless -c "\dt"

Wenn alles passt, stoppst du den Datenbank-Container noch einmal:

docker stop paperless-postgres

Anschließend wird die komplette Anwendung wieder gestartet:

docker-compose up -d

Nacharbeiten und Kontrolle

Nach dem Start der Anwendung solltest du die Logs prüfen:

docker-compose logs -f

Besonders interessant sind dabei:

  • Startet PostgreSQL ohne Fehler?
  • Kann sich die Anwendung mit der Datenbank verbinden?
  • Gibt es Fehlermeldungen zu Rollen, Rechten oder Extensions?
  • Sind alle erwarteten Daten vorhanden?

Zusätzlich lohnt sich ein Blick in die PostgreSQL-Version:

docker exec -it paperless-postgres psql -U paperless -c "select version();"

Und ein kurzer Anwendungstest im Browser oder per API.


Wichtige Hinweise

Bei Paperless-ngx kann nach einem Upgrade des zugrunde liegenden PostgreSQL-Containers eine Warnung wie collation version mismatch erscheinen. Das bedeutet nicht automatisch, dass Daten verloren sind. Die Meldung weist darauf hin, dass PostgreSQL Unterschiede bei der verwendeten Sortier-/Collation-Version erkannt hat. Nach einem erfolgreichen Upgrade sollte diese Warnung geprüft und gemäß PostgreSQL- beziehungsweise Paperless-ngx-Dokumentation bereinigt werden.

Vor dem Upgrade solltest du dir das alte Datenverzeichnis nicht löschen. Benenne es lieber eindeutig oder lasse es unverändert liegen, bis du sicher bist, dass die Anwendung mit der neuen PostgreSQL-Version stabil läuft.

Beispiel:

postgres_14/
postgres_15/

So kannst du im Notfall nachvollziehen, welche Daten zu welcher PostgreSQL-Version gehören.

Außerdem solltest du prüfen, ob deine Anwendung die neue PostgreSQL-Version offiziell unterstützt. Nicht jede Anwendung ist sofort mit jeder neuen PostgreSQL-Major-Version kompatibel.


Fazit

Ein PostgreSQL-Major-Upgrade in Docker ist gut machbar, sollte aber bewusst durchgeführt werden. Der wichtigste Punkt ist, nicht einfach das Docker-Image zu ändern und das alte Datenverzeichnis weiterzuverwenden.

Der saubere Weg ist:

  1. Dump erstellen
  2. Neues PostgreSQL-Image mit neuem Datenverzeichnis starten
  3. Dump importieren
  4. Anwendung testen
  5. Altes Datenverzeichnis erst nach erfolgreicher Prüfung entfernen

Damit bleibt das Upgrade nachvollziehbar, reproduzierbar und im Fehlerfall rückbaubar.