我一直在尝试通过创建自定义用户 & 来为开发 postgres 实例设置一个容器。数据库。我正在使用 official postgres docker image。在文档中,它指示您在 /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 是我的容器名称)得到的错误是:
createuser:无法连接到数据库 postgres:无法连接到服务器:没有这样的文件或目录
似乎 /docker-entrypoint-initdb.d/
文件夹内的命令在 postgres 启动之前正在执行。我的问题是,如何使用官方的 postgres 容器以编程方式设置用户/数据库?有没有办法用脚本做到这一点?
编辑 - 自 2015 年 7 月 23 日起
official postgres docker image 将运行 /docker-entrypoint-initdb.d/
文件夹中的 .sql
脚本。
因此,您只需要创建以下 sql 脚本:
初始化.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_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
适用于 2015 年 7 月 23 日之前的图片
从the documentation of the postgres Docker image,据说
[...] 它将获取在该目录 [/docker-entrypoint-initdb.d] 中找到的任何 *.sh 脚本,以便在启动服务之前进行进一步的初始化
这里重要的是“在启动服务之前”。这意味着您的脚本 make_db.sh 将在 postgres 服务启动之前执行,因此错误消息“无法连接到数据库 postgres”。
之后还有另一个有用的信息:
如果您需要在初始化过程中执行 SQL 命令,强烈建议使用 Postgres 单用户模式。
同意这乍一看可能有点神秘。它说的是您的初始化脚本应该在执行其操作之前以单一模式启动 postgres 服务。所以你可以改变你的 make_db.ksh 脚本如下,它应该让你更接近你想要的:
注意,最近发生了变化in the following commit。这将适用于最新的更改:
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
通过使用 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:
chmod 755 ./init-datbase.sh
使本地 ./init-database.sh
可执行的一件事。
POSTGRES_PASSWORD
。为什么在 init-database.sh
中不使用它(而 POSTGRES_USER
是)?
您可以使用以下命令:
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;"
ENCODING 'LATIN1'
很奇怪...您必须有非常特殊的需求来避免使用 utf8
您现在可以将 .sql 文件放入 init 目录中:
如果您想在从该镜像派生的镜像中进行额外的初始化,请在 /docker-entrypoint-initdb.d 下添加一个或多个 *.sql 或 *.sh 脚本(必要时创建目录)。在入口点调用 initdb 以创建默认的 postgres 用户和数据库后,它将运行任何 *.sql 文件并获取在该目录中找到的任何 *.sh 脚本,以在启动服务之前进行进一步的初始化。
所以复制你的 .sql 文件就可以了。
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.
我在启动服务后将自定义命令添加到在 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>
.
使用 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
这将创建启动时提到的用户和数据库
在创建用户之前,您需要运行数据库。为此,您需要多个进程。您可以在 shell 脚本的子 shell (&) 中启动 postgres,或者使用像 supervisord 这样的工具来运行 postgres,然后运行任何初始化脚本。
supervisord 和 docker https://docs.docker.com/articles/using_supervisord/ 指南
RUN service postgresql start ; su - postgres -c "psql -c \"CREATE USER test WITH PASSWORD 'test' CREATEDB\"" ; service postgresql stop
gosu postgres postgres --single < /tmp/somefile.sql
psql -U myDb -d myDb -f myDb.sql
/docker-entrypoint-initdb.d
中的脚本仅在您使用 为空的数据目录启动容器时运行我>。