0

I have a SpringBoot application that works perfectly. Now I am trying to Dockerise it, but have some issues when connecting to the database.

The application has two datasources:

application.properties

server.port= 8081
# pims datasource
spring.datasource1.driver-class-name=org.postgresql.Driver
spring.datasource1.jdbc-url=jdbc:postgresql://localhost:5432/pims
spring.datasource1.username=postgres
spring.datasource1.password=
spring.jpa.database-platform=postgres
#spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=false
# approval datasource
spring.datasource2.driver-class-name=org.postgresql.Driver
spring.datasource2.jdbc-url=jdbc:postgresql://localhost:5432/approval
spring.datasource2.username=postgres
spring.datasource2.password=

In the application, I use Spring to access the two datasources:

@Configuration
@ComponentScan(basePackages = "com.nexct")
public class MultipleDBConfig {

    @Bean(name = "datasource1")
    @ConfigurationProperties("spring.datasource1")
    @Primary
    public DataSource dataSource1(){
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "datasource2")
    @ConfigurationProperties("spring.datasource2")
    public DataSource dataSource2(){
        return DataSourceBuilder.create().build();
    }
}

So I have created:

Dockerfile

FROM openjdk:14
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} nexct-approval-service.jar
EXPOSE 8081
ENTRYPOINT ["java","-jar","/nexct-approval-service.jar"]

docker-compose.yml

version: '3.7'

services:
  product-service:
    build: ../nexct-approval-service
    volumes:
      - ../nexct-approval-service:/usr/src/app
    ports:
      - "8081:8081"
    db:
      image: postgres
      environment:
        POSTGRES_DB_PORT: "5432"
        POSTGRES_DB_HOST: "localhost"
        POSTGRES_PASSWORD:
        POSTGRES_USER: postgres
        POSTGRES_DB: pims

However, I am not sure how to configure the two Postgres databases.

Any advise would be appreciated.

Note: the databases are not running in a container, as they are used by other legacy applications.

If I remove the db from docker-compose.yml. When I run docker-compose up, the Spring Boot application starts, and I can access a RESTful service. However, I get the following error:

