Failed to deploy Spring and MySQL application using Docker - spring

I am trying to connect a Spring server to a Mysql database, both running in different containers, and I got this error:
Caused by: com.mysql.cj.exceptions.WrongArgumentException: Malformed database URL, failed to parse the main URL sections.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_232]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_232]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_232]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_232]
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61) ~[mysql-connector-java-8.0.17.jar!/:8.0.17]
at com.mysql.cj.conf.ConnectionUrlParser.parseConnectionString(ConnectionUrlParser.java:162) ~[mysql-connector-java-8.0.17.jar!/:8.0.17]
at com.mysql.cj.conf.ConnectionUrlParser.<init>(ConnectionUrlParser.java:136) ~[mysql-connector-java-8.0.17.jar!/:8.0.17]
at com.mysql.cj.conf.ConnectionUrlParser.parseConnectionString(ConnectionUrlParser.java:118) ~[mysql-connector-java-8.0.17.jar!/:8.0.17]
at com.mysql.cj.conf.ConnectionUrl.getConnectionUrlInstance(ConnectionUrl.java:197) ~[mysql-connector-java-8.0.17.jar!/:8.0.17]
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:196) ~[mysql-connector-java-8.0.17.jar!/:8.0.17]
... 53 common frames omitted
For the Mysql container I am using the latest image from dockerhub.
I'm guessing that the ip address of the mysql container i'm trying to connect to is wrong, but I don't know how to obtain the correct address.
I am starting the mysql container via:
docker run -p 3036:3036 --name mysql-container -d mysql
application.properties in the Spring project:
database.ip = ${MYSQL_IP:mysql-container}
database.port = ${MYSQL_PORT:3306}
spring.datasource.url = jdbc:mysql://${database.ip}:${database.port}/${database.name}
backend container:
docker run -p 8080:8080 --name backend_container --link mysql-container:mysql -d backend_container
I didn't use Docker until now, so sorry if it is a trivial/boring question.
I would appreciate some help! :)

First of all, I don't understand why the database was containerized. Generally speaking, there's no reason for that.
Check if your database host has port-forwarding, i.e. port 3036 on the database host should be mapped to a URL or a global IP address. Check out ngrok so that you're unblocked, but there's a "proper" way to do this that's usually specific to your cloud provider.
Edit: There's also a typo in the code you posted. Your docker run command uses port 3036, but your Spring code contains database.port = ${MYSQL_PORT:3306}. Can't tell whether that's just a typo on here or in your actual code, but that's also possibly there.

As I found out, the problem was that the 2 containers were not on the same docker network.
When I started them with docker-compose using a docker-compose.yml, the 2 containers were started on the same default network, so that the spring container could connect to the mysql container ip address.
docker-compose.yml:
version: '3'
services:
mysql-container:
container_name: mysql-container
image: mysql:latest
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=db_name
- MYSQL_PASSWORD=root
spring_app_container:
container_name: spring_app_container
image: spring_app
depends_on:
- mysql-container
ports:
- 8085:8085
- 8080:8080
environment:
- DATABASE_HOST=mysql-container
- DATABASE_USER=root
- DATABASE_PASSWORD=password
- DATABASE_NAME=db_name
- DATABASE_PORT=3306

Related

Connecting to a Mongo container from Spring container

