Como persistir dados em um banco de dados postgres encaixado usando volumes

205

Meu arquivo de composição do docker possui três contêineres, web, nginx e postgres. O Postgres fica assim:

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

Meu objetivo é montar um volume que corresponda a uma pasta local chamada ./databasedentro do contêiner do postgres como /var/lib/postgres. Quando inicio esses contêineres e insiro dados no postgres, verifico se /var/lib/postgres/data/base/estão cheios dos dados que estou adicionando (no contêiner do postgres), mas no meu sistema local, ./databaseapenas obtém uma datapasta nele, ou seja, ./database/dataé criada, mas está vazia . Por quê?

Notas:

ATUALIZAÇÃO 1

Por sugestão de Nick, fiz um docker inspecte descobri:

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

O que faz parecer que os dados estão sendo roubados por outro volume que não me codifiquei. Não sei por que isso é. A imagem do postgres está criando esse volume para mim? Nesse caso, existe alguma maneira de usar esse volume em vez do volume que estou montando quando reinicio? Caso contrário, existe uma boa maneira de desativar esse outro volume e usar o meu ./database?

ATUALIZAÇÃO 2

Encontrei a solução, graças ao Nick! (e outro amigo) Responda abaixo.

Alex Lenail
fonte
você já executa a initdblinha de comando para inicializar seu cluster de banco de dados?
23817 Sebastian Webber
Tem certeza de que seu subdiretório de dados está realmente vazio? Pode ter permissões de acesso especiais.
Yaroslav Stavnichiy
Obrigado por voltar para mim tão rápido! Eu estou usando um balão de aplicação, de modo que from app import dbe db.create_all()a partir de um docker runapós o início dos recipientes. Eu não initdbdiretamente da linha de comando.
Alex Lenail
1
@YaroslavStavnichiy Não sei mais como verificar isso sudo su -e procurar ./database/data. Não há nada lá, tanto quanto eu posso dizer.
Alex Lenail
Alguém pode achar isso útil: amostra de arquivo compor persistindo postgres, elasticsearch e dados de mídia, stackoverflow.com/a/56475980/5180118
ArdentLearner

Respostas:

254

Curiosamente, a solução acabou sendo mudar

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

para

volumes:
  - ./postgres-data:/var/lib/postgresql/data
Alex Lenail
fonte
45
Apenas um "porquê" rápido para esta resposta (que funciona). Por as pessoas Postgres, o diretório de dados padrão é /var/lib/postgresql/data- você pode ler as notas variáveis PGDATA aqui: store.docker.com/images/...
Matt Pavelle
2
Na pergunta acima, o OP diz que funcionou para ele sem os / data no final. Isso está correto?
Sid
2
E adicione o diretório local ao seu .dockerignorearquivo, especialmente se você fizer isso com uma imagem de produção. Consulte codefresh.io/blog/not-ignore-dockerignore para uma discussão.
DSZ
4
isso ainda não funciona para mim (mac os x High Sierra)
olidem
1
@ OlliD-Metz Eu tive que fazer um docker rm my_postgres_container_1antes que funcionasse (também High Sierra).
Rich
100

Você pode criar um volume comum para todos os dados do Postgres

 docker volume create pgdata

ou você pode configurá-lo para o arquivo de composição

   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:

Ele criará o nome do volume pgdata e montará esse volume no caminho do contêiner.

Você pode inspecionar este 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
fonte
8
Comentando um pouco tarde, mas esses dados não serão claros se eu fizer um docker-compose down -v. E qual é a solução para isso?
Sid
3
@ Sid, sim, vai! Apenas tenha cuidado com esta opção.
olidem
1
então com docker-compose [down] o volume não é mais persistido? Faz uma limpeza completa mesmo do volume?
Paul
2
@Sid Comentando ainda mais tarde, mas você pode usar docker-compose down --rmi all sem a -vopção e limpará "tudo", exceto os volumes, como contêineres, redes, imagens, etc. Eu faço isso ao implantar, permitindo a persistência dos dados.
code_dredd
13

Eu evitaria usar um caminho relativo. Lembre-se de que o docker é um relacionamento daemon / cliente.

Quando você está executando a composição, é basicamente apenas dividir em vários comandos do cliente docker, que são passados ​​ao daemon. Isso ./databaseé relativo ao daemon , não ao cliente.

Agora, a equipe de desenvolvedores do docker tem algumas informações sobre esse assunto , mas o resultado é que pode haver resultados inesperados.

Em resumo, não use um caminho relativo, use um caminho absoluto.

Nick Burke
fonte
Obrigado por esta resposta! Infelizmente, não acho que funcionou. Alterei a linha para um caminho absoluto e, após inserir os dados, a database/datapasta ainda está vazia = (
Alex Lenail 13/17/17
K. Em seguida, execute docker inspecto contêiner e verifique se ele está ciente do volume (caso a composição esteja confusa ou algo assim). (nota: a janela de encaixe inspecionar pode ter dados confidenciais; portanto, não cole-os aqui sem usar a munging ;-) Depois disso, é uma questão de verificar as permissões (embora isso normalmente mostre um erro)
Nick Burke
Aha! @ Nick Burke Acho que você encontrou algo. Eu atualizei a pergunta.
Alex Lenail
2

Eu acho que você só precisa criar seu volume fora do docker primeiro com um docker create -v /location --namee depois reutilizá-lo.

E quando eu costumava usar muito o docker, não era possível usar um volume estático do docker com a definição do dockerfile, então minha sugestão é tentar a linha de comando (eventualmente com um script).

Joel B
fonte