在Docker中启动并填充Postgres容器

问题描述 投票:37回答:6

我有一个包含Postgres数据库的Docker容器。它使用官方的Postgres image,它有一个CMD条目,可以在主线程上启动服务器。

我想在开始收听查询之前运行RUN psql –U postgres postgres < /dump/dump.sql来填充数据库。

我不明白Docker如何实现这一点。如果我在CMD之后放置RUN命令,它当然永远不会被访问,因为Docker已经完成了对Dockerfile的读取。但是如果我把它放在CMD之前,它将在psql甚至作为一个进程存在之前运行。

如何在Docker中预填充Postgres数据库?

database postgresql docker
6个回答
44
投票

经过大量的战斗,我找到了解决方案;-)

对我来说非常有用,这里发表评论:来自“justfalter”的https://registry.hub.docker.com/_/postgres/

无论如何,我这样做了:

# Dockerfile
FROM postgres:9.4

RUN mkdir -p /tmp/psql_data/

COPY db/structure.sql /tmp/psql_data/
COPY scripts/init_docker_postgres.sh /docker-entrypoint-initdb.d/

db/structure.sql是一个sql转储,用于初始化第一个表空间。

然后,init_docker_postgres.sh

#!/bin/bash

# this script is run when the docker container is built
# it imports the base database structure and create the database for the tests

DATABASE_NAME="db_name"
DB_DUMP_LOCATION="/tmp/psql_data/structure.sql"

echo "*** CREATING DATABASE ***"

# create default database
gosu postgres postgres --single <<EOSQL
  CREATE DATABASE "$DATABASE_NAME";
  GRANT ALL PRIVILEGES ON DATABASE "$DATABASE_NAME" TO postgres;
EOSQL

# clean sql_dump - because I want to have a one-line command

# remove indentation
sed "s/^[ \t]*//" -i "$DB_DUMP_LOCATION"

# remove comments
sed '/^--/ d' -i "$DB_DUMP_LOCATION"

# remove new lines
sed ':a;N;$!ba;s/\n/ /g' -i "$DB_DUMP_LOCATION"

# remove other spaces
sed 's/  */ /g' -i "$DB_DUMP_LOCATION"

# remove firsts line spaces
sed 's/^ *//' -i "$DB_DUMP_LOCATION"

# append new line at the end (suggested by @Nicola Ferraro)
sed -e '$a\' -i "$DB_DUMP_LOCATION"

# import sql_dump
gosu postgres postgres --single "$DATABASE_NAME" < "$DB_DUMP_LOCATION";


echo "*** DATABASE CREATED! ***"

最后:

# no postgres is running
[myserver]# psql -h 127.0.0.1 -U postgres
psql: could not connect to server: Connection refused
    Is the server running on host "127.0.0.1" and accepting
    TCP/IP connections on port 5432?

[myserver]# docker build -t custom_psql .
[myserver]# docker run -d --name custom_psql_running -p 5432:5432 custom_psql

[myserver]# docker ps -a
CONTAINER ID        IMAGE                COMMAND                CREATED             STATUS              PORTS                    NAMES
ce4212697372        custom_psql:latest   "/docker-entrypoint.   9 minutes ago       Up 9 minutes        0.0.0.0:5432->5432/tcp   custom_psql_running

[myserver]# psql -h 127.0.0.1 -U postgres
psql (9.2.10, server 9.4.1)
WARNING: psql version 9.2, server version 9.4.
         Some psql features might not work.
Type "help" for help.

postgres=# 

# postgres is now initialized with the dump

希望能帮助到你!


25
投票

或者,您可以将卷装入包含所有DDL脚本的/docker-entrypoint-initdb.d/。您可以输入* .sh,* .sql或* .sql.gz文件,它将负责在启动时执行这些文件。

例如(假设你的脚本在/ tmp / my_scripts中)

docker run -v /tmp/my_scripts:/docker-entrypoint-initdb.d postgres

12
投票

For those who want to initialize postgres DB with millions of records during first run.

Import using *.sql dump

你可以做简单的sql转储并将dump.sql文件复制到/docker-entrypoint-initdb.d/。问题是速度。我的dump.sql脚本大约是17MB(小DB - 10个表,其中只有一个有100k行),初始化需要一分钟(!)。这对于当地开发/单元测试等是不可接受的。

Import using binary dump

解决方案是制作二进制postgres转储并使用shell scripts initialization support。然后相同的DB初始化为500ms而不是1分钟:)

1. Create the dump.pgdata binary dump of DB named "my-db"

直接来自容器或本地数据库

pg_dump -U postgres --format custom my-db > "dump.pgdata"

或者来自运行容器的主机(postgres-container)

docker exec postgres-container pg_dump -U postgres --format custom my-db > "dump.pgdata"

2. Create docker image with given dump and initialization script

$ tree
.
├── Dockerfile
└── docker-entrypoint-initdb.d
    ├── 01-restore.sh
    ├── 02-updates.sql
    └── dump.pgdata
$ cat Dockerfile
FROM postgres:11

COPY ./docker-entrypoint-initdb.d/ /docker-entrypoint-initdb.d/
$ cat docker-entrypoint-initdb.d/01-restore.sh
#!/bin/bash

file="/docker-entrypoint-initdb.d/dump.pgdata"
dbname=my-db

echo "Restoring DB using $file"
pg_restore -U postgres --dbname=$dbname --verbose --single-transaction < "$file" || exit 1
$ cat docker-entrypoint-initdb.d/02-updates.sql
-- some updates on your DB, for example for next application version
-- this file will be executed on DB during next release
UPDATE ... ;

3. Build image and run it

$ docker build -t db-test-img .
$ docker run -it --rm --name db-test db-test-img

1
投票

utilises Flocker还有另一种选择:

Flocker是一个容器数据卷管理器,旨在允许像PostgreSQL这样的数据库轻松地在生产中的容器中运行。在生产中运行数据库时,您必须考虑从主机故障中恢复等问题。 Flocker提供了一种工具,用于管理生产环境中的机器群集中的数据量。例如,由于Postgres容器是在主机之间调度以响应服务器故障,因此Flocker可以同时在主机之间自动移动其关联的数据卷。这意味着当您的Postgres容器在新主机上启动时,它会拥有其数据。此操作可以使用Flocker API或CLI手动完成,也可以由Flocker集成的容器编排工具自动完成,例如Docker Swarm,Kubernetes或Mesos。


0
投票

我可以通过/etc/init.d/postgresql预先挂起docker文件中的run命令来加载数据。我的docker文件有以下行,它对我有用:

RUN /etc/init.d/postgresql start && /usr/bin/psql -a < /tmp/dump.sql

0
投票

我遵循@damoiser的相同解决方案,唯一不同的情况是我想导入所有转储数据。

请按照下面的解决方案。(我没有做过任何检查)

Dockerfile

FROM postgres:9.5

RUN mkdir -p /tmp/psql_data/

COPY db/structure.sql /tmp/psql_data/
COPY scripts/init_docker_postgres.sh /docker-entrypoint-initdb.d/

然后是doker-entrypoint-initdb.d脚本

#!/bin/bash

DB_DUMP_LOCATION="/tmp/psql_data/structure.sql"

echo "*** CREATING DATABASE ***"

psql -U postgres < "$DB_DUMP_LOCATION";

echo "*** DATABASE CREATED! ***"

然后你可以建立你的形象

docker build -t abhije***/postgres-data .

docker run -d abhije***/postgres-data 
© www.soinside.com 2019 - 2024. All rights reserved.