Datenbank in Docker oder auf dem Host betreiben?
PostgreSQL, MySQL, MongoDB und Redis laufen produktiv problemlos in Docker. Entscheidend sind Volumes, Upgrades, Backups und harte Speicherlimits.
Soll die Datenbank in Docker oder auf dem Host laufen?
Betreiben Sie die Datenbank in Docker. Für einen Anwendungsstack auf einem VPS ist ein containerisiertes PostgreSQL, MySQL, MongoDB oder Redis eine übliche Wahl für den Produktivbetrieb. Die Diskussion darüber basiert meist auf dem falschen Argument. Ein Container ist ein Linux-Prozess mit Namespaces und cgroups. Er ist keine virtuelle Maschine. Zwischen der Datenbank und dem Datenträger befindet sich daher kein Hypervisor. Bei einem Bind-Mount oder einem lokalen benannten Volume landen Lese- und Schreibvorgänge im Dateisystem des Hosts. Es ist dasselbe Dateisystem, das auch eine Paketinstallation verwenden würde.
Die tatsächlichen Kosten entstehen im Betrieb. Vier Punkte entscheiden darüber, ob dieses Setup problemlos funktioniert oder zu einem langsamen Desaster wird: Wo liegen die Daten? Wem gehört das Verzeichnis? Wie sieht ein Upgrade auf eine neue Hauptversion aus? Und haben Sie jemals ein Backup wiederhergestellt? Wenn diese Punkte geklärt sind, ist der Container nur ein Detail. Wenn nicht, werden Sie dem Container die Probleme zuschreiben.
Diese Entscheidung ist bei jeder Serverdatenbank dieselbe. Die folgenden Beispiele verwenden PostgreSQL, MySQL, MongoDB und Redis. Die produktspezifischen Unterschiede werden an den relevanten Stellen erläutert.
Was ein Container tatsächlich ändert
Nicht den Speicherpfad, sofern Sie einen einbinden. Es wird derselbe Kernel, derselbe Page Cache und dasselbe Dateisystem verwendet.
Es gibt eine echte Performance-Falle: Sie tritt auf, wenn Sie keinen Speicher einbinden. Ohne Volume liegt das Datenverzeichnis in der beschreibbaren Schicht des Containers. Diese basiert auf einem Overlay-Dateisystem, das über dem Image liegt. Schreibvorgänge sind dort langsamer. Außerdem wird die gesamte Schicht gelöscht, wenn der Container entfernt wird. Daher stammt die Meldung: „Heute Morgen war meine Datenbank leer.“
Tatsächlich ändern sich folgende Punkte:
- Der Lebenszyklus.
docker compose downzerstört den Container. Alles, was nicht in einem Volume lag, wird ebenfalls gelöscht. - Die Version. Der Image-Tag bestimmt die Version. In einem Datenbank-Container gibt es kein
apt upgrade, das den nächstendocker compose pullübersteht. - Die Speicherabrechnung. Ein cgroup-Limit ist eine vom Kernel erzwungene harte Grenze. Die Datenbank weiß nicht, dass diese Grenze existiert.
- Der Benutzer. Der Prozess läuft im Container unter einer numerischen Benutzer-ID. Diese kann auf dem Host keine Eigentumsrechte besitzen.
Wo sich die Daten befinden, bestimmt alles
Es gibt zwei gute Optionen und einen häufigen Fehler.
- Ein benanntes Volume:
pgdata:/var/lib/postgresql/data. Docker erstellt das Verzeichnis unter/var/lib/docker/volumes/<project>_pgdata/_data, und der Image-Entrypoint setzt beim ersten Start den Besitzer. Das ist die Standardempfehlung. - Ein Bind-Mount:
/srv/appname/pg:/var/lib/postgresql/data. Sie wählen den Pfad, daher müssen Sie sich selbst um die Berechtigungen kümmern. - Überhaupt kein Mount. Siehe oben. Die Daten befinden sich im Container.
Die vollständige Abwägung ist ein eigenes Thema; Bind-Mounts im Vergleich zu benannten Volumes behandelt sie. Für eine Datenbank gilt kurz gesagt: Verwenden Sie ein benanntes Volume, sofern es keinen konkreten Grund gibt, den Pfad auf dem Host zu kennen. Wenn Sie einen Bind-Mount verwenden, legen Sie ihn an einem stabilen Ort wie /srv/appname/pg ab und nicht im Projektverzeichnis, wo ein git clean darauf zugreifen kann.
Eine feste Einschränkung gilt: Legen Sie ein Datenverzeichnis einer Datenbank nicht auf NFS (Network File System) oder auf einem anderen Netzwerk-Mount ab, dessen Sperr- und fsync-Verhalten Sie nicht getestet haben. Datenbanken setzen voraus, dass ein erfolgreiches fsync bedeutet, dass sich die Bytes auf einem stabilen Speichermedium befinden. Wenn diese Annahme nicht zutrifft, entsteht eine Beschädigung, die erst Wochen später sichtbar wird.
Legen Sie den Volume-Namen fest, bevor das Volume verschwindet
Compose benennt ein Volume als <project>_<volume>, und der Projektname entspricht standardmäßig dem Verzeichnisnamen. Die Identität des Volumes hängt damit von einem Verzeichnisnamen ab, den Benutzer ändern, ohne darüber nachzudenken.
Verschieben Sie /srv/app nach /srv/app-old oder benennen Sie den Schlüssel pgdata in der Compose-Datei um, erstellt der nächste docker compose up -d ein vollständig neues, leeres Volume. Postgres initialisiert darin einen neuen Cluster. Der Container ist fehlerfrei, die Anwendung startet, und alle Tabellen sind verschwunden. Das alte Volume liegt weiterhin unter seinem alten Namen auf der Festplatte. Das ist die gute Nachricht.
docker volume ls
docker volume inspect app_pgdataLegen Sie die Namen fest, damit dies nicht passieren kann. Setzen Sie den Projektnamen und den Volume-Namen explizit:
name: myapp
services:
db:
image: postgres:17
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
name: myapp_pgdataWenn ein Volume bereits Ihre Daten enthält, kopieren Sie die Daten bei gestoppter Datenbank:
docker compose stop db
docker run --rm -v app_pgdata:/from -v myapp_pgdata:/to alpine sh -c 'cp -a /from/. /to/'
docker compose start dbWenn Sie die Daten bei laufender Datenbank kopieren, erhalten Sie eine inkonsistente Kopie von Dateien, in die gerade geschrieben wurde. Stoppen Sie die Datenbank zuerst.
Wem gehört das Datenverzeichnis?
Die offiziellen Postgres-, MySQL- und MongoDB-Images führen ihren Server als Benutzer mit einer nicht privilegierten Benutzer-ID aus, normalerweise 999. Wenn der Container als root startet, ändert der Entrypoint den Eigentümer des Datenverzeichnisses auf diesen Benutzer und gibt anschließend die Privilegien ab. Deshalb funktioniert ein leerer Bind-Mount beim ersten Versuch normalerweise.
Das schlägt fehl, sobald Sie in der Compose-Datei user: festlegen. Dann hat der Entrypoint keine Berechtigungen mehr, um die Eigentümerrechte zu korrigieren. Postgres meldet das direkt:
initdb: error: could not change permissions of directory "/var/lib/postgresql/data": Operation not permittedEin Datenverzeichnis, das mit den falschen Berechtigungen vorhanden ist, erzeugt eine andere Meldung. Diese sollten Sie erkennen, weil die Korrektur chmod lautet und nicht chown:
FATAL: data directory "/var/lib/postgresql/data" has invalid permissions
DETAIL: Permissions should be u=rwx (0700) or u=rwx,g=rx (0750).MongoDB schlägt bei einem Bind-Mount mit root als Eigentümer an der Lock-Datei fehl:
Unable to create/open the lock file: /data/db/mongod.lock (Permission denied). Ensure the user executing mongod is the owner of the lock file and has the appropriate permissions.Die Korrektur besteht darin, das Verzeichnis auf dem Host dem numerischen Benutzer-ID-Wert zuzuweisen, nicht einem Namen:
sudo chown -R 999:999 /srv/appname/pg
sudo chmod 700 /srv/appname/pg
ls -ldn /srv/appname/pgls -ldn gibt Zahlen statt Namen aus und sollte 999 999 anzeigen. Das Konto mit dem Namen postgres auf Ihrem Host und das Konto mit dem Namen postgres innerhalb des Images haben keinen Zusammenhang: Der Kernel vergleicht die Zahlen, und die Namen werden auf jeder Seite separat aufgelöst. wie PUID und PGID Hostbenutzer in einen Container abbilden erläutert diese Zuordnung. Bei rootless Docker oder der Zuordnung von Benutzer-Namespaces verschieben sich die Zahlen erneut. Lesen Sie die IDs deshalb aus dem laufenden Container aus, statt 999 anzunehmen.
Bei Named Volumes entfällt dieser gesamte Abschnitt beim ersten Start, weil Docker ein leeres Verzeichnis erstellt und der Entrypoint dessen Eigentümer wird.
Upgrades: Paket-Upgrade gegenüber einer Änderung des Image-Tags
Auf dem Host bringt Sie apt upgrade innerhalb einer Minor-Version weiter. Ihre Distribution führt nicht eigenständig einen Sprung auf eine neue Major-Version der Datenbank durch. Wenn Sie diesen Schritt ausführen, können beide Binärsätze gleichzeitig installiert werden. Genau das benötigt pg_upgrade.
In einem Container entspricht der Tag der Version. Ein Upgrade besteht daher aus der Änderung einer Zeile. Dadurch sind Minor-Upgrades trivial, während Major-Upgrades einem festen Verfahren folgen.
Ändern Sie postgres:16 in postgres:17 und führen Sie docker compose up -d aus. Der Container wird sofort beendet:
PostgreSQL Database directory appears to contain a database; Skipping initialization
FATAL: database files are incompatible with server
DETAIL: The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17.Dabei wird nichts beschädigt. Die neuen Binärdateien können das alte Kataloglayout auf der Festplatte nicht lesen. Dieses Layout ändert sich zwischen Major-Versionen. Setzen Sie den Tag auf postgres:16 zurück. Danach startet der Container wieder. Dieses Rollback ist der einzige echte Upgrade-Vorteil von Containern.
Der unterstützte Weg besteht aus Dump und Restore. PostgreSQL bevorzugt einen Dump, der mit dem neueren Client erstellt wurde. Führen Sie ihn daher aus dem neuen Image gegen den weiterhin laufenden alten Server im Compose-Netzwerk aus:
docker run --rm --network myapp_default -e PGPASSWORD="$POSTGRES_PASSWORD" \
postgres:17 pg_dumpall -h db -U postgres > /srv/backups/all.sql
ls -lh /srv/backups/all.sql
tail -n 2 /srv/backups/all.sqlDie Datei sollte mindestens einige zehn Kilobyte groß sein und mit einer Zeile enden, die PostgreSQL database cluster dump complete enthält. Eine Datei mit wenigen hundert Bytes bedeutet, dass der Dump fehlgeschlagen ist. Andernfalls löschen Sie möglicherweise ein Volume, ohne etwas zu gewinnen. Erst nach dieser Prüfung:
docker compose down
docker volume rm myapp_pgdata
# edit the compose file: image: postgres:17
docker compose up -d db
docker compose exec -T db psql -U postgres -f /dev/stdin < /srv/backups/all.sqlBei den anderen Engines gelten andere Verfahren:
- MySQL 8 aktualisiert sein eigenes Datenwörterbuch beim Start. Ein Wechsel auf einen neuen Minor-Tag erfordert daher normalerweise nur einen Neustart. Lesen Sie vor einem Wechsel zwischen Release-Reihen die Release Notes. Erstellen Sie in jedem Fall zuerst einen Dump.
- Bei MariaDB muss
mariadb-upgradeausgeführt werden, nachdem der Server mit der neuen Version gestartet wurde. - MongoDB muss jeweils um genau eine Major-Version aktualisiert werden. Nach jedem Schritt setzen Sie die Feature-Compatibility-Version, bevor Sie fortfahren. Wenn Sie eine Version überspringen, verweigert
mongodden Start und protokolliert eine Zeile mitUPGRADE PROBLEM, in derfeatureCompatibilityVersiongenannt wird. Ab MongoDB 7.0 benötigt der Befehl ein explizites Bestätigungs-Flag:db.adminCommand({ setFeatureCompatibilityVersion: "8.0", confirm: true }). - Redis lädt ältere Snapshot-Dateien problemlos, aber keine neueren. Ein Upgrade besteht daher aus einem Neustart. Ein Downgrade kann dagegen beim Laden der Daten fehlschlagen.
Die allgemeine Regel lautet: Ein Container erleichtert ein Downgrade, aber ein Upgrade wird dadurch nicht einfacher.
Warum wird mein Datenbankcontainer mit Exit-Code 137 beendet?
Der OOM-Killer des Kernels hat ihn wegen Speichermangels beendet. 137 entspricht 128 plus Signal 9.
docker compose ps
docker inspect myapp-db-1 | grep -i oomkilled
journalctl -k | tail -n 20docker compose ps zeigt Exited (137), die Inspect-Zeile lautet "OOMKilled": true, und das Kernel-Log enthält einen passenden Eintrag:
Memory cgroup out of memory: Killed process 4711 (postgres) total-vm:2170416kBDer Mechanismus funktioniert wie folgt und überrascht viele Anwender. PostgreSQL und MySQL dimensionieren ihre Puffer anhand des vom Host gemeldeten Gesamtspeichers. Ein cgroup-Limit ändert diesen Wert für sie nicht. Auf einem Host mit 16 GB und einem Limit von 2 GB plant die Datenbank so, als hätte sie 16 GB. Die cgroup beendet sie daher lange bevor der Host selbst unter Speicherdruck steht. Ein Speicherlimit allein reicht deshalb nicht aus. Sie müssen der Datenbank zusätzlich mitteilen, wie viel Speicher ihr zur Verfügung steht:
- PostgreSQL: Setzen Sie
shared_buffersund achten Sie aufwork_mem.work_memwird pro Sortiervorgang und pro Verbindung reserviert. Ein großzügiger Wert multipliziert mit fünfzig Verbindungen ist daher die übliche Ursache für einen Container, der unter Last statt beim Start beendet wird. - MySQL und MariaDB: Setzen Sie
innodb_buffer_pool_size, dessen Standardwert 128M ist. Lassen Sieinnodb_dedicated_serverin einem Container deaktiviert, da diese Einstellung ausschließlich dazu dient, die Größe anhand des erkannten Maschinenspeichers zu bestimmen. - MongoDB: Setzen Sie die Größe des WiredTiger-Cache explizit, statt sie anhand des Hostspeichers schätzen zu lassen.
- Redis:
maxmemoryist standardmäßig unbegrenzt. Redis wächst daher, bis die cgroup den Prozess beendet. Setzen Siemaxmemorydeutlich unter dem Container-Limit und wählen Sie einenmaxmemory-policy.
Postgres meldet das Ereignis auch aus eigener Sicht. Diese beiden Zeilen finden Sie im Log:
LOG: server process (PID 123) was terminated by signal 9: Killed
LOG: terminating any other active sessions due to crash of another server processWenn ein Backend beendet wird, müssen alle anderen Backends neu gestartet werden, weil der gemeinsam genutzte Speicher inkonsistent sein kann. Für Ihre Anwendung führt das zu einer Verbindungswelle und ist kein unauffälliges Ereignis. Speicherlimits in Docker Compose setzen erläutert die Syntax sowie den Unterschied zwischen mem_limit und der deploy.resources-Form.
Auf dem Host verschwindet dieses Problem nicht. Es verlagert sich nur. Ohne cgroup konkurriert die Datenbank mit allen anderen Prozessen auf dem System. Der OOM-Killer des Hosts wählt anhand eines Scores einen Prozess aus. Das kann sshd sein. Ein Limit, das die Datenbank kontrolliert beendet, ist im Betrieb leichter zu handhaben als ein OOM-Zustand des Hosts, der Sie aussperrt.
Backups: Datenbank intern sichern, extern sichern
Sichern Sie eine laufende Datenbank nicht, indem Sie ihr Datenverzeichnis kopieren. Eine Kopie auf Dateiebene, die während Schreibvorgängen des Servers erstellt wird, ist inkonsistent. Das stellen Sie erst beim Wiederherstellen fest.
Es gibt zwei zuverlässige Methoden: Erstellen Sie mit dem eigenen Werkzeug der laufenden Datenbank einen Dump und sichern Sie diesen, oder stoppen Sie den Container und kopieren Sie das Volume im ausgeschalteten Zustand.
docker compose exec -T db pg_dump -U postgres -Fc appdb > /srv/backups/appdb.dump
docker compose exec -T db mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" --single-transaction --all-databases > /srv/backups/mysql.sql
docker compose exec -T db mongodump --archive --gzip --db appdb > /srv/backups/appdb.archive.gz
docker compose exec -T redis redis-cli BGSAVE-T ist entscheidend. Ohne diese Option kann docker compose exec ein Terminal an den Befehl anhängen. Die Terminalschnittstelle fügt dem Ausgabestream dann Wagenrückläufe hinzu. Ein Textdump lässt sich anschließend nur mit ungewöhnlichen Fehlern wiederherstellen. Ein Binärdump ist schlicht beschädigt. Der Fehler bleibt beim Backup unbemerkt und tritt erst einen Monat später deutlich hervor.
--single-transaction erstellt für mysqldump einen konsistenten Snapshot der InnoDB-Tabellen, ohne den gesamten Server zu sperren.
Diese Befehle schreiben jeweils eine Datei. Sie sind kein Backup-System: Es gibt keine Aufbewahrungsregeln, keine Kopie außerhalb des Servers und keine Verifizierung. Übergeben Sie das Dump-Verzeichnis an ein Werkzeug, das alle drei Aufgaben übernimmt. Genau dafür sind restic-Backups von einem VPS gedacht. Sichern Sie /srv/backups, nicht /var/lib/docker/volumes.
Führen Sie anschließend die Wiederherstellung aus. Ein Backup, das Sie noch nie wiederhergestellt haben, ist kein Backup:
docker compose exec -T db createdb -U postgres restore_test
docker compose exec -T db pg_restore -U postgres -d restore_test < /srv/backups/appdb.dump
docker compose exec -T db psql -U postgres -d restore_test -c '\dt'\dt sollte die Tabellen Ihrer Anwendung auflisten. Ein leeres Ergebnis oder Did not find any relations. bedeutet, dass der Dump nicht dem erwarteten Inhalt entspricht. Entfernen Sie restore_test, wenn Sie fertig sind.
Der Befehl, der alles löscht
docker compose down -v.
down entfernt nur die Container und das Netzwerk. -v entfernt außerdem jedes benannte Volume, das in dieser Compose-Datei deklariert ist, sowie jedes an diese Container angehängte anonyme Volume. Es gibt keine Rückfrage und keine Möglichkeit zum Rückgängigmachen. Dies ist die häufigste Methode, mit der eine selbst gehostete Datenbank zerstört wird. Meist passiert das bei der Fehlersuche an einem anderen Problem, weil eine Antwort in einem Forum dazu aufgefordert hat.
Vier Maßnahmen begrenzen den Schadensumfang:
- Deklarieren Sie das Datenbank-Volume mit
external: true. Compose entfernt kein Volume, das es nicht selbst verwaltet. Daher kann-vdieses Volume nicht erreichen. Sie legen es einmalig mitdocker volume create myapp_pgdataan. - Verwenden Sie
docker compose stopunddocker compose startfür reguläre Neustarts. down im Vergleich zu stop in Compose erläutert, was die beiden Befehle jeweils entfernen. - Speichern Sie Dumps in einem Host-Pfad außerhalb aller Volumes, die Compose verwaltet.
- Fügen Sie
-vniemals aus einer Antwort zur Fehlersuche in einen Stack ein, der Daten enthält, die Sie benötigen.
Datenbank-Port nicht veröffentlichen
Diese Zeile stellt Ihre Datenbank im öffentlichen Internet bereit:
ports:
- "5432:5432"Sie bindet den Port an alle Interfaces. Docker schreibt das Ziel des Pakets um, bevor die Input-Regeln Ihrer Firewall das Paket sehen. Die Regeln von ufw befinden sich in der Input-Kette. Deshalb bewirkt ufw deny 5432 überhaupt nichts. Warum veröffentlichte Docker-Ports ufw umgehen zeigt den Durchlauf durch die Ketten.
Eine Anwendung im selben Compose-Projekt erreicht die Datenbank über den Servicenamen im Compose-Netzwerk. Dafür ist kein veröffentlichter Port erforderlich. Löschen Sie den Block. Wenn Sie einen Client auf dem Host verwenden möchten, binden Sie den Port ausschließlich an das Loopback-Interface:
ports:
- "127.0.0.1:5432:5432"Prüfen Sie, welcher Prozess tatsächlich lauscht:
sudo ss -ltnp | grep 5432127.0.0.1:5432 ist der gewünschte Zustand. 0.0.0.0:5432 bedeutet, dass jeder Ihr Passwort ausprobieren kann.
Was wo ausgeführt wird
Eine Anwendung auf einem VPS. Verwenden Sie einen Container. Nutzen Sie ein benanntes Volume mit festgelegtem Namen, veröffentlichen Sie keinen Port, setzen Sie ein Speicherlimit mit passenden Datenbankeinstellungen und erstellen Sie jede Nacht einen Dump in einen Host-Pfad, den restic erfasst. Beginnen Sie mit einer sauberen Docker-Installation auf einem VPS und verwalten Sie den Stack in einer einzigen Compose-Datei, die Sie in das Repository einchecken. Der Vorteil ist konkret: Die Datenbankversion steht als prüfbare Zeile in git.
Ein Host mit mehreren Diensten. Verwenden Sie Container und eine Datenbank pro Anwendung, nicht einen gemeinsamen Server für alle Anwendungen. Ein gemeinsamer Server bindet jede Anwendung an denselben Upgrade-Zeitplan. Eine außer Kontrolle geratene Abfrage verursacht dann einen Ausfall für alle. Geben Sie jedem Container ein eigenes Speicherlimit, damit eine fehlerhafte Abfrage auf die Anwendung begrenzt bleibt, die sie ausgelöst hat. Mehrere kleine Postgres-Instanzen benötigen etwas mehr Speicherplatz und deutlich weniger Abstimmung.
Die Datenbank ist das Produkt. Betreiben Sie sie auf dem Host aus dem Paket-Repository des Herstellers oder verwenden Sie einen Managed Service. pg_upgrade benötigt beide Hauptversionen der Binärdateien gleichzeitig. Das ermöglichen Pakete, ein Image mit nur einer Version jedoch nicht. Replikation und Point-in-Time-Recovery mit WAL-(Write-Ahead-Log-)Archivierung sind einfacher, wenn die Datenbank den Rechner und seine Datenträger selbst verwaltet. Wählen Sie für das System, das Sie um 03:00 alarmiert, den unspektakulären Weg.
Die Anwendung ist klein. Erwägen Sie, vollständig auf eine Serverdatenbank zu verzichten. Eine Webanwendung mit einem einzigen Schreibprozess auf einem VPS ist mit SQLite in der Produktion auf einem VPS oft besser bedient. Das Backup besteht dann aus einer Datei und der Upgrade-Pfad aus einer Bibliotheksversion.
FAQ
Ist es sicher, eine Produktionsdatenbank in Docker zu betreiben?
Ja, bei einem Anwendungs-Stack auf einem einzelnen Server. Ein Container ist ein Linux-Prozess mit Namespaces und cgroups. Mit einem eingebundenen Volume schreibt die Datenbank in dasselbe Host-Dateisystem wie bei einer Installation aus einem Paket. Die Risiken sind betrieblicher Natur und betreffen nicht die Geschwindigkeit: ein Volume, dessen Name nicht fest vorgegeben ist, ein Bind-Mount mit der falschen Benutzer-ID, eine nie getestete Wiederherstellung und docker compose down -v. Wenn Sie diese vier Punkte ausschließen, ist der Container geeignet. Installieren Sie die Datenbank direkt auf dem Host, wenn sie die Haupt-Workload darstellt und Sie pg_upgrade, Replikation oder Point-in-Time-Recovery benötigen.
Sollte ich für Datenbankdaten einen Bind-Mount oder ein benanntes Volume verwenden?
Verwenden Sie ein benanntes Volume, sofern Sie keinen bestimmten Grund haben, den Host-Pfad kennen zu müssen. Docker erstellt das Verzeichnis, und der Image-Entrypoint setzt beim ersten Start die Eigentümerschaft. Dadurch tritt das Berechtigungsproblem nicht auf. Legen Sie das Volume mit einem expliziten name: fest oder markieren Sie es als external: true. Andernfalls erzeugt das Umbenennen des Projektverzeichnisses unbemerkt ein neues leeres Volume und eine leere Datenbank. Ein Bind-Mount ist geeignet, wenn Sie das Host-Verzeichnis auf die numerische Benutzer-ID ändern, unter der das Image ausgeführt wird. Bei den offiziellen Postgres-, MySQL- und MongoDB-Images ist dies 999. Prüfen Sie dies mit ls -ldn, da ls -l den Namen anzeigt, den Ihr Host für diese Nummer verwendet. Dieser Name hat innerhalb des Containers keine Bedeutung.
Was löscht docker compose down -v?
Der Befehl entfernt die Container und das Netzwerk wie ein normales down. -v entfernt zusätzlich jedes in dieser Compose-Datei deklarierte benannte Volume sowie jedes an diese Container angehängte anonyme Volume. Das schließt die Datenbank ein. Es gibt keine Bestätigungsabfrage und keine Wiederherstellungsmöglichkeit. Als external: true markierte Volumes werden nicht entfernt. Das ist der wichtigste Grund, ein Datenbank-Volume als extern zu markieren. Für einen normalen Neustart verwenden Sie stattdessen docker compose stop und docker compose start.
Wie aktualisiere ich PostgreSQL in Docker auf eine neue Hauptversion?
Erstellen Sie einen Dump und spielen Sie ihn wieder ein. Wenn Sie postgres:16 auf postgres:17 ändern und den Container neu starten, erhalten Sie FATAL: database files are incompatible with server mit einer DETAIL-Zeile, in der beide Versionen genannt werden. Die neuen Binärdateien können das alte Katalogformat nicht lesen. Es werden keine Daten beschädigt. Setzen Sie den alten Tag zurück, dann startet der Container wieder. Erstellen Sie mit dem Client der neuen Version einen pg_dumpall aus dem laufenden Container der alten Version. Vergewissern Sie sich, dass die Datei mit PostgreSQL database cluster dump complete endet. Starten Sie anschließend den neuen Tag mit einem leeren Volume und spielen Sie den Dump ein. Für Minor-Upgrades innerhalb derselben Hauptversion genügen ein Pull und ein Neustart.
Warum beendet sich mein Datenbank-Container mit dem Exit-Code 137?
137 entspricht 128 plus Signal 9. Der Prozess wurde daher unmittelbar beendet. Führen Sie docker inspect <container> | grep -i oomkilled aus. Ein Wert von true bedeutet, dass der Container sein cgroup-Speicherlimit erreicht hat. Die häufigste Ursache ist, dass PostgreSQL und MySQL den Gesamtspeicher des Hosts auslesen und das Container-Limit nicht erkennen. Sie planen dann beispielsweise mit 16 GB, laufen aber innerhalb eines Limits von 2 GB. Setzen Sie shared_buffers und work_mem oder innodb_buffer_pool_size, damit die Werte zum Speicherlimit des Containers passen. Prüfen Sie journalctl -k auf die zugehörige Memory cgroup out of memory-Zeile. Damit bestätigen Sie, welchen Prozess der Kernel beendet hat.