Cách tạo Người dùng / Cơ sở dữ liệu trong tập lệnh cho Docker Postgres


213

Tôi đã cố gắng thiết lập một thùng chứa cho một cá thể postgres phát triển bằng cách tạo một người dùng và cơ sở dữ liệu tùy chỉnh. Tôi đang sử dụng hình ảnh docker postgres chính thức . Trong tài liệu hướng dẫn, bạn sẽ chèn một tập lệnh bash bên trong /docker-entrypoint-initdb.d/thư mục để thiết lập cơ sở dữ liệu với bất kỳ tham số tùy chỉnh nào.

Tập lệnh bash của tôi: 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ỗi tôi nhận được từ docker logs -f db(db là tên container của tôi) là:

người tạo: không thể kết nối với cơ sở dữ liệu postgres: không thể kết nối với máy chủ: Không có tệp hoặc thư mục như vậy

Có vẻ như các lệnh bên trong /docker-entrypoint-initdb.d/thư mục đang được thực thi trước khi postgres được bắt đầu. Câu hỏi của tôi là, làm cách nào để thiết lập một người dùng / cơ sở dữ liệu theo chương trình bằng cách sử dụng bộ chứa postgres chính thức? Có cách nào để làm điều này với một kịch bản?

Câu trả lời:


378

EDIT - kể từ ngày 23 tháng 7 năm 2015

Các hình ảnh postgres Docker chính thức sẽ chạy .sqlscript tìm thấy trong /docker-entrypoint-initdb.d/thư mục.

Vì vậy, tất cả những gì bạn cần là tạo tập lệnh sql sau:

init.sql

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

và thêm nó vào Dockerfile của bạn:

Dockerfile

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

Nhưng kể từ ngày 08 tháng bảy năm 2015, nếu tất cả các bạn cần là để tạo ra một người sử dụng và cơ sở dữ liệu , nó là dễ dàng hơn để chỉ làm cho sử dụng đến POSTGRES_USER, POSTGRES_PASSWORDPOSTGRES_DBcác biến môi trường:

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

hoặc với Dockerfile:

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

cho hình ảnh cũ hơn ngày 23 tháng 7 năm 2015

Từ tài liệu của hình ảnh Docker postgres , người ta nói rằng

[...] Nó sẽ lấy bất kỳ tập lệnh * .sh nào được tìm thấy trong thư mục đó [ /docker-entrypoint-initdb.d] để thực hiện khởi tạo thêm trước khi bắt đầu dịch vụ

Điều quan trọng ở đây là "trước khi bắt đầu dịch vụ" . Điều này có nghĩa là tập lệnh make_db.sh của bạn sẽ được thực thi trước khi dịch vụ postgres được khởi động, do đó thông báo lỗi "không thể kết nối với postgres cơ sở dữ liệu" .

Sau đó, có một thông tin hữu ích khác:

Nếu bạn cần thực thi các lệnh SQL như là một phần của việc khởi tạo, việc sử dụng chế độ người dùng đơn Postgres rất được khuyến khích.

Đồng ý điều này có thể là một chút bí ẩn ở cái nhìn đầu tiên. Những gì nó nói là tập lệnh khởi tạo của bạn sẽ bắt đầu dịch vụ postgres ở chế độ đơn trước khi thực hiện hành động của nó. Vì vậy, bạn có thể thay đổi make_db.ksh tập lệnh như sau và nó sẽ giúp bạn đến gần hơn với những gì bạn muốn:

LƯU Ý , điều này đã thay đổi gần đây trong cam kết sau đây . Điều này sẽ làm việc với sự thay đổi mới nhất:

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

Trước đây, việc sử dụng --singlechế độ là bắt buộc:

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

2
bạn có thể với:gosu postgres postgres --single < /tmp/somefile.sql
Thomasleveil

1
Làm thế nào tôi có thể chạypsql -U myDb -d myDb -f myDb.sql
DarVar

