Cómo conservar datos en una base de datos postgres dockerizada usando volúmenes

205

Mi archivo de compilación de Docker tiene tres contenedores, web, nginx y postgres. Postgres se ve así:

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

Mi objetivo es montar un volumen que corresponda a una carpeta local llamada ./databasedentro del contenedor de postgres como /var/lib/postgres. Cuando inicio estos contenedores e inserto datos en postgres, verifico que /var/lib/postgres/data/base/está lleno de los datos que estoy agregando (en el contenedor de postgres), pero en mi sistema local, ./databasesolo obtiene una datacarpeta, ./database/dataes decir, se crea, pero está vacío . ¿Por qué?

Notas:

ACTUALIZACIÓN 1

Según la sugerencia de Nick, hice una docker inspecty encontré:

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

Lo que hace que parezca que los datos están siendo robados por otro volumen que no codifiqué yo mismo. No estoy seguro de por qué es eso. ¿La imagen de postgres está creando ese volumen para mí? Si es así, ¿hay alguna forma de usar ese volumen en lugar del volumen que estoy montando cuando reinicio? De lo contrario, ¿hay una buena manera de desactivar ese otro volumen y usar el mío ./database?

ACTUALIZACIÓN 2

Encontré la solución, gracias a Nick! (y otro amigo) Responde a continuación.

Alex Lenail
fuente
¿Ya ejecuta la initdblínea de comando para inicializar el clúster de su base de datos?
Sebastian Webber
¿Estás seguro de que tu subdirectorio de datos está realmente vacío? Puede tener permisos de acceso especiales.
Yaroslav Stavnichiy
¡Gracias por responderme tan rápido! Estoy usando una aplicación de matraz, así que from app import dby db.create_all()desde docker rundespués de comenzar los contenedores. No lo hago initdbdirectamente desde la línea de comando.
Alex Lenail
1
@YaroslavStavnichiy No sé de qué otra manera verificar eso sudo su -y mirar ./database/data. No hay nada allí por lo que puedo decir.
Alex Lenail
Alguien puede encontrar esto útil: muestra componer archivo postgres persistentes, búsqueda elástica y datos de medios, stackoverflow.com/a/56475980/5180118
ArdentLearner

Respuestas:

254

Por extraño que parezca, la solución terminó siendo cambiar

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

a

volumes:
  - ./postgres-data:/var/lib/postgresql/data
Alex Lenail
fuente
45
Solo un rápido "por qué" para esta respuesta (que funciona). Según la gente de postgres, el directorio de datos predeterminado es /var/lib/postgresql/data: puede leer las notas de la variable PGDATA aquí: store.docker.com/images/…
Matt Pavelle
2
En la pregunta anterior, el OP dice que funcionó para él sin los datos / al final. ¿Es eso correcto?
Sid
2
Y agregue el directorio local a su .dockerignorearchivo, especialmente si alguna vez lo convertirá en una imagen de producción. Ver codefresh.io/blog/not-ignore-dockerignore para una discusión.
dsz
44
esto todavía no funciona para mí (mac os x high sierra)
olidem
1
@ OlliD-Metz Tuve que hacer un docker rm my_postgres_container_1antes de que funcionara (también High Sierra).
rico
101

Puede crear un volumen común para todos los datos de Postgres

 docker volume create pgdata

o puede configurarlo en el archivo de redacción

   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:

Creará el nombre del volumen pgdata y montará este volumen en la ruta del contenedor.

Puedes inspeccionar este volumen

docker volume inspect pgdata

// output will be
[
    {
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/pgdata/_data",
        "Name": "pgdata",
        "Options": {},
        "Scope": "local"
    }
]
Nishchit Dhanani
fuente
8
Comento un poco tarde, pero esto no borrará los datos si hago un docker-compose down -v. ¿Y cuál es la solución a eso?
Sid
3
@Sid, sí, ¡lo hará! Solo ten cuidado con esta opción.
olidem
1
entonces con docker-compose [down] el volumen ya no se persiste? ¿Una limpieza completa incluso del volumen?
Paul
2
@Sid Comentando aún más tarde, pero puede usarlo docker-compose down --rmi all sin la -vopción y eliminará "todo" excepto los volúmenes, es decir, contenedores, redes, imágenes, etc. Lo hago cuando lo despliego mientras permito la persistencia de los datos.
code_dredd
13

Evitaría usar una ruta relativa. Recuerde que Docker es una relación demonio / cliente.

Cuando está ejecutando la composición, esencialmente se divide en varios comandos de cliente de docker, que luego se pasan al demonio. Eso ./databasees relativo al demonio , no al cliente.

Ahora, el equipo de desarrollo de Docker tiene algunas dudas sobre este tema , pero la conclusión es que puede tener algunos resultados inesperados.

En resumen, no use una ruta relativa, use una ruta absoluta.

Nick Burke
fuente
Gracias por esta respuesta! Lamentablemente, no creo que haya funcionado. Cambié la línea a una ruta absoluta, y después de insertar los datos, la database/datacarpeta todavía está vacía = (
Alex Lenail
K. Lo siguiente es ejecutar docker inspecten el contenedor y asegurarse de que el contenedor esté al tanto del volumen (en caso de que la composición esté confundida o algo así). (nota: docker inspeccionar puede tener datos confidenciales, así que no los pegue aquí sin molestarlos ;-) Después de eso, es cuestión de verificar los permisos (aunque eso generalmente mostraría un error)
Nick Burke
¡Ajá! @ Nick Burke Creo que has encontrado algo. He actualizado la pregunta.
Alex Lenail
2

Creo que solo necesita crear su volumen fuera de la ventana acoplable primero con un docker create -v /location --namey luego reutilizarlo.

Y cuando solía usar mucho docker, no era posible usar un volumen de docker estático con definición de dockerfile, por lo que mi sugerencia es probar la línea de comandos (eventualmente con un script).

Joel B
fuente