Cara membuat Pengguna / Database dalam skrip untuk Docker Postgres

213

Saya telah mencoba membuat wadah untuk instance postgres pengembangan dengan membuat pengguna khusus & basis data. Saya menggunakan gambar poster docker resmi . Dalam dokumentasi itu memerintahkan Anda untuk memasukkan skrip bash di dalam /docker-entrypoint-initdb.d/folder untuk mengatur database dengan parameter khusus apa pun.

Skrip bash saya: 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/

Kesalahan yang saya dapatkan dari docker logs -f db(db adalah nama wadah saya) adalah:

createuser: tidak dapat terhubung ke database postgres: tidak dapat terhubung ke server: Tidak ada file atau direktori tersebut

Tampaknya perintah di dalam /docker-entrypoint-initdb.d/folder dieksekusi sebelum postgres dimulai. Pertanyaan saya adalah, bagaimana cara mengatur pengguna / basis data secara terprogram menggunakan wadah postgres resmi? Apakah ada cara untuk melakukan ini dengan skrip?

pech0rin
sumber

Jawaban:

378

EDIT - sejak 23 Jul 2015

Gambar poster docker resmi akan menjalankan .sqlskrip yang ditemukan di /docker-entrypoint-initdb.d/folder.

Jadi yang Anda butuhkan adalah membuat skrip sql berikut:

init.sql

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

dan tambahkan di Dockerfile Anda:

Dockerfile

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

Tapi sejak 8 Juli 2015, jika semua yang Anda butuhkan adalah untuk membuat user dan database yang , lebih mudah untuk hanya menggunakan make ke POSTGRES_USER, POSTGRES_PASSWORDdan POSTGRES_DBvariabel lingkungan:

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

atau dengan Dockerfile:

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

untuk gambar yang lebih tua dari 23 Jul 2015

Dari dokumentasi gambar postgres Docker , dikatakan demikian

[...] ini akan mencari skrip * .sh yang ditemukan di direktori [ /docker-entrypoint-initdb.d] untuk melakukan inisialisasi lebih lanjut sebelum memulai layanan

Yang penting di sini adalah "sebelum memulai layanan" . Ini berarti skrip Anda make_db.sh akan dieksekusi sebelum layanan postgres dimulai, oleh karena itu pesan kesalahan "tidak dapat terhubung ke database postgres" .

Setelah itu ada informasi lain yang bermanfaat:

Jika Anda perlu menjalankan perintah SQL sebagai bagian dari inisialisasi Anda, penggunaan mode pengguna tunggal Postgres sangat dianjurkan.

Setuju ini bisa sedikit misterius pada tampilan pertama. Apa yang dikatakannya adalah bahwa skrip inisialisasi Anda harus memulai layanan postgres dalam mode tunggal sebelum melakukan aksinya. Jadi Anda bisa mengubah skrip make_db.ksh Anda sebagai berikut dan itu akan membuat Anda lebih dekat dengan apa yang Anda inginkan:

CATATAN , ini telah berubah baru-baru ini di komit berikut . Ini akan bekerja dengan perubahan terbaru:

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

Sebelumnya, penggunaan --single mode diperlukan:

gosu postgres postgres --single <<- EOSQL
    CREATE USER docker;
    CREATE DATABASE docker;
    GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
EOSQL
Thomasleveil
sumber
2
Anda dapat dengan:gosu postgres postgres --single < /tmp/somefile.sql
Thomasleveil
1
Bagaimana saya bisa menjalankanpsql -U myDb -d myDb -f myDb.sql
DarVar
3
Catatan, --single tidak lagi didukung di Dockerfiles postgres mana pun.
brianz
1
Saya mengikuti langkah-langkah dan ketika saya ssh ke wadah mysql dan cd ke docker-entrypoint-initdb.dsaya melihat saya init.sqldengan kode sql di dalamnya. TETAPI ketika saya membuka mysql (menggunakan akses root) dan ketik show database saya hanya melihat default di docker-compose.ymlfile! Mengapa ini tidak berhasil untuk saya?
Mahmoud Zalt
1
Ini tidak mengeksekusi db.sqlbahkan setelah itu disalin ke `docker-entrypoint-initdb.d`
kamal
16

Anda sekarang dapat meletakkan file .sql di dalam direktori init:

Dari dokumen

Jika Anda ingin melakukan inisialisasi tambahan pada gambar yang berasal dari gambar ini, tambahkan satu atau lebih skrip * .sql atau * .sh di bawah /docker-entrypoint-initdb.d (membuat direktori jika perlu). Setelah entrypoint memanggil initdb untuk membuat pengguna dan database postgres default, ia akan menjalankan semua file * .sql dan sumber skrip * .sh yang ditemukan dalam direktori itu untuk melakukan inisialisasi lebih lanjut sebelum memulai layanan.

Jadi, menyalin file .sql Anda akan berfungsi.

m0meni
sumber
variabel lingkungan untuk pengguna / kata sandi dan pembuatan db masih berfungsi. (9.5.3)
Jeremiah Adams
1
Saya punya proyek yang bekerja secara lokal. Namun, ketika saya memindahkannya ke AWS EC2, dikatakan bahwa DB tidak ditemukan. Saya menyalin file .sql di direktori yang benar, tetapi masih mengembalikan kesalahan itu. Tahu di mana aku bisa mencari? Saya baru mengenal Docker.
MadPhysicist
1
Ini hanya benar jika ada instance db tunggal terikat ke volume tunggal, yaitu tidak akan menjalankan skrip jika ada sesuatu yang sudah ada di folder volume. Ini memberi saya sakit kepala, karena saya ingin memiliki inisialisasi db terpisah untuk setiap layanan stack saya.
Violet Red
Dari docs 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

Dengan menggunakan docker-compose:

Dengan asumsi bahwa Anda memiliki tata letak direktori berikut:

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

Mengajukan: docker-compose.yml

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

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

Mengajukan: Docker/db.Dockerfile

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

Menyusun dan memulai layanan:

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

Saya menambahkan perintah kustom ke lingkungan yang ditimbulkan dalam CMD setelah memulai layanan ... Saya belum melakukannya dengan postgres, tetapi dengan 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

dan mulai dengan

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

.

Rondo
sumber
7

Anda dapat menggunakan perintah ini:

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
sumber
3
ENCODING 'LATIN1'sangat aneh ... Anda harus memiliki kebutuhan khusus untuk menghindari penggunaan utf8
Zyigh
4

Anda harus menjalankan database sebelum membuat pengguna. Untuk ini, Anda perlu beberapa proses. Anda dapat memulai postgres dalam subshell (&) di skrip shell, atau menggunakan alat seperti supervisord untuk menjalankan postgres dan kemudian menjalankan skrip inisialisasi.

Panduan untuk supervisord dan buruh pelabuhan https://docs.docker.com/articles/using_supervisord/

seanmcl
sumber
2

Dengan komposisi docker ada alternatif sederhana (tidak perlu membuat Dockerfile). Cukup buat 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

Dan rujuk di bagian volume:

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
sumber