3
Lưu ý, --single không còn được hỗ trợ trong bất kỳ Dockerfiles postgres nào.
brianz

1
Tôi đã làm theo các bước và khi tôi ssh vào thùng chứa mysql và cd vào docker-entrypoint-initdb.dtôi thấy tôi init.sqlcó mã sql trong đó. NHƯNG khi tôi mở mysql (sử dụng quyền truy cập root) và gõ cơ sở dữ liệu hiển thị, tôi chỉ thấy mặc định từ docker-compose.ymltệp! Tại sao nó không làm việc cho tôi?
Mahmoud Zalt

1
Nó không thực thi db.sqlngay cả sau khi nó được sao chép vào `docker-entrypoint-initdb.d`
kamal

16

Bây giờ bạn có thể đặt các tệp .sql trong thư mục init:

Từ các tài liệu

Nếu bạn muốn thực hiện khởi tạo bổ sung trong một hình ảnh xuất phát từ hình ảnh này, hãy thêm một hoặc nhiều tập lệnh * .sql hoặc * .sh trong /docker-entrypoint-initdb.d (tạo thư mục nếu cần). Sau khi entrypoint gọi initdb để tạo cơ sở dữ liệu và người dùng postgres mặc định, nó sẽ chạy bất kỳ tệp * .sql nào và lấy bất kỳ tập lệnh * .sh nào được tìm thấy trong thư mục đó để thực hiện khởi tạo thêm trước khi bắt đầu dịch vụ.

Vì vậy, sao chép tập tin .sql của bạn sẽ hoạt động.


các biến môi trường cho người dùng / mật khẩu và tạo db vẫn hoạt động. (9.5.3)
Jeremiah Adams

1
Tôi có một dự án làm việc tại địa phương. Tuy nhiên, khi tôi chuyển nó sang AWS EC2, nó nói rằng DB không được tìm thấy. Tôi sao chép tệp .sql trong thư mục thích hợp, nhưng nó vẫn trả về lỗi đó. Bất cứ ý tưởng nơi tôi có thể nhìn? Tôi mới đến Docker.
MadPhysicist

1
Điều này chỉ đúng nếu có một cá thể db duy nhất được liên kết với một ổ đĩa, tức là nó sẽ không chạy bất kỳ tập lệnh nào nếu có bất cứ thứ gì đã có trong thư mục ổ đĩa. Điều này khiến tôi đau đầu, vì tôi muốn có một trình khởi tạo db riêng cho mỗi dịch vụ ngăn xếp của mình.
Violet Đỏ

9

Bằng cách sử dụng docker-compose:

Giả sử rằng bạn có bố cục thư mục sau:

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

Tập tin: docker-compose.yml

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

Tập tin: 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;

Tập tin: Docker/db.Dockerfile

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

Sáng tác và bắt đầu dịch vụ:

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

8

Tôi thêm các lệnh tùy chỉnh vào một môi trường được gợi lên trong một CMD sau khi bắt đầu dịch vụ ... Tôi đã không thực hiện nó với postgres, nhưng với 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

và bắt đầu với

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

.


7

Bạn có thể sử dụng các lệnh này:

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'là rất kỳ lạ ... Bạn phải có những nhu cầu rất đặc biệt để tránh sử dụng utf8
Zyigh

4

Bạn cần phải có cơ sở dữ liệu chạy trước khi bạn tạo người dùng. Đối với điều này, bạn cần nhiều quá trình. Bạn có thể bắt đầu postgres trong một subshell (&) trong tập lệnh shell hoặc sử dụng một công cụ như giám sát để chạy postgres và sau đó chạy bất kỳ tập lệnh khởi tạo nào.

Hướng dẫn về giám sát và docker https://docs.docker.com/articles/USE_supervisord/


2

Với docker soạn có một cách thay thế đơn giản (không cần tạo Dockerfile). Chỉ cần tạo 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

Và tham khảo nó trong phần tập:

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:
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.