Befunde aus dem ersten echten Erstinstallations-Test auf frischen Debian-12- und Debian-13-Containern. Der Weg selbst hat getragen (Basis-Install, Instanz-Anlage, zweite Instanz, Update mit Rauchtest, Rollback) — diese Stellen haben gelogen oder gefehlt: - Das Ghostscript-Backports-Angebot auf Debian 12 war ein garantierter Leerlauf, der "aktualisiert ✓" meldete: bookworm-backports enthaelt gar kein ghostscript (am Paketindex verifiziert). Die Routine sucht jetzt den echten Kandidaten, vergleicht vorher/nachher und raeumt eine nur zur Probe angelegte Quelle wieder weg. - Derselbe untaugliche Rat stand in der Preflight-Meldung, der pdfa_level-Warnung, config.example.toml und vier Doku-Dateien — ueberall ersetzt durch die echten Optionen. - Mehrzeilige Log-Hinweise waren durch "echo -e" zerrissen und nicht kopierbar; log_* nutzt jetzt printf mit %s. - pip-freeze.txt landete beim Rollback als /pip-freeze.txt im Wurzelverzeichnis, liegt jetzt unter opt/pdf-ocr-hotfolder/. - git und sudo fehlen auf dem Proxmox-Debian-Template; "sudo ./install.sh" scheitert dort. Beide Wege dokumentiert, git als Voraussetzung ergaenzt, HTTPS-Clone als Normalfall. - Rollback: systemctl start kann kein Glob. journald-Reparatur: Instanzen danach neu starten, sonst bleibt das Journal leer. 254 Tests gruen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
8.7 KiB
Debian-Major-Upgrade
Wie der Hotfolder ein Distributions-Upgrade übersteht (12 → 13, später 13 → 14).
Verwandte Dokumente: README · Installation · Update
sudooder direkt alsroot. Alle Befehle dieser Seite brauchen root-Rechte, nichtsudo. Wer alsrootarbeitet — im Proxmox-Debian-Standard-Template der Normalfall, dort istsudogar nicht installiert —, lässt dassudoeinfach weg. Siehe INSTALLATION.md.
Warum das ein eigener Ablauf ist
Die venv unter /opt/pdf-ocr-hotfolder/venv/ hängt an der Python-Version der
Distribution. Ein apt full-upgrade von Debian 12 auf 13 tauscht Python 3.11
gegen 3.13 aus. Danach zeigt venv/bin/python auf einen Interpreter, den es so
nicht mehr gibt — systemd quittiert den Start jeder Instanz mit 203/EXEC, und
auch wenn der Interpreter noch existiert, passen die installierten Pakete nicht
mehr zum System-Python.
Die venv muss nach dem Sprung neu gebaut werden. Ein normales
sudo ./update.sh genügt dafür nicht sicher genug — es gibt den ausdrücklichen
Schalter --rebuild-venv.
Der Ablauf
1. Vorher updaten
cd /pfad/zum/repo
git pull
sudo ./update.sh
Das bringt die Installation auf den aktuellen Stand und erzeugt vor allem ein
frisches Backup inklusive pip-freeze.txt — die Liste der Paketversionen,
die auf dem alten System liefen. Inhalt und Ort des Backups:
UPDATE.md.
2. Instanzen stoppen
sudo systemctl stop 'pdf-ocr-hotfolder@*'
Während des Upgrades darf kein OCR laufen: Ghostscript, Tesseract und die Python-Pakete werden mitten im Betrieb ausgetauscht.
Geduld. Die Unit hat
TimeoutStopSec=300, damit ein laufendes OCR sauber zu Ende kommt. Ein Stop kann pro Instanz bis zu 5 Minuten dauern — bei mehreren Instanzen entsprechend länger. Nicht mitkill -9nachhelfen; ein harter Stopp lässt das Original inworking/liegen (der Dienst nimmt es beim nächsten Start zwar wieder auf, aber der Durchlauf ist verloren).
Prüfen, dass wirklich alles steht:
systemctl status 'pdf-ocr-hotfolder@*'
3. Distribution upgraden
Der übliche Debian-Weg — Sources auf das neue Release umstellen, dann:
sudo apt update
sudo apt full-upgrade
sudo reboot
Die Instanzen sind enabled und starten nach dem Reboot mit; mit der alten venv
scheitern sie (203/EXEC). Das ist erwartet und wird im nächsten Schritt
behoben.
4. venv neu bauen
cd /pfad/zum/repo
git pull
sudo ./update.sh --rebuild-venv
--rebuild-venv erzwingt den Neubau. Der Rest des Updates läuft wie gewohnt
(siehe UPDATE.md) — die
System-Pakete werden dabei ebenfalls abgeglichen, auch python3-venv für das
neue Python.
Der Neubau ist ganz oder gar nicht:
- Die alte venv wird nach
venv.old-<timestamp>verschoben. python3 -m venvbaut neu.- Die Requirements werden installiert.
- Erst bei Erfolg wird die alte venv gelöscht.
5. Wenn ein Pin nicht mehr passt
Scheitert pip install an einer gepinnten Version, bricht das Skript ab und
sagt genau, was los ist:
- die letzten 25 Zeilen der pip-Ausgabe,
- das gescheiterte Paket ("Gescheitertes Paket: …"),
- die Diagnose: "eine in requirements.txt fest gepinnte Version gibt es für Python <version> nicht (mehr)",
- den nächsten Schritt: requirements.txt anheben und
update.sh --rebuild-venverneut laufen lassen.
Die alte venv ist dann zurückgerollt — es liegt keine halb gefüllte venv herum. Sie hängt zwar weiterhin am alten Interpreter und die Instanzen laufen damit nicht (das sagt das Skript auch), aber der Zustand ist eindeutig.
Also:
# im Repo, auf einer Testmaschine
vim requirements.txt # Version des genannten Pakets anheben
pytest # Suite muss grün bleiben
git commit -am 'requirements: <paket> auf <version> anheben'
git push
# auf dem Zielsystem
git pull
sudo ./update.sh --rebuild-venv
6. --rebuild-venv vergessen?
Halb so wild: update.sh prüft die venv auch ohne den Schalter und baut sie bei
Versions-Drift von selbst neu. Geprüft wird
- ob das Verzeichnis und
venv/bin/pythonüberhaupt existieren, - ob der Interpreter der venv noch läuft (toter Symlink nach dem Upgrade),
- ob seine
major.minorzum System-python3passt, - ob
pyvenv.cfgdieselbe Version nennt wie der Interpreter.
Stimmt eines davon nicht, nennt das Skript den Grund und baut neu.
--rebuild-venv ist also nicht der einzige, aber der ausdrückliche Weg —
und der, den man nach einem Distributions-Upgrade nimmt, statt sich auf die
Erkennung zu verlassen.
Danach prüfen
Laufen alle Instanzen?
systemctl status 'pdf-ocr-hotfolder@*'
update.sh hat das schon verifiziert (Wartezeit, is-failed, Crash-Loop) und
in der Zusammenfassung Soll gegen Ist gestellt — ein Exit 0 heißt, dass jede
Instanz, die vorher lief, auch wieder läuft.
Sind die Configs sauber?
cd /opt/pdf-ocr-hotfolder
for f in /etc/pdf-ocr-hotfolder/*.toml; do
sudo ./venv/bin/python -m pdf_ocr_hotfolder --check-config --config "$f"
done
Exit 0/1/2 und was bei Warnungen zu tun ist: UPDATE.md.
Läuft eine echte PDF durch?
cp test.pdf /var/lib/pdf-ocr-hotfolder/<instanz>/incoming/
journalctl -u pdf-ocr-hotfolder@<instanz> -f
Im outgoing/ muss das OCR-PDF liegen, im Journal steht OCR done. Das ist der
einzige Test, der die neue venv und die neuen System-Binaries (Tesseract,
Ghostscript) wirklich anfasst — systemctl status sagt darüber nichts.
Ghostscript-Version auf dem neuen Release ansehen:
gs --version
Auf Debian 13 ist der Ghostscript-Bug aus Debian 12 kein Thema mehr — Debian
13 liefert Ghostscript 10.05.1. Damit ist PDF/A ([ocr].pdfa_level = "1",
"2" oder "3") zusammen mit skip_text = true erstmals ohne Einschränkung
nutzbar; auf Debian 12 gab es dafür keinen Weg (ein Upgrade aus
bookworm-backports existiert nicht, dort liegt kein Ghostscript-Paket). Genau
das ist oft der Grund für das Upgrade. Hintergrund:
INSTALLATION.md.
Hat jemand auf dem alten System nach der früheren, falschen Empfehlung einen
bookworm-backports-Eintrag unter /etc/apt/sources.list.d/ angelegt, gehört
er nach dem Upgrade entfernt — Ghostscript kam ohnehin nie daher:
sudo rm -f /etc/apt/sources.list.d/bookworm-backports.list
sudo apt update
Pins in requirements.txt
Die Python-Abhängigkeiten sind bewusst fest gepinnt:
ocrmypdf==17.4.1
watchdog==6.0.0
requests==2.33.1
paramiko==4.0.0
Ohne Pins würde ein pip install --upgrade bei jedem Update ungefragt eine neue
Major-Version ziehen — der nächste Sprung wäre ocrmypdf 17 auf 18, und der
reißt sonst alle Instanzen auf einmal, und zwar im Moment des Updates, nicht zu
einem Zeitpunkt, den man sich ausgesucht hat.
⚠️ ocrmypdf darf nicht unter 17 fallen. Bis einschließlich 16.x prüft ocrmypdf die Ghostscript-Version auch dann, wenn gar kein PDF/A erzeugt wird — auf Debian 12 (Ghostscript 10.0.0) scheitert damit jede PDF, weil
skip_text = trueunser Default ist. Genau das war der Ausfall in 0.6.0. Hintergrund: INSTALLATION.md.
Die aktuellen Pins sind gegen Python 3.11 (Debian 12) und 3.13 (Debian 13)
geprüft; für beide gibt es fertige Wheels, es wird nichts kompiliert. Das gilt
auch für die Abhängigkeiten, die ocrmypdf 17 zusätzlich mitbringt (pydantic,
pypdfium2, fpdf2, uharfbuzz).
Beim Anheben:
- Testmaschine benutzen — nie direkt auf dem produktiven Hotfolder.
- Prüfen, dass es für die neue Version auf beiden Python-Versionen fertige
Wheels gibt, sonst wird auf dem Zielsystem kompiliert:
pip install --dry-run --only-binary=:all: --python-version 3.11 \ --target /tmp/wheelcheck ocrmypdf==<version> pip install --dry-run --only-binary=:all: --python-version 3.13 \ --target /tmp/wheelcheck ocrmypdf==<version> - Dort
update.sh --rebuild-venvfahren, damit die Pakete wirklich frisch aufgelöst werden. pytestmuss grün bleiben (254 Tests).- Eine echte PDF durchschieben — die Test-Suite mockt ocrmypdf, ein Major-Sprung
fällt dort also nicht auf. Der Rauchtest in
update.shmacht genau das automatisch. - Erst dann committen und auf die produktiven Systeme geben.
Der ocrmypdf-Sprung 16 → 17 ist ein Major-Sprung und gehört in einen eigenen Vorgang mit eigenem Test, nicht in ein OS-Upgrade.