วิธีสร้างผู้ใช้ / ฐานข้อมูลในสคริปต์สำหรับ 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.