So speichern Sie Daten in einer Docker-Postgres-Datenbank mithilfe von Volumes

204

Meine Docker-Erstellungsdatei enthält drei Container: Web, Nginx und Postgres. Postgres sieht so aus:

postgres:
  container_name: postgres
  restart: always
  image: postgres:latest
  volumes:
    - ./database:/var/lib/postgresql
  ports:
    - "5432:5432

Mein Ziel ist es, ein Volume ./databasebereitzustellen, das einem lokalen Ordner entspricht, der im Postgres-Container als aufgerufen wird /var/lib/postgres. Wenn ich diese Container starte und Daten in Postgres einfüge, überprüfe ich, ob /var/lib/postgres/data/base/die Daten, die ich hinzufüge , voll sind (im Postgres-Container), aber in meinem lokalen System wird ./databasenur ein dataOrdner darin angezeigt , dh er ./database/datawird erstellt, aber er ist leer . Warum?

Anmerkungen:

UPDATE 1

Per Nicks Vorschlag habe ich ein gemacht docker inspectund festgestellt:

    "Mounts": [
        {
            "Source": "/Users/alex/Documents/MyApp/database",
            "Destination": "/var/lib/postgresql",
            "Mode": "rw",
            "RW": true,
            "Propagation": "rprivate"
        },
        {
            "Name": "e5bf22471215db058127109053e72e0a423d97b05a2afb4824b411322efd2c35",
            "Source": "/var/lib/docker/volumes/e5bf22471215db058127109053e72e0a423d97b05a2afb4824b411322efd2c35/_data",
            "Destination": "/var/lib/postgresql/data",
            "Driver": "local",
            "Mode": "",
            "RW": true,
            "Propagation": ""
        }
    ],

Was den Anschein erweckt, als würden die Daten von einem anderen Volume gestohlen, das ich selbst nicht codiert habe. Ich bin mir nicht sicher, warum das so ist. Erstellt das Postgres-Bild dieses Volumen für mich? Wenn ja, gibt es eine Möglichkeit, dieses Volume anstelle des Volumes zu verwenden , das ich beim Neustart bereitstelle? Gibt es sonst eine gute Möglichkeit, dieses andere Volume zu deaktivieren und mein eigenes zu verwenden ./database?

UPDATE 2

Ich habe die Lösung gefunden, danke an Nick! (und ein anderer Freund) Antworte unten.

Alex Lenail
quelle
Führen Sie bereits die initdbBefehlszeile aus, um Ihren Datenbankcluster zu initialisieren?
Sebastian Webber
Sind Sie sicher, dass Ihr Datenunterverzeichnis wirklich leer ist? Möglicherweise verfügt es über spezielle Zugriffsberechtigungen.
Jaroslaw Stavnichiy
Vielen Dank, dass Sie sich so schnell bei mir gemeldet haben! Ich benutze eine Kolben-App, also habe ich from app import dbund db.create_all()von einem docker runnach dem Start die Container. Ich nicht initdbdirekt von der Kommandozeile.
Alex Lenail
1
@YaroslavStavnichiy Ich weiß nicht, wie ich das sonst überprüfen sudo su -und nachsehen soll ./database/data. Soweit ich das beurteilen kann, ist dort nichts drin.
Alex Lenail
Jemand könnte dies nützlich finden: Beispiel für die Erstellung von Postgres-Dateien, elastische Such- und Mediendaten, stackoverflow.com/a/56475980/5180118
ArdentLearner

Antworten:

251

Seltsamerweise bestand die Lösung darin, sich zu ändern

volumes:
  - ./postgres-data:/var/lib/postgresql

zu

volumes:
  - ./postgres-data:/var/lib/postgresql/data
