Подтвердить что ты не робот

Запуск и заполнение контейнера Postgres в Docker

У меня есть контейнер Docker, содержащий мою базу данных Postgres. Он использует официальное изображение Postgres, в котором есть запись CMD, которая запускает сервер в основном потоке.

Я хочу заполнить базу данных, запустив RUN psql –U postgres postgres < /dump/dump.sql, прежде чем она начнет прослушивать запросы.

Я не понимаю, как это возможно с Docker. Если я поместил команду RUN после CMD, она, конечно, никогда не будет достигнута, потому что Docker закончил чтение файла Docker. Но если я поместил его перед CMD, он будет работать до того, как psql будет существовать как процесс.

Как я могу предварительно заполнить базу данных Postgres в Docker?

4b9b3361

Ответ 1

После долгих боев я нашел решение ;-)

Для меня был очень полезен комментарий, размещенный здесь: https://registry.hub.docker.com/_/postgres/ от "justfalter"

Во всяком случае, я сделал так:

# 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

Надеюсь, поможет!

Ответ 2

Кроме того, вы можете просто подключить том к /docker -entrypoint-initdb.d/, который содержит все ваши DDL-скрипты. Вы можете поместить файлы *. Sh, *.sql или *.sql.gz, и он позаботится об их запуске.

например. (предполагая, что у вас есть ваши скрипты в /tmp/my _scripts)

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

Ответ 3

Для тех, кто хочет инициализировать базу данных postgres с миллионами записей во время первого запуска.

Импорт с использованием *.sql dump

Вы можете сделать простой SQL дамп и скопировать dump.sql файл в /docker-entrypoint-initdb.d/. Проблема в скорости. Мой сценарий dump.sql занимает около 17 МБ (небольшая БД - 10 таблиц, по 100 000 строк только в одной из них), и инициализация занимает более минуты (!). Это неприемлемо для локальной разработки/модульного тестирования и т.д.

Импорт с использованием двоичного дампа

Решение состоит в том, чтобы сделать двоичный дамп postgres и использовать поддержку инициализации сценариев оболочки. Затем эта же БД инициализируется как 500 мс вместо 1 минуты :)

1. Создайте двоичный дамп dump.pgdata для БД с именем "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. Создайте образ докера с заданным скриптом дампа и инициализации

$ 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. Создайте образ и запустите его

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

Ответ 4

Есть еще один доступный вариант, который использует Flocker:

Flocker - это диспетчер томов контейнерных данных, который позволяет легко создавать базы данных, такие как PostgreSQL, в контейнерах на производстве. При запуске базы данных на производстве вы должны думать о таких вещах, как восстановление после сбоя хоста. Flocker предоставляет инструменты для управления томами данных в кластере машин, как в рабочей среде. Например, поскольку контейнер Postgres запланирован между хостами в ответ на сбой сервера, Flocker может автоматически перемещать свой связанный объем данных между хостами одновременно. Это означает, что когда ваш Postgres-контейнер запускается на новом хосте, он имеет свои данные. Эту операцию можно выполнить вручную с помощью Flocker API или CLI или автоматически с помощью инструмента для сопоставления контейнеров, с которым Flocker интегрируется, например, Docker Swarm, Kubernetes или Mesos.

Ответ 5

Мне удалось загрузить данные, предварительно запустив команду run в файле докеров с помощью /etc/init.d/postgresql. Мой файл докеров имеет следующую строку, которая работает для меня:

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

Ответ 6

Я следовал тому же решению, что и @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