Reputation: 475
I'm trying to set up a Spring Boot application that depends on a MySQL database called teste in docker-compose. After issuing docker-compose up
, I'm getting:
Caused by: java.net.ConnectException: Connection refused (Connection refused)
I'm running on Linux Mint, my docker-compose version is 1.23.2, my Docker version is 18.09.0.
application.properties
# JPA PROPS
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.datasource.url=jdbc:mysql://db:3306/teste?useSSL=false&serverTimezone=UTC
spring.datasource.username=rafael
spring.datasource.password=password
spring.database.driverClassName =com.mysql.cj.jdbc.Driver
docker-compose.yml
version: '3.5'
services:
db:
image: mysql:latest
environment:
- MYSQL_ROOT_PASSWORD=rootpass
- MYSQL_DATABASE=teste
- MYSQL_USER=rafael
- MYSQL_PASSWORD=password
ports:
- 3306:3306
web:
image: spring-mysql
depends_on:
- db
links:
- db
ports:
- 8080:8080
environment:
- DATABASE_HOST=db
- DATABASE_USER=rafael
- DATABASE_NAME=teste
- DATABASE_PORT=3306
and the Dockerfile
FROM openjdk:8
ADD target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Upvotes: 12
Views: 12438
Reputation: 4543
You need to declare networks
for both the services and and make them use the same to communicate.
If the dependency (here db) takes long to start you need some mechanism to wait for it - I would say doing it (re-connecting) on application level would make your app more resilient. I think for a database a standard connection pool like Hikari takes care of it already.
Upvotes: 0
Reputation: 2418
For the connection refuse issue, we need to consider a few things
spring.datasource.url=jdbc:mysql://<mysql_service_name_here>:3306/<db_here>
Spring application can be looking for MySQL DB connection before properly starting the MySQL container. To eliminate that issue should spring-app container make wait using healthcheck
and depends_on
properties on compose file.
All two containers should be in the same docker network.
Perfect sample compose file that includes those solutions.
version: '3'
services:
mysql:
container_name: mysql
image: mysql:5.7
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
interval: 10s
timeout: 5s
retries: 5
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: http_logger
MYSQL_USER: supun
MYSQL_PASSWORD: password
ports:
- "3307:3306"
networks:
- logger-network
volumes:
- mysql-data:/var/lib/mysql
http-logger:
image: http-logger:v1.8.0
container_name: http-logger
ports:
- "8080:8080"
build: .
depends_on:
mysql :
condition: service_healthy
networks:
- logger-network
environment:
MYSQL_HOST: mysql
MYSQL_PORT: 3306
MYSQL_DB: http_logger
MYSQL_USER: supun
MYSQL_PASSWORD: password
networks:
logger-network:
driver: bridge
volumes:
mysql-data:
Here is perfectly working spring boot + MySQL volume + docker-compose example. https://github.com/supunUOM/spring_mysql_docker_volume
Upvotes: 0
Reputation: 157
I was facing the same issue and in case you do not want to use any custom scripts, this can easily be resolved using health checks along with depends on. A sample using these is as follows:
services:
mysql-db:
image: mysql
environment:
- MYSQL_ROOT_PASSWORD=vikas1234
- MYSQL_USER=vikas
ports:
- 3306:3306
restart: always
healthcheck:
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
timeout: 20s
retries: 10
app:
image: shop-keeper
container_name: shop-keeper-app
build:
context: .
dockerfile: Dockerfile
ports:
- 8080:8080
depends_on:
mysql-db:
condition: service_healthy
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql-db:3306/shopkeeper?createDatabaseIfNotExist=true
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: vikas1234
Upvotes: 6
Reputation: 3364
Docker compose always starts and stops containers in dependency order, or sequential order in the file if not given. But docker-compose does not guarantee that it will wait till the dependency container is running. You can refer here for further details. So the problem here is that your database is not ready when your spring-mysql
container tries to access the database. So, the recommended solution is you could use wait-for-it.sh or similar script to wrap your spring-mysql
app starting ENTRYPOINT
.
As example if you use wait-for-it.sh
your ENTRYPOINT
in your Dockerfile should change to following after copying above script to your project root:
ENTRYPOINT ["./wait-for-it.sh", "db:3306", "--", "java", "-jar", "app.jar"]
And two other important thing to consider here is:
Upvotes: 5
Reputation: 8636
Your config looks nice, I would just recommend:
links: db
. It has no value in user-defined bridge
networkingdocker-compose
- all ports are exposed automatically inside user-defined bridge
network. I think the problem is that database container takes more time to start than web. depends_on
just controls the order, but does not guarantee you database readiness. If possible, set several connection attempts or put socket-wait procedure in your web container.
Upvotes: 1