Alex Lenail
quelle
45
Nur ein kurzes "Warum" für diese Antwort (was funktioniert). Laut den Postgres-Leuten ist das Standarddatenverzeichnis /var/lib/postgresql/data- Sie können die PGDATA-Variablennotizen hier lesen: store.docker.com/images/…
Matt Pavelle
2
In der obigen Frage sagt das OP, dass es für ihn ohne die / Daten am Ende funktioniert hat. Ist das korrekt?
Sid
2
.dockerignoreFügen Sie das lokale Verzeichnis zu Ihrer Datei hinzu, insbesondere wenn Sie dies jemals in ein Produktionsabbild zerlegen. Eine Diskussion finden Sie unter codefresh.io/blog/not-ignore-dockerignore .
dsz
4
das funktioniert immer noch nicht für mich (mac os x high sierra)
olidem
1
@ OlliD-Metz Ich musste ein machen, docker rm my_postgres_container_1bevor es funktionierte (auch High Sierra).
Rich
100

Sie können ein gemeinsames Volume für alle Postgres-Daten erstellen

 docker volume create pgdata

oder Sie können es auf die Erstellungsdatei setzen

   version: "3"
   services:
     db:
       image: postgres
       environment:
         - POSTGRES_USER=postgres
         - POSTGRES_PASSWORD=postgress
         - POSTGRES_DB=postgres
       ports:
         - "5433:5432"
       volumes:
         - pgdata:/var/lib/postgresql/data
       networks:
         - suruse
   volumes: 
     pgdata:

Es werden Datenträgernamen pgdata erstellt und dieses Datenträger in den Pfad des Containers .

Sie können dieses Volumen überprüfen

docker volume inspect pgdata

// output will be
[
    {
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/pgdata/_data",
        "Name": "pgdata",
        "Options": {},
        "Scope": "local"
    }
]
Nishchit Dhanani
quelle
8
Etwas spät kommentieren, aber diese Daten werden nicht gelöscht, wenn ich a mache docker-compose down -v. Und was ist die Lösung dafür?
Sid
3
@Sid, ja, das wird es! Seien Sie vorsichtig mit dieser Option.
Olidem
1
Also wird mit Docker-Compose [Down] die Lautstärke nicht mehr beibehalten? Führt eine vollständige Bereinigung sogar des Volumens durch?
Paul
2
@Sid auch später kommentiert, aber Sie können verwenden , docker-compose down --rmi all ohne die -vOption , und es wird klar aus „alles“ außer der Volumina, dh Behälter, Netzwerke, Bilder usw. ich, dass bei der Bereitstellung während Datenpersistenz ermöglicht.
code_dredd
13

Ich würde es vermeiden, einen relativen Pfad zu verwenden. Denken Sie daran, dass Docker eine Daemon / Client-Beziehung ist.

Wenn Sie das Compose ausführen, wird es im Wesentlichen nur in verschiedene Docker-Client-Befehle zerlegt, die dann an den Daemon übergeben werden. Das ./databaseist dann relativ zum Daemon , nicht zum Client.

Jetzt hat das Docker-Entwicklerteam einige Probleme mit diesem Problem , aber unter dem Strich kann es zu unerwarteten Ergebnissen kommen.

Kurz gesagt, verwenden Sie keinen relativen Pfad, sondern einen absoluten Pfad.

Nick Burke
quelle
Danke für diese Antwort! Leider glaube ich nicht, dass es funktioniert hat. Ich habe die Zeile in einen absoluten Pfad geändert und nach dem Einfügen der Daten ist der database/dataOrdner immer noch leer = (
Alex Lenail
K. Als nächstes müssen Sie docker inspectden Container ausführen und sicherstellen, dass der Container das Volumen kennt (nur für den Fall, dass das Verfassen verwirrt ist oder so). (Hinweis: Docker Inspect kann vertrauliche Daten enthalten. Fügen Sie diese also nicht ohne Munging hier ein. ;-) Danach müssen die Berechtigungen überprüft werden (obwohl dies normalerweise einen Fehler anzeigen würde)
Nick Burke
Aha! @ Nick Burke Ich denke du hast etwas gefunden. Ich habe die Frage aktualisiert.
Alex Lenail
2

Ich denke, Sie müssen Ihr Volume nur außerhalb von Docker erst mit einem erstellen docker create -v /location --nameund dann wiederverwenden.

Und als ich Docker oft benutzte, war es nicht möglich, ein statisches Docker-Volume mit Docker-Dateidefinition zu verwenden. Mein Vorschlag ist daher, die Befehlszeile (eventuell mit einem Skript) auszuprobieren.

Joel B.
quelle