Come creare Utente / Database in script per Docker Postgres


213

Ho cercato di impostare un contenitore per un'istanza postgres di sviluppo creando un utente e un database personalizzati. Sto usando l' immagine docker ufficiale di Postgres . Nella documentazione indica di inserire uno script bash all'interno della /docker-entrypoint-initdb.d/cartella per impostare il database con qualsiasi parametro personalizzato.

Il mio 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/

L'errore che ottengo dal docker logs -f db(db è il mio nome contenitore) è:

createuser: impossibile connettersi al database postgres: impossibile connettersi al server: nessun file o directory

Sembra che i comandi all'interno della /docker-entrypoint-initdb.d/cartella vengano eseguiti prima dell'avvio di postgres. La mia domanda è: come posso impostare un utente / database in modo programmatico usando il contenitore ufficiale di Postgres? C'è un modo per farlo con uno script?

Risposte:


378

MODIFICA - dal 23 luglio 2015

L' immagine docker ufficiale di postgres eseguirà gli .sqlscript trovati nella /docker-entrypoint-initdb.d/cartella.

Quindi tutto ciò che serve è creare il seguente script sql:

init.sql

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

e aggiungilo nel tuo Dockerfile:

Dockerfile

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

Ma dal momento che 8 luglio 2015, se tutto ciò che serve è quello di creare un utente e un database , è più facile fare uso solo al POSTGRES_USER, POSTGRES_PASSWORDe POSTGRES_DBle variabili di ambiente:

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

o con un file Docker:

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

per immagini precedenti al 23 luglio 2015

Dalla documentazione dell'immagine Docker di Postgres , si dice che

[...] genererà qualsiasi script * .sh trovato in quella directory [ /docker-entrypoint-initdb.d] per eseguire ulteriori inizializzazioni prima di avviare il servizio

Ciò che è importante qui è "prima di iniziare il servizio" . Ciò significa che lo script make_db.sh verrà eseguito prima dell'avvio del servizio Postgres , quindi il messaggio di errore "Impossibile connettersi al database Postgres" .

Dopodiché c'è un'altra utile informazione:

Se è necessario eseguire i comandi SQL come parte dell'inizializzazione, si consiglia vivamente di utilizzare la modalità utente singolo di Postgres.

D'accordo, questo può essere un po 'misterioso al primo sguardo. Ciò che dice è che lo script di inizializzazione dovrebbe avviare il servizio Postgres in modalità singola prima di eseguire le sue azioni. Quindi potresti cambiare il tuo script make_db.ksh come segue e dovrebbe avvicinarti a quello che vuoi:

NOTA , questo è cambiato di recente nel seguente commit . Questo funzionerà con l'ultima modifica:

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

In precedenza, --singleera richiesto l'uso della modalità:

gosu postgres postgres --single <<- EOSQL
    CREATE USER docker;
    CREATE DATABASE docker;
    GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
EOSQL

2
puoi con:gosu postgres postgres --single < /tmp/somefile.sql
Thomasleveil il

1
Come posso correrepsql -U myDb -d myDb -f myDb.sql
DarVar il

3
Nota: --single non è più supportato in nessuno dei file Dockerfile postgres.
brianz,

1
Ho seguito i passaggi e quando ho SSH nel contenitore mysql e cd in docker-entrypoint-initdb.dvedo il mio init.sqlcon il codice sql in esso. MA quando apro mysql (usando l'accesso root) e digito show database vedo solo l'impostazione predefinita dal docker-compose.ymlfile! Perché non funziona per me?
Mahmoud Zalt,

1
Non viene eseguito db.sqlanche dopo essere stato copiato in `docker-entrypoint-initdb.d`
kamal

16

Ora puoi inserire i file .sql nella directory init:

Dai documenti

Se desideri eseguire un'inizializzazione aggiuntiva in un'immagine derivata da questa, aggiungi uno o più script * .sql o * .sh in /docker-entrypoint-initdb.d (creando la directory se necessario). Dopo che l'entrypoint ha chiamato initdb per creare l'utente e il database postgres predefiniti, eseguirà qualsiasi file * .sql e genererà qualsiasi script * .sh trovato in quella directory per effettuare ulteriori inizializzazioni prima di avviare il servizio.

Quindi la copia del tuo file .sql funzionerà.


le variabili ambientali per la creazione di utente / password e db funzionano ancora. (9.5.3)
Jeremiah Adams,

1
Ho un progetto che funziona localmente. Tuttavia, quando lo sposto su AWS EC2, viene indicato che DB non viene trovato. Copio il file .sql nella directory corretta, ma restituisce comunque quell'errore. Qualche idea su dove potrei guardare? Sono nuovo di Docker.
MadPhysicist,

1
Ciò è vero solo se esiste un'unica istanza db associata a un singolo volume, ovvero non eseguirà alcun script se nella cartella del volume è già presente qualcosa. Questo mi dà mal di testa, perché voglio avere un inizializzatore db separato per ciascuno dei miei servizi di stack.
Violet Red,

Dai documenti Warning: scripts in /docker-entrypoint-initdb.d are only run if you start the container with a data directory that is empty; any pre-existing database will be left untouched on container startup. One common problem is that if one of your /docker-entrypoint-initdb.d scripts fails (which will cause the entrypoint script to exit) and your orchestrator restarts the container with the already initialized data directory, it will not continue on with your scripts.
sh87

9

Utilizzando docker-compose:

Supponendo di avere il seguente layout di directory:

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

File: docker-compose.yml

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

File: 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;

File: Docker/db.Dockerfile

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

Servizi di composizione e avviamento:

docker-compose -f docker-compose.yml up --no-start
docker-compose -f docker-compose.yml start

8

Aggiungo comandi personalizzati a un ambiente evocato in un CMD dopo aver avviato i servizi ... Non l'ho fatto con Postgres, ma con 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 iniziare con

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

.


7

Puoi usare questi comandi:

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;"

3
ENCODING 'LATIN1'è molto strano ... Devi avere esigenze molto particolari per evitare di usare utf8
Zyigh,

4

È necessario disporre del database in esecuzione prima di creare gli utenti. Per questo sono necessari più processi. È possibile avviare Postgres in una subshell (&) nello script della shell oppure utilizzare uno strumento come Supervord per eseguire Postgres e quindi eseguire qualsiasi script di inizializzazione.

Una guida a supervisord e docker https://docs.docker.com/articles/using_supervisord/


2

Con la finestra mobile componi c'è una semplice alternativa (non è necessario creare un file Docker). Basta creare un 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 fai riferimento nella sezione dei volumi:

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:
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.