วิธีสร้างผู้ใช้ / ฐานข้อมูลในสคริปต์สำหรับ Docker Postgres


213

ฉันพยายามตั้งค่าคอนเทนเนอร์สำหรับอินสแตนซ์ postgres การพัฒนาโดยการสร้างผู้ใช้ & ฐานข้อมูลแบบกำหนดเอง ฉันใช้อย่างเป็นทางการภาพ postgres นักเทียบท่า ในเอกสารคู่มือนั้นแนะนำให้คุณใส่ bash script ภายใน/docker-entrypoint-initdb.d/โฟลเดอร์เพื่อตั้งค่าฐานข้อมูลด้วยพารามิเตอร์ที่กำหนดเอง

สคริปต์ทุบตีของฉัน: 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/

ข้อผิดพลาดที่ฉันได้รับจากdocker logs -f db(db คือชื่อคอนเทนเนอร์ของฉัน) คือ:

createuser: ไม่สามารถเชื่อมต่อกับฐานข้อมูล postgres: ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์: ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว

ดูเหมือนว่าคำสั่งภายใน/docker-entrypoint-initdb.d/โฟลเดอร์จะถูกดำเนินการก่อนที่จะเริ่ม postgres คำถามของฉันคือฉันจะตั้งค่าผู้ใช้ / ฐานข้อมูลโดยใช้โปรแกรมอย่างเป็นทางการของ postgres container ได้อย่างไร มีวิธีใดบ้างในการใช้สคริปต์?

คำตอบ:


378

แก้ไข - ตั้งแต่ 23 กรกฎาคม 2015

อย่างเป็นทางการภาพ postgres นักเทียบท่าจะทำงาน.sqlสคริปต์ที่พบใน/docker-entrypoint-initdb.d/โฟลเดอร์

ดังนั้นสิ่งที่คุณต้องการคือการสร้างสคริปต์ sql ต่อไปนี้:

init.sql

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

และเพิ่มใน Dockerfile ของคุณ:

Dockerfile

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

แต่ตั้งแต่ 8 กรกฎาคม 2015, ถ้าทั้งหมดที่คุณต้องการก็คือการสร้างผู้ใช้และฐานข้อมูลมันเป็นเรื่องง่ายที่จะทำให้การใช้งานเพียงแค่ไปPOSTGRES_USER, POSTGRES_PASSWORDและPOSTGRES_DBตัวแปรสภาพแวดล้อม:

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

หรือกับ Dockerfile:

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

สำหรับรูปภาพที่เก่ากว่า 23 กรกฎาคม 2015

จากเอกสารของอิมเมจ Docker postgresได้มีการกล่าวไว้ว่า

[... ] มันจะแหล่งสคริปต์ * .sh ใด ๆ ที่พบในไดเรกทอรีนั้น [ /docker-entrypoint-initdb.d] เพื่อทำการเริ่มต้นต่อไปก่อนที่จะเริ่มบริการ

สิ่งที่สำคัญที่นี่คือ"ก่อนที่จะเริ่มให้บริการ" ซึ่งหมายความว่าสคริปต์ของคุณmake_db.shจะถูกดำเนินการก่อนที่จะบริการ Postgres จะเริ่มต้นจึงเกิดข้อผิดพลาด"ไม่สามารถเชื่อมต่อกับฐานข้อมูล Postgres"

หลังจากนั้นมีข้อมูลที่เป็นประโยชน์อีกชิ้นหนึ่ง:

หากคุณต้องการดำเนินการคำสั่ง SQL เป็นส่วนหนึ่งของการเริ่มต้นของคุณแนะนำให้ใช้โหมดผู้ใช้คนเดียวของ Postgres

ตกลงนี้อาจเป็นบิตลึกลับที่ดูครั้งแรก สิ่งที่กล่าวคือสคริปต์การเริ่มต้นของคุณควรเริ่มบริการ postgres ในโหมดเดียวก่อนที่จะดำเนินการ ดังนั้นคุณสามารถเปลี่ยนสคริปต์make_db.kshของคุณดังต่อไปนี้และควรทำให้คุณใกล้ชิดกับสิ่งที่คุณต้องการ:

หมายเหตุนี้มีการเปลี่ยนแปลงเมื่อเร็ว ๆ นี้ในต่อไปกระทำ สิ่งนี้จะทำงานกับการเปลี่ยนแปลงล่าสุด:

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

ก่อนหน้านี้--singleจำเป็นต้องใช้โหมด:

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

2
คุณสามารถ:gosu postgres postgres --single < /tmp/somefile.sql
Thomasleveil

1
ฉันจะวิ่งได้อย่างไรpsql -U myDb -d myDb -f myDb.sql
DarVar

3
หมายเหตุ - Single ไม่ได้รับการสนับสนุนใน Postgres Dockerfiles ใด ๆ อีกต่อไป
brianz