PSQLException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
Richard
  • 8,193
  • 28
  • 107
  • 228
  • Have you tried using 127.0.0.1 instead of localhost? – Dominik K Jul 20 '20 at 14:24
  • Hi @DominikK, thanks for the reply. I am not sure how to compose the yml file, so that Spring can access the datasources, e.g. `@ConfigurationProperties("spring.datasource1")` – Richard Jul 20 '20 at 14:28
  • Just to clarify, the postgres dbs are running on the same host as the container right? If so, you need to specify networks in the docker-compose file, setting the driver to bridge. – Dominik K Jul 20 '20 at 14:31
  • Yes, the application and database will run on the same host, that's why I just refer to it as `localhost`. The SpringBoot app is running in a Docker container, but the two database are not (they are legacy databases used by other applications). – Richard Jul 20 '20 at 14:35
  • 1
    If the databases are running on the host try adding `network_mode: "host"` to the `product-service` definition and remove `db` section completly. I am not sure why you added `db` section when you said you run it on your host. – Michał Krzywański Jul 20 '20 at 14:46
  • @michalk, yes you are correct, I need to remove the `db` section. I think I am close, I add `network_mode: "host"`. But now when I try access the application, I get: `Error: connect ECONNREFUSED 127.0.0.1:8081` – Richard Jul 20 '20 at 14:52
  • Duplicate https://stackoverflow.com/questions/62995376/spring-boot-database-connection-does-not-work-when-in-docker/62995648?noredirect=1#comment111423660_62995648 – Richard Jul 21 '20 at 08:04
  • Does this answer your question? [Spring Boot database connection does not work when in Docker](https://stackoverflow.com/questions/62995376/spring-boot-database-connection-does-not-work-when-in-docker) – Daniel Widdis Jul 21 '20 at 21:59

3 Answers3

1

Try configuring your docker-compose file to use bridged networking:

version: '3.7'

services:
  product-service:
    build: ../nexct-approval-service
    volumes:
      - ../nexct-approval-service:/usr/src/app
    environment:
        POSTGRES_DB_PORT: "5432"
        POSTGRES_DB_HOST: "localhost"
        POSTGRES_PASSWORD:
        POSTGRES_USER: postgres
        POSTGRES_DB: pims
    networks:
        - product_service_network

networks:
    product_service_network:
        driver: bridge

You also have to move the ENVIRONMENT variables to product-service if you are going to use them in the product-service container.

If localhost doesn't work, use 127.0.0.1 instead.

Dominik K
  • 399
  • 3
  • 9
  • How do I configure the second database? and how do I get spring to connect to the database? – Richard Jul 20 '20 at 14:37
  • `ERROR: The Compose file './docker-compose.yml' is invalid because: Unsupported config option for services.product-service: 'db'` – Richard Jul 20 '20 at 14:38
  • If you are using bridged network, you can access both databases via localhost and the respective port number. – Dominik K Jul 20 '20 at 14:40
  • If I run it, I get the above error. If I remove `db` and add the `network` section as you suggest, it builds with no errors. However, when I access the app, it gets the following error: `PSQLException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.` – Richard Jul 20 '20 at 14:44
  • That's why I suggested to change `localhost` to `127.0.0.1`. Also you don't need the port binding anymore, as you access the host network directly. I updated the answer to leave out the ports binding. – Dominik K Jul 20 '20 at 14:50
  • I think I need to remove the entire `db` section. So that Spring can just use the `appliction.properties` to connect to the databases. – Richard Jul 20 '20 at 14:54
  • Oh, you are right, I didn't look close enough. You can't nest services like that. You need to indent the whole db section back, but that would make it an own service, which is not what you want, as the dbs are on the host anyway. – Dominik K Jul 20 '20 at 14:57
0
version: '3.7'

services:
  product-service:
    build: ../nexct-approval-service
    volumes:
      - ../nexct-approval-service:/usr/src/app
    ports:
      - "8081:8081"
server.port=8081
# pims datasource
spring.datasource1.driver-class-name=org.postgresql.Driver
spring.datasource1.jdbc-url=jdbc:postgresql://<postgres_host_private_ip>:5432/pims
spring.datasource1.username=postgres
spring.datasource1.password=
spring.jpa.database-platform=postgres
#spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=false
# approval datasource
spring.datasource2.driver-class-name=org.postgresql.Driver
spring.datasource2.jdbc-url=jdbc:postgresql://<postgres_host_private_ip>:5432/approval
spring.datasource2.username=postgres
spring.datasource2.password=

Replace <postgres_host_private_ip> with the private IP of the machine hosting the postgres databases.

I'm not sure what you were trying to achieve with the nested db service, but since your database are already running somewhere outside there is no need for this.

Your Spring application will run on a isolated network from your host because of the docker isolation (unless explicitly asked to use host network with network_mode: "host"). Knowing that, the "localhost" can not work inside the container, you need to use the real IP of the machine that hosts the databases. Most likely something like 192.168.xxx.xxx

Also, you need to make sure the postgres is configured to accept connection from "non-localhost" sources (see https://www.andrew-kirkpatrick.com/2017/05/allow-connection-postgresql-server-outside-localhost/).

Anthony Raymond
  • 7,434
  • 6
  • 42
  • 59
  • Thanks, what you say makes sense. I think this is the answer, I am going to try. I am just having an issue I don't understand yet. When I run the `docker-compose up --build`, Spring has for some reason started tomcat on port 8080 and not 8081, and I cannot access it on either 8080 or 8081 anymore. – Richard Jul 20 '20 at 15:20
  • @Richard May be related to the space between `server.port=` and `8081` in your application.properties – Anthony Raymond Jul 20 '20 at 15:21
  • Thanks yes, I had a stray `/` in the file for some reason – Richard Jul 20 '20 at 15:24
  • After making the above changes and updating my internal IP, I get: `.PSQLException: Connection to 127.0.0.1:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.` – Richard Jul 20 '20 at 15:30
  • Why is this 127.0.0.1? 127.0.0.1 is localhost. – Anthony Raymond Jul 20 '20 at 15:31
0

To access an application running on ur Host there are few options

  • Use the Bridge network. (Doc)
    • Create a bridge network and assign the subnet address and gateway address.
    • Now you can reach your application running at the host from the container at <gateway address>:<port> i.e 172.28.0.1:<port>
version: '3.7'

services:
  product-service:
    build: ../nexct-approval-service
    volumes:
      - ../nexct-approval-service:/usr/src/app
    ports:
      - "8081:8081"
    networks:
      hostnet: {}
           
networks:
  hostnet:
    driver: bridge
    ipam:
      config:
        - subnet: 172.28.0.0/16


  • Use Attach service to host network. (Doc)
    • add network_mode: host to your service (only works on Linux)
    • OR create an external network
    • Now you can reach your application running at the host from the container at localhost:<port>

With network_mode: (Linux)

version: '3.7'

services:
 product-service:
   build: ../nexct-approval-service
   volumes:
     - ../nexct-approval-service:/usr/src/app
   ports:
     - "8081:8081"
   network_mode: host
WSMathias9
  • 669
  • 8
  • 15
  • `ERROR: for approval-service network-scoped alias is supported only for containers in user defined networks ERROR: Encountered errors while bringing up the project.` – Richard Jul 20 '20 at 15:31
  • I am developing on a mac, and will deploy to a linux server – Richard Jul 20 '20 at 15:34
  • Thanks, I will give it a try when I get back to my work. – Richard Jul 20 '20 at 16:11
  • I think this is close to the answer. When I run the Linux example on Mac, I get `Cannot start service approval-service: network hostclear not found`. So I will try your example with a bridge network. – Richard Jul 21 '20 at 07:01