Docker. Eigentlich ja ganz praktisch, wenn man „mal schnell“ ein Softwarepaket trotz überschaubarer Wartbarkeit mit überschaubarem Aufwand ausrollen möchte, ab und an aber auch ein zuverlässiger Quell für Facepalm-Momente. So auch Heute: Nach dem Update einer mit docker-compose
zusammengesetzten Anwendung ging nichts mehr. Der Maintainer hatte dort von postgres:10
auf postgres:11
aktualisiert. Kleines Update sollte man meinen, die PostgreSQL-Images für Docker sind jedoch technisch nicht in der Lage Daten älterer Installationen zu migrieren. Folglich zeigte sich im Log vor dem Absturz folgende Meldung:
postgres_1 | FATAL: database files are incompatible with server
postgres_1 | DETAIL: The data directory was initialized by PostgreSQL version 10, which is not compatible with this version 11.6.
Was auf „normalen“ Servern mit pg_upgrade
schnell geregelt und bei einigen Distributionen gar automatisiert ist, wird mit Docker ein paar Nummern komplizierter. Der Offizielle Weg: Backup machen, neu aufsetzen, importieren. Eigentlich wollte ich durch Docker Arbeit sparen, nicht mir weitere aufhalsen.
Glück im Unglück: Tianon Gravi hat auf GitHub und Docker Hub ein passendes System bereitgestellt, mit welchem man die Daten schnell zwischen verschiedenen PostgreSQL-Versionen migrieren kann.
Im Folgenden gehe ich davon aus, dass ein Named Volume „postgres-data
“ existiert und alle darauf zugreifenden Container gestoppt sind.
Achtung, Fallstrick: Nutzt man docker-compose, so ändern sich die Volume-Namen. Ein Named Volume „postgres-data
“ der Applikation „foobar
“ heißt in Wahrheit „foobar_postgres-data
„. Im Zweifel nochmal mit „docker volume ls
“ prüfen.
- Fangen wir mit dem üblichen an: Backups. Bei Bind-Mounts kopiert man einfach den Quellordner passend zurecht, bei Named Volumes kann man diese üblicherweise unter
/var/lib/docker/volumes/
finden oder mit docker-clone-volume duplizieren. Ich hatte postgres-data
hierzu auf postgres-data-src
und postgres-data-bck
dupliziert. - Weiter geht es mit dem Umwandeln der Datenbank. Hierzu nimmt man das Image mit den passenden Versionsnummern für Quell- und Zielversion.
docker run --rm -v postgres-data-src:/var/lib/postgresql/10/data -v postgres-data-dst:/var/lib/postgresql/11/data tianon/postgres-upgrade:10-to-11
Hiermit wird ein neues, mit PostgreSQL 11 kompatibles, Volume erzeugt, welches alle bisherigen Daten enthalten sollte. - Leider gibt es in der aktuellen Version einen bekannten Bug, welche die Zugriffe in
pg_hba.conf
abweichend von den Dateien der offiziellen Images konfiguriert. Dies führt mit vielen Images zu Zugriffsfehlern. Um die Datei per hand zu editieren startet man entweder einen passenden Container oder greift über das Dateisystem des Hosts auf diese zu. In meinem Fall nutzte ich letztere Methode über die Datei /var/lib/docker/volumes/postgres-data-dst/_data/pg_hba.conf
. An das Ende dieser wird folgende Zeile angefügt:
host all all all md5
- Am Ende ändert man entweder den Volume-Eintrag seiner
docker-compose.yml
oder kopiert das neue Image passend zurück. In meinem Fall klang letzteres sinnvoller. Einen Befehl zum Umbenennen von Volumes ist Docker bis Heute nicht bekannt, daher bleibt hier nur das ursprüngliche Volume mit docker volume rm postgres-data
zu löschen und postgres-data-dst
– wie zuvor – mit docker-clone-volume oder im Dateisystem zum korrekten Volume-Namen zu klonen.
Warum man das nicht automatisiert erschließt sich mir nicht so ganz. Vermutlich beschränkt sich der Benutzerkreis hauptsächlich auf Entwickler, die ohnehin immer von 0 starten, und Enterprise-Häuser, die gemäß Fire-and-forget Systeme ohne Update bis zur Explosion betreiben.