Postgres 1x Datenbank umziehen

Da ich schon lange Paperless als digitales Dokumenten Archiv nutze, stellte sich immer wieder die Frage wie ziehe ich eigentlich die Datenbank auf eine neue Version von Postgres um.

Aber Halt, bevor Ihr Euch jetzt schon entsetzt abwendet weil Ihr kA habt wovon ich rede eine kurze Einleitung. Paperless ist wie schon erwähnt ein webbasierendes Dokumentenarchiv was ihr selbst bei Euch daheim oder bei einen Host im Internet aufsetzen könnt. Zum selber Hosten bietet sich die Nutzung von Docker an, denn so lassen sich die einzelnen Bestandteile die Paperless zum Starten benötigt einfacher konfigurieren. Der mit Paperless bei mir zu Grunde liegende Workflow basiert dabei auf einen Dokumenten Einzugsscanner mit (W)LAN Funktion, denn so lassen sich neue Dokumente direkt in den Eingangsordner von Paperless transportieren. Die Verarbeitung der neuen Dokumente erledigt dann Paperless über eigens erstellte Vorlagen oder manuell über die Webseite der installierten Instanz.

Eines der nötigen Zusatzpakete die Paperless benötigt ist Postgres, also eine schlanke auf SQL basierende Datenbank. Dort werden alle systemrelevante Daten von Paperless gespeichert. Zum Zeitpunkt der Erstellung ist die Release Version von Postgres v16 und Diese bietet noch einen weit in die Zukunft reichenden Support (Updates) an.

Bevor ich mich dem Thema des Umzugs der Daten auf diese Version annahm lief bei mir die Paperless Installation noch mit Postgres v13 (Support bis 2025). Es bestand also eigentlich kein Handlungsbedarf, aber da mich die Frage wie man das macht keine Ruhe gelassen hat, kam mir vor ein paar Tagen das Tutorial Video von @Navigio ganz Recht. In dem Video beschreibt er den Umzug der Datenbank auf einen Synology NAS innerhalb von Docker und Portainer. Dieses Vorgehen hat mich motiviert es auf meine Hardware/Software Situation zu portieren.

Ausgangssituation:

Server mit Proxmox Virtualisierung

auf Debian basierender LXC (Proxmox eigener Linux Container)

installierte Docker, Docker-Compose Umgebung