I have a problem here that I really cannot understand. I already saw few topics here with the same problem and those topics was successfully solved. I basically did the same thing and cannot understand what I'm doing wrong.
I have a Spring application container that tries to connect to a Mongo container through the following Docker Composer:
version: '3'
services:
app:
build: .
ports:
- "8080:8080"
links:
- db
db:
image: mongo
volumes:
- ./database:/data
ports:
- "27017:27017"
In my application.properties:
spring.data.mongodb.uri=mongodb://db:27017/app
Finally, my Dockerfile:
FROM eclipse-temurin:11-jre-alpine
WORKDIR /home/java
RUN mkdir /home/java/bar
COPY ./build/libs/foo.jar /home/java/bar/foo.jar
CMD ["java","-jar", "/home/java/bar/foo.jar"]
When I run docker compose up --build I got:
2022-11-17 12:08:53.452 INFO 1 --- [null'}-db:27017] org.mongodb.driver.cluster : Exception in monitor thread while connecting to server db:27017
Caused by: java.net.UnknownHostException: db
Running the docker compose ps I can see the mongo container running well, and I am able to connect to it through Mongo Compass and with this same Spring Application but outside of container. The difference running outside of container is the host from spring.data.mongodb.uri=mongodb://db:27017/app to spring.data.mongodb.uri=mongodb://localhost:27017/app.
Also, I already tried to change the host for localhost inside of the spring container and didnt work.
You need to specify MongoDB host, port and database as different parameters as mentioned here.
spring.data.mongodb.host=db
spring.data.mongodb.port=27017
spring.data.mongodb.authentication-database=admin
As per the official docker-compose documentation the above docker-compose file should worked since both db and app are in the same network (You can check if they are in different networks just in case)
If the networking is not working, as a workaround, instead of using localhost inside the spring container, use the server's IP, i.e, mongodb://<server_ip>:27017/app (And make sure there is no firewall blocking it)

spring flyway docker connection to localhost:5432 refused

I have a spring application with flyway and psql. After
mvn clean install
sudo docker build -t air-travels-api.jar .
docker run -p 8080:8080 air-travels-api.jar
I stuck with an error:
org.postgresql.util.PSQLException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
2022-07-09 14:28:09.610 WARN 1 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.internal.exception.FlywaySqlException: Unable to obtain connection from database: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
Here's my docker-compose.yaml:
version: '3'
services:
air-travels-api:
image: air-travels-api
build:
context: .
container_name: air-travels-api
ports:
- "8080:8080"
depends_on:
- flyway
environment:
- SPRING_DATASOURCE_URL=jdbc:postgresql://air-travels-api-db:5432/air-travels-api
- SPRING_DATASOURCE_USERNAME=postgres
- SPRING_DATASOURCE_PASSWORD=postgres
- SPRING_JPA_HIBERNATE_DDL_AUTO=update
flyway:
image: boxfuse/flyway:5-alpine
command: -url=jdbc:postgresql://air-travels-api-db:5432/air-travels-api -schemas=public -user=postgres -password=postgres migrate
volumes:
- ./migration:/flyway/sql
depends_on:
- air-travels-api-db
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=air-travels-api
- POSTGRES_HOST=postgres
- POSTGRES_PORT=5432
- POSTGRES_SCHEMA=public
air-travels-api-db:
image: postgres:12
restart: always
ports:
- "5432:5432"
container_name: air-travels-api-db
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: air-travels-api
Dockerfile:
FROM adoptopenjdk:11-jre-hotspot
EXPOSE 8080
ADD target/air-travels-api-0.0.1-SNAPSHOT.jar air-travels-api.jar
ENTRYPOINT ["java", "-jar", "/air-travels-api.jar"]
Applicaton.yaml
spring:
datasource:
url: jdbc:postgresql://air-travels-api-db:5432/air-travels-api
username: postgres
password: postgres
I found a similar question on stackoverflow, they suggested making sure postgres is running on the local machine. But I have it running inside a container (air-travels-api-db).
There are 2 issues that I see:
In the Application.yaml your url should be
jdbc:postgresql://air-travels-api-db:5432/air-travels-api
since your database service has the hostname air-travels-api-db and not localhost.
In your flyway service in docker-compose.yaml, the url is also incorrect. It should point to air-travels-api-db instead of postgres.
command: -url=jdbc:postgresql://api-travels-api-db:5432/air-travels-api -schemas=public -user=postgres -password=postgres migrate
You do set the environment variable, but it is possible the command-line argument will override that.
One suggestion: Database containers are known to have a slow startup, therefore, it is a good idea to either add a health-check to your database service, or make sure to implement retry logic in your application. Otherwise, you will see race condition issues where the application runs before the database is available and it crashes. This is very common.

Connection refused to localhost:5432 through Docker Compose after already specifying the name of the service instead of localhost

I have a few microservices running under Docker. They are Zuul, Eureka, and a configuration server. These are working but when I start my authorization-service, it says I cannot connect to PostgreSQL.
version: '3'
services:
eureka-discovery:
...
zuul-gateway:
...
config:
...
postgres:
image: postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: root
POSTGRES_DB: spring_microservices
ports:
- 5432:5432
authorization-service:
image: authorization-service:0.0.1
environment:
- eureka.client.serviceUrl.defaultZone=http://eureka-discovery:8761/eureka
- spring.cloud.config.uri=http://zuul-gateway:8765/config-service
- spring.datasource.url=jdbc:postgresql://postgres:5432/spring_microservices
depends_on:
- eureka-discovery
- zuul-gateway
- config
- postgres
ports:
- 1001:1001
What's confusing is that I am specifying postgres instead of localhost to make the connection, but the error continues to say "localhost". You see I override other properties the same way I do with spring.datasource.url and they work but this one.
org.postgresql.util.PSQLException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
I attempted a few variations I could find around, such as using a different service name, using SPRING_DATASOURCE_URL, using the connection string as postgresql://[user]:[pass]#[service]/[database], I tried moving this line to the config-service instead since the database connection is indeed in the Spring Cloud Config Server microservice, but all to no avail. What's missing? It seems to be correct comparing to all the solutions I found.
I made Spring Config Server see my repository for the configurations. Thinking better, if it's reading from the repository it's evident that changing it on the fly locally won't work, so I updated the connection string of the configuration file for authorization-service then pushed, and it worked. I wonder if this is a good practice or better to make Config Server see local files and change it on the fly?
Hi i hope you are okay !
above your authorization-service add a link like this:
links:
- "postgres"
Greetings

Spring Boot, PostgreSQL, and Docker - Connection Refused whil Running in Container

I am attempting to build a "service" consisting of a Spring Boot application and PostgreSQL database. I have been able to access the database (running in a container) from the Spring Boot app while the Spring Boot application was running on my local machine. Now, when I attempt to move the Spring Boot application to a container, I am received the following error:
inventory_1 | 2018-01-20 18:43:06.108 ERROR 1 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection] with root cause
inventory_1 |
inventory_1 | java.net.ConnectException: Connection refused (Connection refused)
However, I am able to connect to DB from my local machine:
psql -h localhost -p 5000 -U kelly_psql -d leisurely_diversion
My application.properties file:
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=false
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.datasource.url=jdbc:postgresql://localhost:5432/leisurely_diversion
spring.datasource.username=kelly_psql
spring.datasource.password=pass
spring.datasource.driver-class-name=org.postgresql.Driver
My docker-compose file:
# Use postgres/example user/password credentials
version: '3.2'
services:
db:
image: postgres
ports:
- 5000:5432
environment:
POSTGRES_PASSWORD: example
volumes:
- type: volume
source: psql_data
target: /var/lib/postgresql/data
networks:
- app
restart: always
inventory:
image: kellymarchewa/inventory_api
depends_on:
- db
ports:
- 8080:8080
networks:
- app
restart: always
volumes:
psql_data:
networks:
app:
My Dockerfile (from the Spring website)
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
I suspect the issue lies in a misunderstanding (on my part) of Docker or containers, but I am not sure. Any advice would be appreciated.
You are pointing your application towards localhost, but this is not shared between containers.
To access another container you have to refer to its hostname.
In your case, I understand that you want the inventory service to access the db service. So you should use the following datasource url:
spring.datasource.url=jdbc:postgresql://db:5432/leisurely_diversion
See this simple tutorial about connecting to a container from another container with docker compose: https://docs.docker.com/compose/gettingstarted/
Like in my case if you are using Docker Toolbox for windows 8.1 then you cannot use "localhost",
Instead you have to use docker machine ip;
host> docker-machine ip default
192.168.99.100
After that your url will look like;
spring.datasource.url=jdbc:postgresql://192.168.99.100:5432/bankdb
This will successfully connect to docker Postgres DB.
Cheers!!
Elaborating a little upon the answer given by ESala:
I agree, it is a networking issue and the given solution works fine, but you can also use localhost (e.g. if you really really want to), by switching to network host mode when running your containers (cf here). Like done here for nginx.
I'd say you won't want this most of the time, since it messes with the sandbox you gain. But the option exists.

