I used mvn clean package
to get my target directory and .jar file. Then, I try to put it and mysql database into docker containers but keep failing. It can be executed perfectly outside the containers.
I try to set up the environments through docker compose file, so I guess the application.properties does not matter here. Correct me if I am wrong.
Current structure of my dir:
The error I got:
java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.
docker-compose.yml:
version: '3.8'
services:
mysql-db:
image: mysql:8.0
container_name: mysql-container
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: inventory
MYSQL_USER: user
MYSQL_PASSWORD: password
ports:
- "3306:3306"
spring-app:
build:
context: .
dockerfile: Dockerfile
container_name: spring-container
ports:
- "8082:8080"
depends_on:
- mysql-db
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql-db:3306/inventory?autoReconnect=true&useSSL=false
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: root
Dockerfile:
# Use a base image with OpenJDK Java 17 installed
FROM openjdk:17
# Set the working directory in the container
WORKDIR /app
# Copy the packaged Spring Boot application JAR file into the container
COPY target/smartstock-0.0.1-SNAPSHOT.jar /app
# Specify the command to run the Spring Boot application when the container starts
CMD ["java", "-jar", "smartstock-0.0.1-SNAPSHOT.jar"]
application.properties:
#information for connect to MySQL database
spring.datasource.url=jdbc:mysql://mysql-db:3306/inventory?autoReconnect=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#auto building table in database according to entity class we have
spring.jpa.hibernate.ddl-auto=update
#show what sql is jpa using
spring.jpa.show-sql=true
#reduce logging information. only shows warm
logging.level.root=warn
2
Answers
I ended up with the following settings. This setting is originally from this youtube video.
application.properties:
docker-compose.yml:
Dockerfile:
When working with Dockerized databases, it’s crucial to use the container name for the host instead of the service name in your code.
Therefore, your connection string should be:
as you specified your MySQL container name on your
docker-compose.yaml
.To ensure compatibility both locally and in Docker, adjust your application.properties file as follows:
and set on your
docker-compose.yaml
on the spring-app service the environment variable:or
you can specify just the host part, like this:
and set on your
docker-compose.yaml
on the spring-app service the env:This way when you run locally without the env it will use your localhost database and when you Dockerize your application you will pass an env with the correct host for your connection string.
You can see an example on running an application with Dockerized PostgreSQL on this Baeldung article: https://www.baeldung.com/spring-boot-postgresql-docker
UPDATE:
Another thing that you should do to work is add an restart-policy to your spring-app. The depends_on keyword on his own is not enough.
This is what happens when you execute the
docker compose up
. The docker will initialize your mysql-db, and after it initializes the depends_on policy will make your spring-app initializes in sequence, but there is the problem, your database is initialized, but not fully loaded and working. So when you load your spring-app it will not find a database and will fail.To prevent this, you should add an restart policy to your spring-app, so when it loads and not found a database it will fail but will start another on sequence. Add it like this:
with this it will try to restart your application until it runs properly, at max 10 times.
The name of the environment variable doesn’t matter, as long as is the same as you specify on your
application.properties
. As a convention I recommend you to use the MYSQL_URL name for the env, because SPRING_DATASOURCE_URL gives an impression that is an Spring provided property. You should end with something like this:Attention: The spring.datasource.url is not an environment variable, just what is inside the ${ } is one.
I would also recommend you to connect your app and database to the same docker network. Providing better isolation, security and communication, preventing from eventual communication issues.
Following everything you should end with an docker-compose like this: