Я пытаюсь создать образ контейнера на основе официального изображения postgres + моей схемы БД, которая в настоящее время определяется как XML-файлы Liquibase.
Вот как выглядит мой Dockerfile:
FROM postgres:13.1
ENV POSTGRES_USER=myuser
ENV POSTGRES_PASSWORD=mypass
ENV POSTGRES_DB=mydb
# Copy the DB and user creation script which will then be automatically executed during the DB creation
ADD ./db_init.sql /docker-entrypoint-initdb.d/
# Temporary copy liquibase
ADD ./liquibase/ /liquibase/
# Copy and extract OpenJDK for liquibase
ADD ./openjdk-11+28_linux-x64_bin.tar.gz /liquibase/
ENV JAVA_HOME=/liquibase/jdk-11
# Copy the changelog for the creation of the schema
ADD ./changelog/liquibase/ /liquibase/
# Execute liquibase
RUN /liquibase/liquibase --changeLogFile=/changelog/liquibase/index.xml --url=jdbc:postgresql://localhost:5432/$POSTGRES_DB --username=$POSTGRES_USER --password=$POSTGRES_PASSWORD --logLevel=info update
RUN rm -rf /liquibase
USER postgres
Сборка завершается с ошибкой:
[2020-12-15 10:37:23] SEVERE [liquibase.integration] Unexpected error running Liquibase: liquibase.exception.DatabaseException: liquibase.exception.DatabaseException: Connection could not be created to jdbc:postgresql://localhost:5432/sisdb with driver org.postgresql.Driver. Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
liquibase.exception.DatabaseException: liquibase.exception.DatabaseException: liquibase.exception.DatabaseException: liquibase.exception.DatabaseException: Connection could not be created to jdbc:postgresql://localhost:5432/sisdb with driver org.postgresql.Driver. Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
at liquibase.integration.commandline.CommandLineUtils.createDatabaseObject(CommandLineUtils.java:131)
at liquibase.integration.commandline.Main.doMigration(Main.java:1409)
at liquibase.integration.commandline.Main$1.lambda$run$0(Main.java:361)
at liquibase.Scope.lambda$child$0(Scope.java:160)
at liquibase.Scope.child(Scope.java:169)
at liquibase.Scope.child(Scope.java:159)
at liquibase.Scope.child(Scope.java:138)
at liquibase.Scope.child(Scope.java:222)
at liquibase.Scope.child(Scope.java:226)
at liquibase.integration.commandline.Main$1.run(Main.java:360)
at liquibase.integration.commandline.Main$1.run(Main.java:193)
at liquibase.Scope.child(Scope.java:169)
at liquibase.Scope.child(Scope.java:145)
at liquibase.integration.commandline.Main.run(Main.java:193)
at liquibase.integration.commandline.Main.main(Main.java:156)
Caused by: liquibase.exception.DatabaseException: liquibase.exception.DatabaseException: liquibase.exception.DatabaseException: Connection could not be created to jdbc:postgresql://localhost:5432/sisdb with driver org.postgresql.Driver. Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
at liquibase.database.DatabaseFactory.openConnection(DatabaseFactory.java:216)
at liquibase.database.DatabaseFactory.openConnection(DatabaseFactory.java:175)
at liquibase.database.DatabaseFactory.openDatabase(DatabaseFactory.java:140)
at liquibase.integration.commandline.CommandLineUtils.createDatabaseObject(CommandLineUtils.java:96)
... 14 more
Caused by: liquibase.exception.DatabaseException: liquibase.exception.DatabaseException: Connection could not be created to jdbc:postgresql://localhost:5432/sisdb with driver org.postgresql.Driver. Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
at liquibase.database.ConnectionServiceFactory.create(ConnectionServiceFactory.java:36)
at liquibase.database.DatabaseFactory.openConnection(DatabaseFactory.java:213)
... 17 more
Caused by: liquibase.exception.DatabaseException: Connection could not be created to jdbc:postgresql://localhost:5432/sisdb with driver org.postgresql.Driver. Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
at liquibase.database.jvm.JdbcConnection.open(JdbcConnection.java:43)
at com.datical.liquibase.ext.database.jvm.ProJdbcConnection.open(Unknown Source)
at liquibase.database.ConnectionServiceFactory.create(ConnectionServiceFactory.java:33)
... 18 more
Что я делаю не так? На данный момент база данных еще не готова принимать подключения? Придется ли мне запускать liquibase только после запуска контейнера? Если да, то есть ли руководство по передовой практике для такого потока?
Внутри Dockerfile вы никогда не сможете подключиться к базе данных. Если вы пытаетесь расширить образ базы данных, база данных никогда не запускается во время последовательности docker build
; если база данных находится в отдельном контейнере, никакие сетевые настройки сборки для вызова базы данных не выполнялись. Стандартные образы базы данных Docker Hub также настроены таким образом, что не допускается создание образа с предварительно загруженными данными.
Такие средства миграции, как Liquibase, обычно поставляются вместе с приложением, а не с базой данных. Например, если ваше приложение создано с использованием Spring Boot, оно поддерживает Выполнение миграции базы данных Liquibase при запуске.
Если вам нужно выполнить миграцию с использованием механики Docker, один из шаблонов — использовать скрипт-оболочку точки входа, чтобы сделать это при запуске вашего контейнера. Образ вашего приложения должен включать Liquibase, как показано здесь. Пусть скрипт запускает команду liquibase
, а затем exec "$@"
для запуска основного приложения-контейнера; COPY
вставьте его в свое изображение и сделайте его ENTRYPOINT
(необходимо использовать синтаксис массива JSON), а CMD java -jar ...
оставьте как есть. (Вы можете поискать похожие примеры, используя фреймворк Python Django.)
Спасибо за подробный ответ Давид!! Я закончил тем, что создал файл дампа sql через liquibase, а затем поместил его в предопределенный каталог в образе PG, из которого PG автоматически выполнил сценарии при первом запуске контейнера.