Starting situation: I am building a REST-Service with Spring Boot and Maven. This REST-Service is writing to a Postgres database. Both components are dockerized and configured through the following docker-compose.yml (I use a .env file to isolate the confidential and repeated information. ${DB_Name} evaluates to "Taskitory".):
version: "0.0.1"
services:
db:
container_name: taskitory-db
image: postgres:14.1
environment:
- POSTGRES_DB=${DB_NAME}
- POSTGRES_USER=${DB_ADMIN_USER}
- POSTGRES_PASSWORD=${DB_ADMIN_PW}
- PGDATA=/data/postgres
volumes:
- ./postgres-volume:/data
networks:
- taskitory-net
ports:
- "60000:5432"
restart: unless-stopped
backend:
container_name: taskitory-backend
build: .
networks:
- taskitory-net
ports:
- "80:8080"
depends_on:
- db
networks:
taskitory-net:
driver: bridge
As I'm using Spring Boot with Maven and Java for my REST-Service, I use JPA and Hibernate for writing to my database. The config for accessing the db is located in the application.properties of my Spring Boot project:
server.port = 8080
logging.level.jdbc = OFF
logging.level.jdbc.sqltiming = DEBUG
logging.level.jdbc.resultsettable = DEBUG
spring.datasource.driver-class-name = org.postgresql.Driver
spring.datasource.url = jdbc:postgresql://${DB_ADDR_ALIAS}:${DB_PORT}/${DB_NAME}
spring.datasource.username = ${DB_CLIENT_USER}
spring.datasource.password = ${DB_CLIENT_PW}
spring.datasource.hikari.max-lifetime = 600000
spring.datasource.testWhileIdle = true
spring.datasource.test-on-borrow = true
spring.datasource.hikari.schema = backend
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto = validate
I use the variables from the .env file in the application.properties too. Therefore the spring.datasource.url evaluates from "jdbc:postgresql://${DB_ADDR_ALIAS}:${DB_PORT}/${DB_NAME}" to "jdbc:postgresql://db:5432/Taskitory" with the following code from the .env file:
DB_ADDR_ALIAS="db"
DB_PORT="5432"
DB_NAME="Taskitory"
DB_BE_SCHEMA="backend"
Problem description: For my Spring Boot application to connect to the database I set the host of the jdbc-url to the service name of my DB container ("db") specified in my docker-compose.yml. Also I set the port of the jdbc-url to the native port of postgres "5432". This way the DB container should be accessible from the Spring Boot container through the docker-network "taskitory-net" which both containers are connected to. When I try to build my Spring Boot Application the following error appears (I needed to shorten the error messages to not blow the character limit):
#10 30.45 Caused by: java.lang.RuntimeException: Driver org.postgresql.Driver claims to not accept jdbcUrl, jdbc:postgresql://${DB_ADDR_ALIAS}:${DB_PORT}/${DB_NAME}
#10 30.45 at com.zaxxer.hikari.util.DriverDataSource.<init>(DriverDataSource.java:110) ~[HikariCP-4.0.3.jar:na]
#10 30.45 at com.zaxxer.hikari.pool.PoolBase.initializeDataSource(PoolBase.java:331) ~[HikariCP-4.0.3.jar:na]
#10 30.45 at com.zaxxer.hikari.pool.PoolBase.<init>(PoolBase.java:114) ~[HikariCP-4.0.3.jar:na]
#10 30.45 at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:108) ~[HikariCP-4.0.3.jar:na]
#10 30.45 at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) ~[HikariCP-4.0.3.jar:na]
#10 30.45 at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:181) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl.getIsolatedConnection(DdlTransactionIsolatorNonJtaImpl.java:44) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl.getJdbcConnection(ImprovedExtractionContextImpl.java:63) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.tool.schema.extract.spi.ExtractionContext.getQueryResults(ExtractionContext.java:43) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl.extractMetadata(SequenceInformationExtractorLegacyImpl.java:39) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl.initializeSequences(DatabaseInformationImpl.java:66) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl.<init>(DatabaseInformationImpl.java:60) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.tool.schema.internal.Helper.buildDatabaseInformation(Helper.java:183) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.tool.schema.internal.AbstractSchemaValidator.doValidation(AbstractSchemaValidator.java:68) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:200) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:81) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:335) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:471) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1498) ~[hibernate-core-5.6.3.Final.jar:5.6.3.Final]
#10 30.45 at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) ~[spring-orm-5.3.14.jar:5.3.14]
#10 30.45 at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.3.14.jar:5.3.14]
#10 30.45 at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-5.3.14.jar:5.3.14]
#10 30.45 ... 86 common frames omitted
#10 30.45
#10 30.48 [ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 3.495 s <<< FAILURE! - in de.krayadev.taskitory.TaskitoryApplicationTests
#10 30.49 [ERROR] contextLoads Time elapsed: 0.007 s <<< ERROR!
#10 30.49 java.lang.IllegalStateException: Failed to load ApplicationContext
#10 30.49 Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is java.lang.RuntimeException: Driver org.postgresql.Driver claims to not accept jdbcUrl, jdbc:postgresql://${DB_ADDR_ALIAS}:${DB_PORT}/${DB_NAME}
#10 30.49 Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is java.lang.RuntimeException: Driver org.postgresql.Driver claims to not accept jdbcUrl, jdbc:postgresql://${DB_ADDR_ALIAS}:${DB_PORT}/${DB_NAME}
#10 30.49 Caused by: java.lang.RuntimeException: Driver org.postgresql.Driver claims to not accept jdbcUrl, jdbc:postgresql://${DB_ADDR_ALIAS}:${DB_PORT}/${DB_NAME}
What I tried:
- I tried to build the Spring Boot application with the DB container up and running and with it stopped. In both cases this error comes up.
- I tried all combinations of host ("db", "localhost", ".env-variable") and port ("5432", "60000", ".env-variable") for the jdbc-url.
- With using the .env-variables I get the above shown error.
- In case of using the host "db" (not over .env-variable) with any port I get the following error:
#10 28.84 Caused by: java.net.UnknownHostException: db
#10 28.84 at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:567) ~[na:na]
#10 28.84 at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327) ~[na:na]
#10 28.84 at java.base/java.net.Socket.connect(Socket.java:633) ~[na:na]
#10 28.84 at org.postgresql.core.PGStream.createSocket(PGStream.java:231) ~[postgresql-42.2.18.jar:42.2.18]
#10 28.84 at org.postgresql.core.PGStream.<init>(PGStream.java:95) ~[postgresql-42.2.18.jar:42.2.18]
#10 28.84 at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:98) ~[postgresql-42.2.18.jar:42.2.18]
#10 28.84 at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:213) ~[postgresql-42.2.18.jar:42.2.18]
#10 28.84 ... 115 common frames omitted
#10 28.84
#10 28.87 [ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 4.365 s <<< FAILURE! - in de.krayadev.taskitory.TaskitoryApplicationTests
#10 28.87 [ERROR] contextLoads Time elapsed: 0.005 s <<< ERROR!
#10 28.87 java.lang.IllegalStateException: Failed to load ApplicationContext
#10 28.87 Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution
#10 28.87 Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution
#10 28.87 Caused by: org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution
#10 28.87 Caused by: org.postgresql.util.PSQLException: The connection attempt failed.
#10 28.87 Caused by: java.net.UnknownHostException: db
- With the host "localhost" and any port I get the following error:
#10 29.47 Caused by: java.net.ConnectException: Connection refused
#10 29.47 at java.base/sun.nio.ch.Net.pollConnect(Native Method) ~[na:na]
#10 29.47 at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) ~[na:na]
#10 29.47 at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:542) ~[na:na]
#10 29.47 at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:597) ~[na:na]
#10 29.47 at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327) ~[na:na]
#10 29.47 at java.base/java.net.Socket.connect(Socket.java:633) ~[na:na]
#10 29.47 at org.postgresql.core.PGStream.createSocket(PGStream.java:231) ~[postgresql-42.2.18.jar:42.2.18]
#10 29.47 at org.postgresql.core.PGStream.<init>(PGStream.java:95) ~[postgresql-42.2.18.jar:42.2.18]
#10 29.47 at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:98) ~[postgresql-42.2.18.jar:42.2.18]
#10 29.47 at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:213) ~[postgresql-42.2.18.jar:42.2.18]
#10 29.47 ... 115 common frames omitted
#10 29.47
#10 29.49 [ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 5.539 s <<< FAILURE! - in de.krayadev.taskitory.TaskitoryApplicationTests
#10 29.49 [ERROR] contextLoads Time elapsed: 0.005 s <<< ERROR!
#10 29.49 java.lang.IllegalStateException: Failed to load ApplicationContext
#10 29.49 Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution
#10 29.49 Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution
#10 29.49 Caused by: org.hibernate.exception.JDBCConnectionException: Unable to open JDBC Connection for DDL execution
#10 29.49 Caused by: org.postgresql.util.PSQLException: Connection to localhost:60000 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
#10 29.49 Caused by: java.net.ConnectException: Connection refused
If you miss something for solving my problem feel free to comment.
CodePudding user response:
You should be passing the .env variables to backend container as you did for db:
backend:
environment:
DB_ADDR_ALIAS: '${DB_ADDR_ALIAS}'
DB_PORT: '${DB_PORT}'
For the name resolution part, I would give a try for "taskitory-db".
CodePudding user response:
I think I solved the part with the .env-variables in the application.properties file. To do this, I defined environment variables for the build time in the Dockerfile of my Spring Boot application using the ARG command. I initialized these args in Docker-compose.yml with the .env variables:
Dockerfile
FROM maven:3.8.4-openjdk-17-slim AS build
ARG DB_ADDR_ALIAS
ARG DB_PORT
ARG DB_NAME
ARG DB_CLIENT_USER
ARG DB_CLIENT_PW
Docker-compose.yml
backend:
container_name: taskitory-backend
build:
context: .
args:
- DB_ADDR_ALIAS=${DB_ADDR_ALIAS}
- DB_PORT=${DB_PORT}
- DB_NAME=${DB_NAME}
- DB_CLIENT_USER=${DB_CLIENT_USER}
- DB_CLIENT_PW=${DB_CLIENT_PW}
.env file
DB_ADDR_ALIAS=db
DB_PORT=5432
DB_NAME=Taskitory
DB_CLIENT_USER=client
DB_CLIENT_PW=*********
application.properties
spring.datasource.url = jdbc:postgresql://${DB_ADDR_ALIAS}:${DB_PORT}/${DB_NAME}
spring.datasource.username = ${DB_CLIENT_USER}
spring.datasource.password = ${DB_CLIENT_PW}
However, there is still the problem that the Spring Boot application does not recognize the host "db" at build time: Caused by: java.net.UnknownHostException: db
. During my research I came to the conclusion that in the "application.properties" file only the combination "jdbc:postgresql://db:5432/Taskitory" for the field "spring.datasource.url" is applicable. The use of localhost inside of the backend container would reference the backend container itself and therefore is not applicable for connecting to the db container.