Jak utworzyć użytkownika / bazę danych w skrypcie dla Docker Postgres

213

Próbowałem skonfigurować kontener dla instancji postgres deweloperskiej, tworząc niestandardowego użytkownika i bazę danych. Korzystam z oficjalnego obrazu dokera Postgres . W dokumentacji zaleca się wstawienie skryptu bash do /docker-entrypoint-initdb.d/folderu, aby skonfigurować bazę danych z dowolnymi niestandardowymi parametrami.

Mój skrypt bash: make_db.sh

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

Plik Docker

FROM library/postgres

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

Błąd, który otrzymuję z docker logs -f db(db to moja nazwa kontenera) to:

createuser: nie można połączyć się z bazą danych postgres: nie można połączyć się z serwerem: brak takiego pliku lub katalogu

Wygląda na to, że polecenia wewnątrz /docker-entrypoint-initdb.d/folderu są wykonywane przed uruchomieniem postgres. Moje pytanie brzmi: jak skonfigurować użytkownika / bazę danych programowo przy użyciu oficjalnego kontenera Postgres? Czy można to zrobić za pomocą skryptu?

pech0rin
źródło

Odpowiedzi:

378

EDYCJA - od 23 lipca 2015 r

Oficjalny postgres doker obraz będzie działać .sqlskrypty znajdują się w /docker-entrypoint-initdb.d/katalogu.

Więc wszystko, czego potrzebujesz, to utworzyć następujący skrypt SQL:

init.sql

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

i dodaj go do swojego pliku Docker:

Plik Docker

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

Ale od 8 lipca 2015 roku, jeśli wszystko, co potrzebne jest, aby utworzyć użytkownika i bazę danych , to łatwiej jest po prostu wykorzystać do POSTGRES_USER, POSTGRES_PASSWORDi POSTGRES_DBzmiennych środowiskowych:

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

lub z plikiem Dockerfile:

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

dla zdjęć starszych niż 23 lipca 2015 r

Z dokumentacji obrazu postgres Docker wynika, że ​​tak

[...] pobierze dowolny skrypt * .sh znaleziony w tym katalogu [ /docker-entrypoint-initdb.d] w celu przeprowadzenia dalszej inicjalizacji przed uruchomieniem usługi

Ważne jest tutaj „przed uruchomieniem usługi” . Oznacza to, że skrypt make_db.sh zostanie wykonany przed uruchomieniem usługi postgres, dlatego komunikat o błędzie „nie można połączyć się z bazą danych postgres” .

Następnie pojawia się kolejna przydatna informacja:

Jeśli musisz wykonać polecenia SQL w ramach inicjalizacji, wysoce zalecane jest użycie trybu pojedynczego użytkownika Postgres.

Zgadzam się, że na pierwszy rzut oka może to być nieco tajemnicze. Mówi, że skrypt inicjujący powinien uruchomić usługę postgres w trybie pojedynczym przed wykonaniem swoich działań. Możesz więc zmienić skrypt make_db.ksh w następujący sposób i powinien on przybliżyć cię do tego, co chcesz:

UWAGA , ostatnio zmieniło się to w następującym zatwierdzeniu . Będzie to działać z najnowszą zmianą:

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

Wcześniej --singlewymagane było użycie trybu:

gosu postgres postgres --single <<- EOSQL
    CREATE USER docker;
    CREATE DATABASE docker;
    GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
EOSQL
Thomasleveil
źródło
2
możesz:gosu postgres postgres --single < /tmp/somefile.sql
Thomasleveil,
1
Jak mogę biegaćpsql -U myDb -d myDb -f myDb.sql
DarVar
3
Uwaga: --single nie jest już obsługiwany w żadnym z plików dokujących Postgres.
brianz
1
Postępowałem zgodnie z instrukcjami i kiedy ssh do kontenera mysql i cd do docker-entrypoint-initdb.d, widzę mój init.sqlz kodem sql w nim. ALE kiedy otwieram mysql (używając dostępu roota) i piszę pokaż bazy danych, widzę tylko domyślne ustawienie z docker-compose.ymlpliku! Dlaczego mi to nie działa?
Mahmoud Zalt
1
Nie db.sqldziała nawet po skopiowaniu do `docker-entrypoint-initdb.d`
kamal
16

Możesz teraz umieścić pliki .sql w katalogu init:

Z dokumentów

Jeśli chcesz wykonać dodatkową inicjalizację na obrazie pochodzącym z tego, dodaj jeden lub więcej skryptów * .sql lub * .sh w /docker-entrypoint-initdb.d (w razie potrzeby utwórz katalog). Po tym, jak punkt wejścia wywoła initdb w celu utworzenia domyślnego użytkownika postgres i bazy danych, uruchomi wszystkie pliki * .sql i wyszuka wszelkie skrypty * .sh znalezione w tym katalogu w celu przeprowadzenia dalszej inicjalizacji przed uruchomieniem usługi.

Więc skopiowanie pliku .sql będzie działać.

m0meni
źródło
zmienne środowiskowe dla użytkownika / hasła i db db nadal działają. (9.5.3)
Jeremiasz Adams,
1
Mam projekt, który działa lokalnie. Jednak po przeniesieniu go do AWS EC2 jest napisane, że DB nie został znaleziony. Kopiuję plik .sql do odpowiedniego katalogu, ale nadal zwraca ten błąd. Masz pomysł, gdzie mógłbym spojrzeć? Jestem nowy w Docker.
MadPhysicist,
1
Jest to prawdą tylko wtedy, gdy istnieje jedna instancja db powiązana z jednym woluminem, tzn. Nie uruchomi żadnych skryptów, jeśli coś jest już w folderze woluminu. To sprawia mi ból głowy, ponieważ chcę mieć osobne inicjatory db dla każdej z moich usług stosu.
Violet Red,
9

Korzystając z docker-compose:

Zakładając, że masz następujący układ katalogu:

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

Plik: docker-compose.yml

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

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

Plik: Docker/db.Dockerfile

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

Komponowanie i uruchamianie usług:

docker-compose -f docker-compose.yml up --no-start
docker-compose -f docker-compose.yml start
Vlad
źródło
8

Dodałem niestandardowe polecenia do środowiska wywołanego w CMD po uruchomieniu usług ... Nie zrobiłem tego z postgres, ale z 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

i zacznij od

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

.

Rondo
źródło
7

Możesz użyć tych poleceń:

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
źródło
3
ENCODING 'LATIN1'jest bardzo dziwne ... Musisz mieć szczególne potrzeby, aby unikać używania utf8
Zyigh
4

Baza danych musi być uruchomiona przed utworzeniem użytkowników. Do tego potrzebujesz wielu procesów. Możesz albo uruchomić postgres w podpowłoce (&) w skrypcie powłoki, albo użyć narzędzia takiego jak nadzór, aby uruchomić postgres, a następnie uruchomić dowolne skrypty inicjujące.

Przewodnik po superwizorze i oknie dokowanym https://docs.docker.com/articles/using_supervisord/

seanmcl
źródło
2

W przypadku kompilacji dokera istnieje prosta alternatywa (nie trzeba tworzyć pliku Docker). Wystarczy utworzyć 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

I odwołaj się do tego w sekcji tomów:

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
źródło