Como criar usuário / banco de dados em script para o Docker Postgres

213

Eu tenho tentado configurar um contêiner para uma instância de desenvolvimento do postgres, criando um usuário e banco de dados personalizados. Estou usando a imagem oficial do postgres docker . Na documentação, ele instrui a inserir um script bash dentro da /docker-entrypoint-initdb.d/pasta para configurar o banco de dados com quaisquer parâmetros personalizados.

Meu script bash: make_db.sh

su postgres -c "createuser -w -d -r -s docker"
su postgres -c "createdb -O docker docker"

Dockerfile

FROM library/postgres

RUN ["mkdir", "/docker-entrypoint-initdb.d"]
ADD make_db.sh /docker-entrypoint-initdb.d/

O erro que recebo do docker logs -f db(db é o nome do meu contêiner) é:

createuser: não foi possível conectar-se ao banco de dados postgres: não foi possível conectar-se ao servidor: esse arquivo ou diretório não existe

Parece que os comandos dentro da /docker-entrypoint-initdb.d/pasta estão sendo executados antes do postgres ser iniciado. Minha pergunta é: como configuro um usuário / banco de dados programaticamente usando o contêiner oficial do postgres? Existe alguma maneira de fazer isso com um script?

pech0rin
fonte

Respostas:

378

EDIT - desde 23/07/2015

A imagem oficial da janela de encaixe do postgres executará .sqlscripts encontrados na /docker-entrypoint-initdb.d/pasta.

Então, tudo que você precisa é criar o seguinte script sql:

init.sql

CREATE USER docker;
CREATE DATABASE docker;
GRANT ALL PRIVILEGES ON DATABASE docker TO docker;

e adicione-o ao seu Dockerfile:

Dockerfile

FROM library/postgres
COPY init.sql /docker-entrypoint-initdb.d/

Mas desde 08 julho de 2015, se tudo que você precisa é criar um usuário e banco de dados , é mais fácil simplesmente fazer uso do POSTGRES_USER, POSTGRES_PASSWORDe POSTGRES_DBvariáveis de ambiente:

docker run -e POSTGRES_USER=docker -e POSTGRES_PASSWORD=docker -e POSTGRES_DB=docker library/postgres

ou com um Dockerfile:

FROM library/postgres
ENV POSTGRES_USER docker
ENV POSTGRES_PASSWORD docker
ENV POSTGRES_DB docker

para imagens anteriores a 23 de julho de 2015

A partir da documentação da imagem do postgres Docker , diz-se que

[...] fornecerá qualquer script * .sh encontrado nesse diretório [ /docker-entrypoint-initdb.d] para fazer uma inicialização adicional antes de iniciar o serviço

O importante aqui é "antes de iniciar o serviço" . Isso significa que seu script make_db.sh será executado antes que o serviço postgres seja iniciado; portanto, a mensagem de erro "não pôde se conectar ao postgres do banco de dados" .

Depois disso, há outra informação útil:

Se você precisar executar comandos SQL como parte de sua inicialização, o uso do modo de usuário único do Postgres é altamente recomendado.

Concordou que isso pode ser um pouco misterioso à primeira vista. O que diz é que seu script de inicialização deve iniciar o serviço postgres no modo único antes de executar suas ações. Portanto, você pode alterar seu script make_db.ksh da seguinte maneira e deve aproximar-se do que deseja:

NOTA : isso foi alterado recentemente no seguinte commit . Isso funcionará com a alteração mais recente:

export PGUSER=postgres
psql <<- EOSQL
    CREATE USER docker;
    CREATE DATABASE docker;
    GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
EOSQL

Anteriormente, --singleera necessário o uso do modo:

gosu postgres postgres --single <<- EOSQL
    CREATE USER docker;
    CREATE DATABASE docker;
    GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
EOSQL
Thomasleveil
fonte
2
você pode com:gosu postgres postgres --single < /tmp/somefile.sql
Thomasleveil 6/15/15
1
Como posso executarpsql -U myDb -d myDb -f myDb.sql
DarVar
3
Observe que --single não é mais suportado em nenhum dos Dockerfiles do postgres.
Brianz
1
Eu segui as etapas e quando ssh no contêiner mysql e no cd docker-entrypoint-initdb.dvejo o meu init.sqlcom o código sql. MAS, quando abro o mysql (usando acesso root) e digito show database, vejo apenas o padrão no docker-compose.ymlarquivo! Por que não está funcionando para mim?
Mahmoud Zalt
1
A sua não execução db.sqlmesmo depois de ser copiado para `janela de encaixe-entrypoint-initdb.d`
kamal
16

