如何创建用户/数据库在脚本Docker Postgres

我一直试图通过创建一个自定义用户为开发postgres实例设置一个容器;数据库。我正在使用官方postgres docker图片。在文档中,它指导您在/docker-entrypoint-initdb.d/文件夹中插入bash脚本,以使用任何自定义参数设置数据库。

我的bash脚本: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是我的容器名)得到的错误是:

postgres:不能连接到服务器:没有这样的文件或目录

似乎在postgres启动之前,/docker-entrypoint-initdb.d/文件夹中的命令正在执行。我的问题是,如何使用官方postgres容器以编程方式设置用户/数据库?有什么方法可以用脚本来做到这一点吗?

406613 次浏览

在创建用户之前,需要运行数据库。为此,您需要多个进程。您可以在shell脚本中的子shell (&)中启动postgres,或者使用类似于supervisor ord的工具来运行postgres,然后运行任何初始化脚本。

superord和docker https://docs.docker.com/articles/using_supervisord/的指南

编辑-自2015年7月23日

官方postgres docker图片将运行在/docker-entrypoint-initdb.d/文件夹中的.sql脚本。

所以你所需要的就是创建下面的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/

但是从2015年7月8日起,如果您所需要的只是创建一个用户和数据库,使用POSTGRES_USERPOSTGRES_PASSWORDPOSTGRES_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

适用于2015年7月23日之后的图片

postgres Docker镜像的文档中,有人说

[…在启动服务之前,它会在该目录[/docker-entrypoint-initdb.d]中找到任何*.sh脚本来做进一步的初始化

这里重要的是"在开始服务前"。这意味着你的脚本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

我将自定义命令添加到启动服务后在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>

你现在可以把.sql文件放在init目录中:

From docs .

如果您想在此图像派生的图像中进行额外的初始化,请添加一个或多个*。/docker-entrypoint-initdb下的SQL或*.sh脚本。D(如果需要,创建目录)。在入口点调用initdb创建默认的postgres用户和数据库之后,它将运行任何*。SQL文件和源目录中找到的任何*.sh脚本,在启动服务之前进行进一步的初始化。

所以复制你的.sql文件就可以了。

您可以使用以下命令:

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;"

通过使用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

使用docker compose有一个简单的替代方案(不需要创建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:

使用Postgres最新的镜像(ID: b262c8b2fb54)和Docker 20.10.6版本,Docker -compose看起来是这样的:

version: '2'


services:
app:
# the detail of app
db:
image: 'postgres'
container_name: book-shop-db-postgres
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=bookshop-db

这将创建启动时提到的用户和数据库

这是我的docke-compose.yml

   postgres:
image: postgres:latest
ports:
- 5432:5432
volumes:
- postgres_data:/var/lib/postgresql/data
- ${PROJECTDIR}/init.sql:/docker-entrypoint-initdb.d/1-schema.sql
environment:
- POSTGRES_USER=postgres
- POSTGRES_DB=postgres
- POSTGRES_PASSWORD=postgres

这里有两件事你需要考虑:

  1. docker-entrypoint-initdb.d仅在数据字典为空时才有效。所以如果你有卷,一定要删除它们docker-compose down --volumes

  2. init.sql而不是docke-compose.yml中创建用户和数据库。在docker-compose.yml中,你应该指定postgres用户。