Comment conserver des données dans une base de données postgres ancrée à l'aide de volumes

205

Mon fichier de composition Docker a trois conteneurs, Web, Nginx et PostgreSQL. Postgres ressemble à ceci:

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

Mon objectif est de monter un volume qui correspond à un dossier local appelé ./databaseà l'intérieur du conteneur postgres comme /var/lib/postgres. Lorsque je démarre ces conteneurs et que j'insère des données dans PostgreSQL, je vérifie qu'elles /var/lib/postgres/data/base/sont pleines des données que j'ajoute (dans le conteneur PostgreSQL), mais dans mon système local, ./databasene contient qu'un datadossier, c'est ./database/data-à- dire qu'il est créé, mais il est vide . Pourquoi?

Remarques:

MISE À JOUR 1

Selon la suggestion de Nick, j'ai fait un docker inspectet trouvé:

    "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": ""
        }
    ],

Ce qui donne l'impression que les données sont volées par un autre volume que je n'ai pas codé moi-même. Je ne sais pas pourquoi. L'image postgres crée-t-elle ce volume pour moi? Si oui, existe-t-il un moyen d'utiliser ce volume au lieu du volume que je monte lorsque je redémarre? Sinon, est - il une bonne façon de désactiver cet autre volume et en utilisant mon propre, ./database?

MISE À JOUR 2

J'ai trouvé la solution, grâce à Nick! (et un autre ami) Répondez ci-dessous.

Alex Lenail
la source
exécutez-vous déjà la initdbligne de commande pour initialiser votre cluster de base de données?
Sebastian Webber
Êtes-vous sûr que votre sous-répertoire de données est vraiment vide? Il peut avoir des autorisations d'accès spéciales.
Yaroslav Stavnichiy
Merci de me revenir si vite! J'utilise une application de flacon, donc je from app import dbet db.create_all()d'un docker runaprès le démarrage des conteneurs. Je ne suis pas initdbdirectement à partir de la ligne de commande.
Alex Lenail
1
@YaroslavStavnichiy Je ne sais pas comment vérifier cela sudo su -et regarder ./database/data. Pour autant que je sache, il n'y a rien là-dedans.
Alex Lenail
Quelqu'un pourrait trouver cela utile: exemple de fichier de composition persistant postgres, recherche élastique et données multimédias, stackoverflow.com/a/56475980/5180118
ArdentLearner

Réponses:

254

Curieusement, la solution a finalement été de changer

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

à

volumes:
  - ./postgres-data:/var/lib/postgresql/data
Alex Lenail
la source
45
Juste un "pourquoi" rapide pour cette réponse (qui fonctionne). Par les gens de Postgres, le répertoire de données par défaut est /var/lib/postgresql/data- vous pouvez lire les notes variables PGDATA ici: store.docker.com/images/…
Matt Pavelle
2
Dans la question ci-dessus, le PO dit que cela a fonctionné pour lui sans les données / à la fin. Est-ce exact?
Sid
2
Et ajoutez le répertoire local à votre .dockerignorefichier, surtout si vous voulez le regrouper dans une image de production. Voir codefresh.io/blog/not-ignore-dockerignore pour une discussion.
dsz
4
cela ne fonctionne toujours pas pour moi (mac os x high sierra)
olidem
1
@ OlliD-Metz J'ai dû faire un docker rm my_postgres_container_1avant que ça marche (aussi High Sierra).
riche
101

Vous pouvez créer un volume commun pour toutes les données Postgres

 docker volume create pgdata

ou vous pouvez le définir dans le fichier de composition

   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:

Il créera le nom de volume pgdata et montera ce volume sur le chemin du conteneur.

Vous pouvez inspecter ce volume

docker volume inspect pgdata

// output will be
[
    {
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/pgdata/_data",
        "Name": "pgdata",
        "Options": {},
        "Scope": "local"
    }
]
Nishchit Dhanani
la source
8
Commentant un peu tard, mais ces données ne seront-elles pas claires si je fais un docker-compose down -v. Et quelle est la solution à cela?
Sid
3
@Sid, oui, ça le sera! Soyez prudent avec cette option.
olidem
1
donc avec docker-compose [down] le volume n'est plus persistant? Est-ce un nettoyage complet même du volume?
Paul
2
@Sid Commentant encore plus tard, mais vous pouvez utiliser docker-compose down --rmi all sans l' -voption et cela effacera "tout" sauf les volumes, c'est-à-dire les conteneurs, les réseaux, les images, etc. Je le fais lors du déploiement tout en permettant la persistance des données.
code_dredd
13

J'éviterais d'utiliser un chemin relatif. N'oubliez pas que docker est une relation démon / client.

Lorsque vous exécutez la composition, elle se décompose essentiellement en diverses commandes client Docker, qui sont ensuite transmises au démon. C'est ./databasealors relatif au démon , pas au client.

Maintenant, l'équipe de développement de docker a des allers-retours sur ce problème , mais l'essentiel est que cela peut avoir des résultats inattendus.

En bref, n'utilisez pas de chemin relatif, utilisez un chemin absolu.

Nick Burke
la source
Merci pour cette réponse! Malheureusement, je ne pense pas que cela ait fonctionné. J'ai changé la ligne en un chemin absolu, et après avoir inséré les données, le database/datadossier est toujours vide = (
Alex Lenail
K. Ensuite, exécutez docker inspectle conteneur et assurez-vous que le conteneur est conscient du volume (juste au cas où la composition est confuse ou quelque chose). (Remarque: Docker inspect peut avoir des données sensibles, alors ne les collez pas ici sans les munging ;-) Après cela, il s'agit de vérifier les autorisations (bien que cela afficherait généralement une erreur)
Nick Burke
Ah! @ Nick Burke Je pense que vous avez trouvé quelque chose. J'ai mis à jour la question.
Alex Lenail
2

Je pense que vous avez juste besoin de créer votre volume hors docker d'abord avec un docker create -v /location --name, puis de le réutiliser.

Et au moment où j'utilisais beaucoup Docker, il n'était pas possible d'utiliser un volume Docker statique avec une définition Dockerfile, donc ma suggestion est d'essayer la ligne de commande (éventuellement avec un script).

Joel B
la source