Agora você pode colocar arquivos .sql dentro do diretório init:

Dos documentos

Se você deseja fazer uma inicialização adicional em uma imagem derivada desta, adicione um ou mais scripts * .sql ou * .sh em /docker-entrypoint-initdb.d (criando o diretório, se necessário). Depois que o ponto de entrada chama o initdb para criar o usuário e o banco de dados padrão do postgres, ele executa qualquer arquivo * .sql e origina qualquer script * .sh encontrado nesse diretório para fazer uma inicialização adicional antes de iniciar o serviço.

Portanto, copiar seu arquivo .sql funcionará.

m0meni
fonte
variáveis ​​ambientais para criação de usuário / senha e db ainda funcionam. (9.5.3)
Jeremiah Adams
1
Eu tenho um projeto que funciona localmente. No entanto, quando eu o movo para o AWS EC2, ele diz que o banco de dados não foi encontrado. Copio o arquivo .sql no diretório apropriado, mas ele ainda retorna esse erro. Alguma idéia de onde eu poderia procurar? Eu sou novo no Docker.
MadPhysicist
1
Isso só é verdade se houver uma única instância de banco de dados vinculada a um único volume, ou seja, ele não executará nenhum script se alguma coisa já estiver na pasta de volume. Isso me dá dor de cabeça, porque eu quero ter inicializadores de banco de dados separados para cada um dos meus serviços de pilha.
Violet Red
9

Usando docker-compose:

Supondo que você tenha o seguinte layout de diretório:

$MYAPP_ROOT/docker-compose.yml
           /Docker/init.sql
           /Docker/db.Dockerfile

Arquivo: docker-compose.yml

version: "3.3"
services:
  db:
    build:
      context: ./Docker
      dockerfile: db.Dockerfile
    volumes:
      - ./var/pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"

Arquivo: Docker/init.sql

CREATE USER myUser;

CREATE DATABASE myApp_dev;
GRANT ALL PRIVILEGES ON DATABASE myApp_dev TO myUser;

CREATE DATABASE myApp_test;
GRANT ALL PRIVILEGES ON DATABASE myApp_test TO myUser;

Arquivo: Docker/db.Dockerfile

FROM postgres:11.5-alpine
COPY init.sql /docker-entrypoint-initdb.d/

Serviços de composição e início:

docker-compose -f docker-compose.yml up --no-start
docker-compose -f docker-compose.yml start
Vlad
fonte
8

Eu adiciono comandos personalizados a um ambiente evocado em um CMD após o início dos serviços ... Não o fiz no postgres, mas no Oracle:

#set up var with noop command
RUN export POST_START_CMDS=":"
RUN mkdir /scripts
ADD script.sql /scripts
CMD service oracle-xe start; $POST_START_CMDS; tail -f /var/log/dmesg

e comece com

docker run -d ... -e POST_START_CMDS="su - oracle -c 'sqlplus @/scripts/script' " <image>

.

Rondó
fonte
7

Você pode usar estes comandos:

docker exec -it yournamecontainer psql -U postgres -c "CREATE DATABASE mydatabase ENCODING 'LATIN1' TEMPLATE template0 LC_COLLATE 'C' LC_CTYPE 'C';"

docker exec -it yournamecontainer psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE postgres TO postgres;"
Gabriel
fonte
3
ENCODING 'LATIN1'é muito estranho ... Você deve ter necessidades muito particulares para evitar o uso utf8
Zyigh
4

Você precisa ter o banco de dados em execução antes de criar os usuários. Para isso, você precisa de vários processos. Você pode iniciar o postgres em uma subshell (&) no script shell ou usar uma ferramenta como supervisord para executar o postgres e, em seguida, executar qualquer script de inicialização.

Um guia para supervisord e docker https://docs.docker.com/articles/using_supervisord/

seanmcl
fonte
2

Com o docker compor, há uma alternativa simples (não é necessário criar um arquivo Docker). Basta criar um init-database.sh:

#!/bin/bash
set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
    CREATE USER docker;
    CREATE DATABASE my_project_development;
    GRANT ALL PRIVILEGES ON DATABASE my_project_development TO docker;
    CREATE DATABASE my_project_test;
    GRANT ALL PRIVILEGES ON DATABASE my_project_test TO docker;
EOSQL

E referencie-o na seção de volumes:

version: '3.4'

services:
  postgres:
    image: postgres
    restart: unless-stopped
    volumes:
      - postgres:/var/lib/postgresql/data
      - ./init-database.sh:/docker-entrypoint-initdb.d/init-database.sh
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    ports:
      - 5432:5432

volumes:
  postgres:
danigb
fonte