1
ฉันทำตามขั้นตอนและเมื่อฉัน ssh ลงในภาชนะ mysql และ cd เข้าdocker-entrypoint-initdb.dฉันเห็นของฉันinit.sqlด้วยรหัส sql ในนั้น แต่เมื่อฉันเปิด mysql (โดยใช้การเข้าถึงรูท) และพิมพ์ฐานข้อมูลแสดงฉันเห็นเฉพาะค่าเริ่มต้นจากdocker-compose.ymlไฟล์! ทำไมมันไม่ทำงานสำหรับฉัน
Mahmoud Zalt

1
มันไม่ได้ดำเนินการdb.sqlแม้หลังจากที่มันถูกคัดลอกไปยัง `docker-entrypoint-initdb.d`
kamal

16

ตอนนี้คุณสามารถวางไฟล์. sql ไว้ในไดเรกทอรี init:

จากเอกสาร

หากคุณต้องการเริ่มต้นเพิ่มเติมในภาพที่ได้รับจากภาพนี้ให้เพิ่มหนึ่งสคริปต์ขึ้นไป * .sql หรือ * .sh ภายใต้ /docker-entrypoint-initdb.d (สร้างไดเรกทอรีหากจำเป็น) หลังจาก entrypoint เรียกใช้ initdb เพื่อสร้างผู้ใช้ postgres เริ่มต้นและฐานข้อมูลมันจะเรียกใช้ไฟล์ * .sql ใด ๆ และซอร์สสคริปต์ * .sh ใด ๆ ที่พบในไดเรกทอรีนั้นเพื่อทำการเริ่มต้นเพิ่มเติมก่อนเริ่มบริการ

ดังนั้นการคัดลอกไฟล์. sql ของคุณจะทำงานได้


ตัวแปรสภาวะแวดล้อมสำหรับผู้ใช้ / รหัสผ่านและการสร้าง db ยังคงทำงานอยู่ (9.5.3)
Jeremiah Adams

1
ฉันมีโครงการที่ใช้งานได้ในท้องถิ่น อย่างไรก็ตามเมื่อฉันย้ายไปยัง AWS EC2 จะมีข้อความระบุว่าไม่พบ DB ฉันคัดลอกไฟล์. sql ในไดเรกทอรีที่เหมาะสม แต่ก็ยังส่งคืนข้อผิดพลาดนั้น ความคิดใดที่ฉันสามารถมอง? ฉันใหม่สำหรับนักเทียบท่า
MadPhysicist

1
สิ่งนี้เป็นจริงหากมีอินสแตนซ์ db เดียวที่ถูกผูกไว้กับโวลุ่มเดียวนั่นคือจะไม่เรียกใช้สคริปต์ใด ๆ หากมีสิ่งใดอยู่ในโฟลเดอร์วอลุ่ม สิ่งนี้ทำให้ฉันปวดหัวเพราะฉันต้องการมี initializers db แยกต่างหากสำหรับแต่ละบริการ stack ของฉัน
สีม่วงแดง

จากเอกสาร 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

โดยใช้docker-compose:

สมมติว่าคุณมีเค้าโครงไดเรกทอรีดังต่อไปนี้:

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

ไฟล์: docker-compose.yml

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

ไฟล์: 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;

ไฟล์: Docker/db.Dockerfile

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

บริการการเขียนและการเริ่มต้น:

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

8

ฉันเพิ่มคำสั่งที่กำหนดเองให้กับสภาพแวดล้อมที่ปรากฏใน CMD หลังจากเริ่มบริการ ... ฉันยังไม่ได้ทำกับ postgres แต่ใช้ 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

และเริ่มต้นด้วย

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

.


7

คุณสามารถใช้คำสั่งนี้:

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'แปลกมาก ... คุณต้องมีความต้องการเป็นพิเศษเพื่อหลีกเลี่ยงการใช้ utf8
Zyigh

4

คุณต้องให้ฐานข้อมูลทำงานก่อนที่คุณจะสร้างผู้ใช้ สำหรับสิ่งนี้คุณต้องมีกระบวนการหลายอย่าง คุณสามารถเริ่ม postgres ใน subshell (&) ในเชลล์สคริปต์หรือใช้เครื่องมือเช่น supervisord เพื่อรัน postgres แล้วเรียกใช้สคริปต์การเริ่มต้นใด ๆ

คำแนะนำสำหรับ supervisord และนักเทียบท่าhttps://docs.docker.com/articles/using_supervisord/


2

ด้วยนักเทียบท่าเขียนมีทางเลือกง่าย ๆ (ไม่จำเป็นต้องสร้าง Dockerfile) เพียงสร้าง 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

และอ้างอิงในส่วนเล่ม:

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:
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.