Paperless und alle nötigen Container (Postgres (v13), Redis7, Gotenberg, Tika laufen

SSH Zugriff auf den LXC (entweder über die Proxmox Shell des LXC oder wenn sshd entsprechend eingerichtet über die Shellkonsole des PC

Ziel:

Datenbank von älterer Postgres Version auf aktuele Version umziehen

Eines noch, die Ausgangssituation oben beschreibt meine Ausgangssituation und Diese muß NICHT Eure sein.

Wir beginnen mit dem bei der Erstinstallation verwendeten Compose Datei die üblicherweise im YAML Format vorliegt.

version: "3.4"
services:
broker:
image: docker.io/library/redis:7
container_name: broker
restart: unless-stopped
volumes:
- /data/paperless/redis/_data:/data

db:
image: docker.io/library/postgres:13
container_name: db
restart: unless-stopped
volumes:
- /data/paperless/postgresql/_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD: paperless

webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
container_name: webserver
restart: unless-stopped
depends_on:
- db
- broker
- gotenberg
- tika
ports:
- 8001:8000
healthcheck:
test: ["CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000"]
interval: 30s
timeout: 10s
retries: 5

volumes:
- /data/paperless/consume:/usr/src/paperless/consume
- /data/paperless/data:/usr/src/paperless/data

environment:
PAPERLESS_ADMIN_USER: xxx
PAPERLESS_ADMIN_PASSWORD: xxx
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_DBHOST: db
PAPERLESS_TIKA_ENABLED: 1
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
PAPERLESS_OCR_LANGUAGE: deu
PAPERLESS_TIME_ZONE: Europe/Berlin
USERMAP_UID: 1000
USERMAP_GID: 1000

gotenberg:
image: docker.io/gotenberg/gotenberg:latest
container_name: gotenberg
restart: unless-stopped
command:
- "gotenberg"
- "--chromium-disable-routes=true"
- "--chromium-allow-list=file:///tmp/.*"

tika:
image: ghcr.io/paperless-ngx/tika:latest
container_name: tika
restart: unless-stopped

Erläuterung:

Host Pfad der Datenbank => /data/paperless/postgresql/_data

Enviroment Datenbank Angaben (paperless) eventuell ändern (für mehr Sicherheit)

Host Paperless Eingang Überwachungsordner => /data/paperless/consume

Wir beginnen mit einer Sicherungskopie des Installation Docker-Compose File

cp docker-compose.yml docker-compose-orig.yml

Dann editieren wir die docker-compose.yml und ergänzen den gezeigten Blockcode

nano docker-compose.yml

db:
image: docker.io/library/postgres:13
container_name: db
restart: unless-stopped
volumes:
- /data/paperless/postgresql/_data:/var/lib/postgresql/data
- /data/paperless/postgresql/backup:/backup
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD: paperless

db-16:
image: docker.io/library/postgres:16
container_name: db-16
restart: unless-stopped
volumes:
- /data/paperless/postgresql/_data-16:/var/lib/postgresql/data
- /data/paperless/postgresql/backup:/backup
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD: paperless

Es wird ein zweiter Container mit der neuen Postgres Version 16 gestartet und die Pfade angepasst. Darüber hinaus verlinken wir einen /backup Folder in beide Container, denn dort wird später der Datenbank Dump geschrieben. Dann Datei speichern (STRG+O) und nano verlassen (STRG+X). Nun fertige docker-compose.yml zur Sicherheit nochmal wegschreiben.

cp docker-compose.yml docker-compose-upgr.yml

Nun diese Änderungen übergeben und die neue Docker Konfiguration starten

docker compose up -d

Um einen gesicherten Datenbank Zustand herzustellen stoppen wir nun alle Container außer die beiden Datenbank (Postgres) Container. Um Diese stoppen zu können müssen wir die Container IDs ermitteln

docker ps

Dank dieser Übersicht können wir nun die genannten Container stoppen. Im Bild oben fehlt der alte Postgres Container! Bei Euch muss der auch gelistet sein.

docker stop c869ee47fc38 43da162bb5dd d9c50d670102 8fd18438a4a9

Wenn das ohne Fehler funktioniert hat listet Docker die gestoppten Container auf.
Nun müssen wir uns mit der Bash Shell in den Container begeben. Unten stehenden Code entsprechend anpassen und die ID des alten Postgres Container nutzen

docker exec -it ID-ALTE-POSTGRES bash

Nun in der Bash mit folgenden Befehl den Datenbank Dump auf den Host /backup Folder schreiben

pg_dumpall -U $POSTGRES_USER > /backup/<dateiname>

Dabei den Placeholder <dateiname> mit gewünschten Namen ergänzen z.B.

pg_dumpall -U $POSTGRES_USER > /backup/20231208.sql

Bei der Ausführung erfolgt keine Rückmeldung, nur eventuelle Fehler werden gemeldet. Überprüfen lässt sich die Aktion natürlich wie folgt

ls -la /backup/

Oder nach Verlassen der Container Bash (mit dem Befehl exit) auf dem Host

ls -la /data/paperless/postgresql/backup

skywatcher@pve-paperless:~$ ls -la /data/paperless/postgresql/backup
insgesamt 1324
drwxr-xr-x 2 root root 4096 8. Dez 21:37 .
drwxr-xr-x 5 skywatcher skywatcher 4096 8. Dez 21:30 ..
-rw-r--r-- 1 root root 1344228 8. Dez 21:37 20231208.sql

Nun stellen wir eine Verbindung zum neuen Postgres Container her

docker exec -it ID-NEUE-POSTGRES bash

Dort wird nun folgender Befehl eingeben. Dabei den Placeholder <dateiname< durch den Dump Namen der Datenbank ersetzen, also wie oben zu sehen z.B. /backup/20231209.sql

psql -d $POSTGRES_DB -U $POSTGRES_USER < /backup/<dateiname>

skywatcher@pve-paperless:~$ docker exec -it 33f202298ae5 bash
root@33f202298ae5:/# psql -d $POSTGRES_DB -U $POSTGRES_USER < /backup/20231209.sql

Nach Abschicken des Befehl laufen ganz viele Meldungen durch die Bash und das kann je nach Menge der Datenbankeinträge einen Moment dauern.

Nun editieren wir nochmal die docker-compose.yml und erstellen eine Version nachdem Upgrade der Datenbank.

nano docker-compose.yml

version: "3.4"
services:
broker:
image: docker.io/library/redis:7
container_name: broker
restart: unless-stopped
volumes:
- /data/paperless/redis/_data:/data

db-13:
image: docker.io/library/postgres:13
container_name: db-13
restart: unless-stopped
volumes:
- /data/paperless/postgresql/_data:/var/lib/postgresql/data
# - /data/paperless/postgresql/backup:/backup
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD: paperless
POSTGRES_HOST_AUTH_METHOD: trust

db:
image: docker.io/library/postgres:16
container_name: db
restart: unless-stopped
volumes:
- /data/paperless/postgresql/_data-16:/var/lib/postgresql/data
# - /data/paperless/postgresql/backup:/backup
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD: paperless

webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
container_name: webserver
restart: unless-stopped
depends_on:
- db
- broker
- gotenberg
- tika
ports:
- 8001:8000
healthcheck:
test: ["CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000"]
interval: 30s
timeout: 10s
retries: 5
volumes:
- /data/paperless/consume:/usr/src/paperless/consume
- /data/paperless/data:/usr/src/paperless/data
- /data/paperless/media:/usr/src/paperless/media
- /data/paperless/export:/usr/src/paperless/export
environment:
PAPERLESS_ADMIN_USER: xxx
PAPERLESS_ADMIN_PASSWORD: xxx
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_DBHOST: db
PAPERLESS_TIKA_ENABLED: 1
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
PAPERLESS_OCR_LANGUAGE: deu
PAPERLESS_TIME_ZONE: Europe/Berlin
USERMAP_UID: 1000
USERMAP_GID: 1000

gotenberg:
image: docker.io/gotenberg/gotenberg:latest
container_name: gotenberg
restart: unless-stopped
command:
- "gotenberg"
- "--chromium-disable-routes=true"
- "--chromium-allow-list=file:///tmp/.*"

tika:
image: ghcr.io/paperless-ngx/tika:latest
container_name: tika
restart: unless-stopped

Was wurde geändert? Nun wir haben der alten Datenbank den Namen db-13 gegeben und er neuen Datenbank den Namen db (auf die Paperless auch zugreifen wird). Außerdem haben wir die backup Folder in beiden Datenbank Container auskommentiert da wir Diese nicht mehr benötigen. Nun können wir die Container neu bauen lassen und zum Test starten.

docker compose up -d

Wenn es ohne Fehler durchgelaufen ist prüfen wir trotzdem das Log des Paperless Webserver auf Fehler. Dazu zuerst die ID des Paperless Container ermitteln und dann die ID in den Befehl einfügen z.B.

docker ps
docker logs c869ee47fc38

Dort sollten keine Errors zu sehen sein. Nun können wir auch das Webif von Paperless mit der neuen Postgres bestaunen.

http://IP-ADRESSE-PAPERLESS:8001
https://10.3.2.104:8001 <= Beispiel

Schön und gut, allerdings sollten wir nochmal eingreifen und das Chaos etwas entschlacken. Dazu ändern wir nun Final noch einmal die docker-compose.yml

version: "3.4"
services:
broker:
image: docker.io/library/redis:7
container_name: broker
restart: unless-stopped
volumes:
- /data/paperless/redis/_data:/data

db:
image: docker.io/library/postgres:16
container_name: db
restart: unless-stopped
volumes:
- /data/paperless/postgresql/_data-16:/var/lib/postgresql/data
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD: paperless
POSTGRES_HOST_AUTH_METHOD: trust

webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
container_name: webserver
restart: unless-stopped
depends_on:
- db
- broker
- gotenberg
- tika
ports:
- 8001:8000
healthcheck:
test: ["CMD", "curl", "-fs", "-S", "--max-time", "2", "http://localhost:8000"]
interval: 30s
timeout: 10s
retries: 5
volumes:
- /data/paperless/consume:/usr/src/paperless/consume
- /data/paperless/data:/usr/src/paperless/data
- /data/paperless/media:/usr/src/paperless/media
- /data/paperless/export:/usr/src/paperless/export
environment:
PAPERLESS_ADMIN_USER: xxx
PAPERLESS_ADMIN_PASSWORD: xxx
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_DBHOST: db
PAPERLESS_TIKA_ENABLED: 1
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
PAPERLESS_OCR_LANGUAGE: deu
PAPERLESS_TIME_ZONE: Europe/Berlin
USERMAP_UID: 1000
USERMAP_GID: 1000

gotenberg:
image: docker.io/gotenberg/gotenberg:latest
container_name: gotenberg
restart: unless-stopped
command:
- "gotenberg"
- "--chromium-disable-routes=true"
- "--chromium-allow-list=file:///tmp/.*"

tika:
image: ghcr.io/paperless-ngx/tika:latest
container_name: tika
restart: unless-stopped

Der aufmerksame Leser wird erkennen das wir die alte Postgres und den Link des Backup Folder entfernt haben. Diesen Stand können wir nun auch für unsere Doku als docker-compose-final.yml sichern.

cp docker-compose.yml docker-compose-final.yml

Bevor wir die entschlackten Container starten empfiehlt es sich mal alle Container zu stoppen und dann neu zu starten.

docker stop $(docker ps -a -q)
docker compose up -d

Troubleshooting

Sollte beim Starten der Container eine Fehlermeldung erscheinen mit dem Inhalt ‚–remove-orphans‘ solltest für den betroffenen Container (vermutlich der alte Postgres Container) folgenden Befehl ausführen und dann die Container alle wieder neu erstellen und starten

docker-compose down --remove-orphans
docker compose up -d

weiterführende Publikationen

vielen Dank an Jürgen vom Youtube Kanal @Navigio

Anregung dieses Tutorial entstand durch dieses Video

Paperless-ngx im LXC Container installieren von Lucas Schreiner alias ‚Schreiners IT‘