Docker Compose + Spring Boot + Postgres connection

I have a Java Spring Boot app which works with a Postgres database. I want to use Docker for both of them. I initially put just the Postgres in Docker, and I had a docker-compose.yml file defined like this:
version: '2'
services:
db:
container_name: sample_db
image: postgres:9.5
volumes:
- sample_db:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=sample
- POSTGRES_USER=sample
- POSTGRES_DB=sample
- PGDATA=/var/lib/postgresql/data/pgdata
ports:
- 5432:5432
volumes:
sample_db: {}
Then, when I issued the commands sudo dockerd and sudo docker-compose -f docker-compose.yml up, it was starting the database. I could connect using pgAdmin for example, by using localhost as server and port 5432. Then, in my Spring Boot app, inside the application.properties file I defined the following properties.
spring.datasource.url=jdbc:postgresql://localhost:5432/sample
spring.datasource.username=sample
spring.datasource.password=sample
spring.jpa.generate-ddl=true
At this point I could run my Spring Boot app locally through Spring Suite, and it all was working fine. Then, I wanted to also add my Spring Boot app as Docker image. I first of all created a Dockerfile in my project directory, which looks like this:
FROM java:8
EXPOSE 8080
ADD /target/manager.jar manager.jar
ENTRYPOINT ["java","-jar","manager.jar"]
Then, I entered to the directory of the project issued mvn clean followed by mvn install. Next, issued docker build -f Dockerfile -t manager . followed by docker tag 9c6b1e3f1d5e myuser/manager:latest (the id is correct). Finally, I edited my existing docker-compose.yml file to look like this:
version: '2'
services:
web:
image: myuser/manager:latest
ports:
- 8080:8080
depends_on:
- db
db:
container_name: sample_db
image: postgres:9.5
volumes:
- sample_db:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=sample
- POSTGRES_USER=sample
- POSTGRES_DB=sample
- PGDATA=/var/lib/postgresql/data/pgdata
ports:
- 5432:5432
volumes:
sample_db: {}
But, now if I issue sudo docker-compose -f docker-compose.yml up command, the database again starts correctly, but I get errors and exit code 1 for the web app part. The problem is the connection string. I believe I have to change it to something else, but I don't know what it should be. I get the following error messages:
web_1 | 2017-06-27 22:11:54.418 ERROR 1 --- [ main] o.a.tomcat.jdbc.pool.ConnectionPool : Unable to create initial connections of pool.
web_1 |
web_1 | org.postgresql.util.PSQLException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections
Any ideas?
Each container has its own network interface with its own localhost. So change how Java points to Postgres:
spring.datasource.url=jdbc:postgresql://localhost:5432/sample
To:
spring.datasource.url=jdbc:postgresql://db:5432/sample
db will resolve to the proper Postgres IP.
Bonus. With docker-compose you don't need to build your image by hand. So change:
web:
image: myuser/manager:latest
To:
web:
build: .
I had the same problem and I lost some time to understand and solve this problem:
org.postgresql.util.PSQLException: Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
I show all the properties so that everyone understands.
application.properties:
spring.datasource.url=jdbc:postgresql://localhost:5432/testdb
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL82Dialect
spring.jpa.hibernate.ddl-auto=update
docker-compose.yml:
version: "3"
services:
springapp:
build: .
container_name: springapp
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/testdb
ports:
- 8000:8080
restart: always
depends_on:
- db
db:
image: postgres
container_name: db
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=testdb
- PGDATA=/var/lib/postgresql/data/pgdata
ports:
- 5000:5432
volumes:
- pgdata:/var/lib/postgresql/data
restart: always
volumes:
pgdata:
For start spring application with local database we use url localhost.
For connect to container with database we need change 'localhost' on your database service, in my case 'localhost' to 'db'.
Solution: add SPRING_DATASOURCE_URL environment in docker-compose.yml wich rewrite spring.datasource.url value for connect:
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/testdb
I hope this helps someone save his time.
You can use this.
version: "2"
services:
sample_db-postgresql:
image: postgres:9.5
ports:
- 5432:5432
environment:
- POSTGRES_PASSWORD=sample
- POSTGRES_USER=sample
- POSTGRES_DB=sample
volumes:
- sample_db:/var/lib/postgresql/data
volumes:
sample_db:
You can use ENV variable to change the db address in your docker-compose.
Dockerfile:
FROM java:8
EXPOSE 8080
ENV POSTGRES localhost
ADD /target/manager.jar manager.jar
ENTRYPOINT exec java $JAVA_OPTS -jar manager.jar --spring.datasource.url=jdbc:postgresql://$POSTGRES:5432/sample
docker-compose:
`
container_name: springapp
environment:
- POSTGRES=db`

Resources