Comment créer un utilisateur / une base de données dans un script pour Docker Postgres

213

J'ai essayé de mettre en place un conteneur pour une instance postgres de développement en créant un utilisateur et une base de données personnalisés. J'utilise l' image Docker officielle de PostgreSQL . Dans la documentation, il vous demande d'insérer un script bash à l'intérieur du /docker-entrypoint-initdb.d/dossier pour configurer la base de données avec tous les paramètres personnalisés.

Mon 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'erreur que j'obtiens de docker logs -f db(db est mon nom de conteneur) est:

createuser: impossible de se connecter à la base de données postgres: impossible de se connecter au serveur: aucun fichier ou répertoire de ce type

Il semble que les commandes à l'intérieur du /docker-entrypoint-initdb.d/dossier soient exécutées avant le démarrage de postgres. Ma question est, comment puis-je configurer un utilisateur / base de données par programmation en utilisant le conteneur officiel postgres? Existe-t-il un moyen de le faire avec un script?

pech0rin
la source

Réponses:

378

EDIT - depuis le 23 juil.2015

L' image docker officielle de postgres exécutera les .sqlscripts trouvés dans le /docker-entrypoint-initdb.d/dossier.

Il vous suffit donc de créer le script sql suivant:

init.sql

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

et ajoutez-le dans votre Dockerfile:

Dockerfile

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

Mais depuis le 8 Juillet, 2015, si vous avez besoin est de créer un utilisateur et base de données , il est plus facile de faire usage à la POSTGRES_USER, POSTGRES_PASSWORDet les POSTGRES_DBvariables d'environnement:

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

ou avec un Dockerfile:

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

pour les images antérieures au 23 juillet 2015

D'après la documentation de l'image Docker postgres , il est dit que

[...] il source tout script * .sh trouvé dans ce répertoire [ /docker-entrypoint-initdb.d] pour effectuer une initialisation supplémentaire avant de démarrer le service

L'important ici est "avant de démarrer le service" . Cela signifie que votre script make_db.sh sera exécuté avant le démarrage du service postgres, d'où le message d'erreur "impossible de se connecter à la base de données postgres" .

Après cela, il y a une autre information utile:

Si vous devez exécuter des commandes SQL dans le cadre de votre initialisation, l'utilisation du mode mono-utilisateur Postgres est fortement recommandée.

D'accord, cela peut être un peu mystérieux au premier abord. Ce qu'il dit, c'est que votre script d'initialisation devrait démarrer le service postgres en mode unique avant de faire ses actions. Vous pouvez donc modifier votre script make_db.ksh comme suit et cela devrait vous rapprocher de ce que vous voulez:

REMARQUE , cela a changé récemment dans le commit suivant . Cela fonctionnera avec la dernière modification:

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

Auparavant, l'utilisation du --singlemode était requise:

gosu postgres postgres --single <<- EOSQL
    CREATE USER docker;
    CREATE DATABASE docker;
    GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
EOSQL
Thomasleveil
la source
2
vous pouvez avec:gosu postgres postgres --single < /tmp/somefile.sql
Thomasleveil
1
Comment puis-je courirpsql -U myDb -d myDb -f myDb.sql
DarVar
3
Remarque: --single n'est plus pris en charge dans aucun des Dockerfiles postgres.
brianz
1
J'ai suivi les étapes et quand je ssh dans le conteneur mysql et cd dans docker-entrypoint-initdb.dje vois mon init.sqlavec le code sql dedans. MAIS quand j'ouvre mysql (en utilisant l'accès root) et que je tape show databases je ne vois que la valeur par défaut dans le docker-compose.ymlfichier! Pourquoi ça ne marche pas pour moi?
Mahmoud Zalt
1
Il ne s'exécute pas db.sqlmême après avoir été copié dans `docker-entrypoint-initdb.d`
kamal
16

Vous pouvez maintenant placer des fichiers .sql dans le répertoire init:

À partir des documents

Si vous souhaitez effectuer une initialisation supplémentaire dans une image dérivée de celle-ci, ajoutez un ou plusieurs scripts * .sql ou * .sh sous /docker-entrypoint-initdb.d (en créant le répertoire si nécessaire). Après que le point d'entrée appelle initdb pour créer l'utilisateur et la base de données postgres par défaut, il exécutera tous les fichiers * .sql et source tous les scripts * .sh trouvés dans ce répertoire pour effectuer une initialisation supplémentaire avant de démarrer le service.

La copie de votre fichier .sql fonctionnera donc.

m0meni
la source
les variables d'environnement pour la création d'utilisateur / mot de passe et de base de données fonctionnent toujours. (9.5.3)
Jeremiah Adams
1
J'ai un projet qui fonctionne localement. Cependant, lorsque je le déplace vers AWS EC2, il indique que DB n'est pas trouvé. Je copie le fichier .sql dans le répertoire approprié, mais il renvoie toujours cette erreur. Une idée où je pourrais regarder? Je suis nouveau sur Docker.
MadPhysicist
1
Cela n'est vrai que s'il existe une seule instance de base de données liée à un seul volume, c'est-à-dire qu'elle n'exécutera aucun script si quelque chose se trouve déjà dans le dossier du volume. Cela me donne un mal de tête, car je veux avoir des initialiseurs db séparés pour chacun de mes services de pile.
Violet Red
De la documentation 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

En utilisant docker-compose:

En supposant que vous disposez de la disposition du répertoire suivante:

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

Fichier: docker-compose.yml

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

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

Fichier: Docker/db.Dockerfile

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

Services de composition et de démarrage:

docker-compose -f docker-compose.yml up --no-start
docker-compose -f docker-compose.yml start
Vlad
la source
8

J'ajoute des commandes personnalisées à un environnement évoqué dans une CMD après le démarrage des services ... Je ne l'ai pas fait avec postgres, mais avec 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

et commencer par

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

.

Rondo
la source
7

Vous pouvez utiliser ces commandes:

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
la source
3
ENCODING 'LATIN1'est très bizarre ... Vous devez avoir des besoins très particuliers pour éviter d'utiliser utf8
Zyigh
4

Vous devez avoir la base de données en cours d'exécution avant de créer les utilisateurs. Pour cela, vous avez besoin de plusieurs processus. Vous pouvez soit démarrer postgres dans un sous-shell (&) dans le script shell, soit utiliser un outil comme supervisord pour exécuter postgres puis exécuter les scripts d'initialisation.

Un guide pour supervisord et docker https://docs.docker.com/articles/using_supervisord/

seanmcl
la source
2

Avec docker compose, il existe une alternative simple (pas besoin de créer un Dockerfile). Créez simplement 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

Et référencez-le dans la section 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
la source