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"]
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:
Do not use links they are deprecated you should use user-defined network instead. All services in docker-compose file will be in single user-defined network if you don't explicitly define any network. So you just have to remove the links from compose file.
You don't need to publish the port for docker container if you only use it inside the user-defined network.
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
Your config looks nice, I would just recommend:
Remove links: db. It has no value in user-defined bridge networking
Remove port exposing for db unless you want to connect from outside docker-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.
Related
I was given a multy-steps task and im stuck !!
im trying to connect my Java container to my MYSQL container,but im getting 503 ERROR
HTTP ERROR 503
Problem accessing /. Reason:
Service Unavailable
docker-compose file :
version: "3.3"
services:
lavagna:
build: .
ports:
- "8080:8080"
networks:
- back_net
depends_on:
- my_db
environment:
spring.datasource.url: "jdbc:mysql://my-db:3306/lavagna"
my_db:
image: mysql:5.7
ports:
- "3306:3306"
networks:
- back_net
volumes:
- $PWD/mysql:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: 123
MYSQL_USER: eyal
MYSQL_PASSWORD: 123
networks:
back_net:
driver: bridge
I got the JAVA src files,i just used maven localy to build it and use target for the Java Dockerfile
java app dockerfile :
FROM openjdk:8-jre-alpine
EXPOSE 8080
COPY ./target/. .
COPY ./entrypoint.sh .
ENV DB_DIALECT MYSQL
ENV DB_URL jdbc:mysql://localhost:3306/lavagna
ENV DB_USER "root"
ENV DB_PASS "123"
ENV SPRING_PROFILE dev
RUN apk update \
&& apk add ca-certificates \
&& update-ca-certificates && apk add openssl
RUN chmod 774 entrypoint.sh
ENTRYPOINT [ "./entrypoint.sh" ]
I think you need a combination of comments and answers given already. Your containers are on the same network, so it appears to boil down to configuration.
In your docker file update your DB_URL to:
ENV DB_URL jdbc:mysql://my_db:3306/lavagna
If you use localhost your container will loopback to itself, and never hit the network.
In your docker-compose yml file, you have a typo in the url, try updating to:
spring.datasource.url: "jdbc:mysql://my_db:3306/lavagna"
As an aside, using depends_on does not wait for the service to be ready. It simply dictates start order as the documentation states:
There are several things to be aware of when using depends_on:
depends_on does not wait for db and redis to be “ready” before starting web - only until they have been started. If you need to wait for a service to be ready...
I am building a Spring Boot application which uses PostgreSQL with docker-compose.
When I run my containers using docker-compose up --build, my Spring Boot application fails to start because it does not find the PostgreSQL container's hostname.
Spring Boot Dockerfile
FROM maven:3.6.3-openjdk-14-slim AS build
COPY src /usr/src/app/src
COPY pom.xml /usr/src/app
RUN mvn -f /usr/src/app/pom.xml clean package
FROM openjdk:14-slim
COPY --from=build /usr/src/app/target/server-0.0.1-SNAPSHOT.jar /usr/app/server-0.0.1-SNAPSHOT.jar
EXPOSE 9000
ENTRYPOINT ["java","-jar","/usr/app/server-0.0.1-SNAPSHOT.jar"]
docker-compose.yml
version: '3'
services:
db:
image: postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: my_db
ports:
- "5432:5432"
volumes:
- db-data:/var/lib/postgresql/data
networks:
- db-network
restart: always
server:
build: './server'
depends_on:
- db
restart: always
ports:
- "9000:9000"
networks:
- db-network
volumes:
- ./server:/server
networks:
db-network:
volumes:
db-data:
application.properties
spring.datasource.url=jdbc:postgresql://db:5432/my_db
spring.datasource.username=postgres
spring.datasource.password=postgres
Error output
Caused by: java.net.UnknownHostException: db
My guess is that docker-compose's virtual network isn't created yet during the build stage of the Spring Boot Dockerfile.
Any idea on how to solve this issue ?
Lots of info here: https://docs.docker.com/compose/networking/
Within the web container, your connection string to db would look like
postgres://db:5432, and from the host machine, the connection string
would look like postgres://{DOCKER_IP}:8001.
What this is saying is db:5432 is fine to use within docker-compose.yaml and the IP address will be passed (not "db"), but using it externally within your application code isn't going to work. You could however pass from docker-compose.yaml db as an application input variable, which your application could fill in in the configuration file. This would enable you then to connect.
Externalising configuration like this is fairly common practice so should be a relatively easy fix.
eg:
Docker-compose.yaml
version: '3'
services:
db:
container_name: db
image: postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: my_db
ports:
- "5432:5432"
volumes:
- db-data:/var/lib/postgresql/data
networks:
- db-network
restart: always
server:
build: './server'
depends_on:
- db
environment:
DB_HOST: db # untested, but there should be a way to pass this in
DB_PORT: 5432
DB_DATABASE: my_db
DB_USER: postgres
DB_PASSWORD: postgres
restart: always
ports:
- "9000:9000"
networks:
- db-network
volumes:
- ./server:/server
networks:
db-network:
volumes:
db-data:
Then have an application.properties file located under src/main/java/resources/application.properties
spring.datasource.url=jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_DATABASE}
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
This post completely solved my issue.
It turns out that maven was trying to establish the connection to the database while building the .jar file. All I had to do is modify my Dockerfile with this line RUN mvn -f /usr/src/app/pom.xml clean package -DskipTests.
Please do note while building the images the service will not have access to the database as it is not yet running . Only after the images are built and the containers are running do the services have access . So when you try to pass a host as db , it is not yet available in the build stage . It is available only once the db container starts running .
Even though I'm giving in the application properties,
spring.data.mongodb.host=api-database4
as the hostname which is the container name and hostname of the MongoDB on the docker-compose file, Spring app still can't connect to the MongoDB instance. I can however connect from MongoDB Compass to localhost:27030 but not to mongodb://api-database4:27030/messagingServiceDb.
My docker-compose file;
version: '3'
services:
messaging-api6:
container_name: 'messaging-api6'
build: ./messaging-api
restart: always
ports:
- 8085:8080
depends_on:
- api-database4
networks:
- shared-net
api-database4:
image: mongo
container_name: api-database4
hostname: api-database4
restart: always
ports:
- 27030:27017
networks:
- shared-net
command: mongod --bind_ip_all
networks:
shared-net:
driver: bridge
and my Docker file for the Spring app is;
FROM openjdk:12-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
and my application.properties are;
#Local MongoDB config
spring.data.mongodb.database=messagingServiceDb
spring.data.mongodb.port=27030
spring.data.mongodb.host=api-database4
Entire code can be seen here.
How can I make my spring app on a docker container create a connection to the MongoDB instance which is on another docker container?
I have tried the solutions on similar questions and replicated them, it still gives the same error.
Edit and Solution:
I solved the issue by commenting out configuration below,
#Local MongoDB config
#spring.data.mongodb.database=messagingServiceDb
spring.data.mongodb.host=api-database4
spring.data.mongodb.port=27030
The remaining question is, why? That was the correct port that I'm trying to connect. Could it be related to the configuration order?
ports directive in docker-compose publishes container ports to the host machine. The containers communicate with each other on exposed ports. You can test whether a container can reach another with netcat.
docker exec -it messaging-api6 bash
> apt-get install netcat
> nc -z -v api-database4 27030
> nc -z -v api-database4 27017
I am building my first Springboot 2.0 application. I am trying to put my Springboot application into one docker container and my PostgresDB into another container.
My Dockerfile
FROM frolvlad/alpine-oraclejdk8:slim
VOLUME /tmp
ADD springboot-api-demo-0.1*.jar app.jar
RUN sh -c 'touch /app.jar'
EXPOSE 9443
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/urandom -jar /app.jar" ]
My docker-compose.yml file
version: "2.1"
services:
springboot-api-demo:
image: "fw/springboot-api-demo"
mem_limit: 1024m
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=local
- AWS_REGION=local
- ENVIRONMENT=local
- AUTH_ENABLED=false
postgres:
container_name: pgdb
image: postgres:9.6-alpine
environment:
- 'POSTGRES_ROOT_PASSWORD=postgres'
- 'POSTGRES_USER=postgres'
- 'POSTGRES_PASSWORD=postgres'
ports:
- "54321:5432"
I am using Springboot JPA Data 2.0 with below config data in my application.properties
spring.datasource.url= jdbc:postgresql://localhost:54321/java_learning
spring.datasource.username=postgres
spring.datasource.password=postgres
I can test that Both of the Images are up. Also from docker log and docker events, I see that postgres Container is running fine, even I can access it and also created a DB too.
But springboot container started but i died because it could not connect to postgress and throwing error below.
Unable to obtain connection from database: The connection attempt
failed
Note that my host machine already has Postgres on port 5432 thats why I did a port mapping ofr 54321:5432 on my postgres container. Here is Proof :) -
➜ springboot-api-demo git:(master) ✗ lsof -i:54321
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
com.docke 44345 shailendra.singh 18u IPv4 0xf62897fbdd69e31d 0t0 TCP *:54321 (LISTEN)
com.docke 44345 shailendra.singh 21u IPv6 0xf62897fbdd119975 0t0 TCP localhost:54321 (LISTEN)
➜ springboot-api-demo git:(master) ✗ lsof -i:5432
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
postgres 715 shailendra.singh 5u IPv6 0xf62897fbb43e03b5 0t0 TCP localhost:postgresql (LISTEN)
postgres 715 shailendra.singh 6u IPv4 0xf62897fbbaeea9bd 0t0 TCP localhost:postgresql (LISTEN)
I am not sure what is the problem. But my Springboot application is not able to connect my postgres container which is running fine with proper creadentials.
Try with :
spring.datasource.url= jdbc:postgresql://pgdb:5432/java_learning
The postgres database is not running on localhost, it's running in the other container which has an other IP (yet unknown).
Thanksfully, docker-compose automatically create a network shared among all the containers in the docker-compose.yml (unless explicitly said to do not), as a result you can magically use the service name as an hostname.
Also, you have a typo in the port, Postgres use 5432 by default, not 54321
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.
you should use the following datasource url:
spring.datasource.url=jdbc:postgresql://pgdb:5432/java_learning
See this simple tutorial about connecting to a container from another container with docker compose: https://docs.docker.com/compose/gettingstarted/
You're missing networking configuration in your docker-compose.yml specification. By using "networks" you can effectively communicate between containers by their service name (using dns, the service name as the hostname).
Here is an updated docker-compose.yml:
version: "2.1"
services:
springboot-api-demo:
image: "fw/springboot-api-demo"
mem_limit: 1024m
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=local
- AWS_REGION=local
- ENVIRONMENT=local
- AUTH_ENABLED=false
networks:
- mynet
postgres:
container_name: pgdb
image: postgres:9.6-alpine
environment:
- 'POSTGRES_ROOT_PASSWORD=postgres'
- 'POSTGRES_USER=postgres'
- 'POSTGRES_PASSWORD=postgres'
ports:
- "54321:5432"
networks:
- mynet
networks:
mynet:
driver: bridge
Your database url should look like spring.datasource.url=jdbc:postgresql://postgres:5432/java_learning (notice the hostname, postgres, is equal to that of the service name.
Apart from the above solutions provided JDK 11 java container with the mentioned configuration (connecting postgres via IP, localhost, servicename .. with postgres container exposed to LAN) still doesn't work. Upgrade to JDK latest version (17 currently) works for me - do consider this also when you use JDK 11 and trying java container (docker) communicating with postgres container.
I am trying to connect my spring-boot application(REST endpoints) running in a Tomcat container with a mongo container. I am using docker-compose to link both the containers. The application was working perfectly fine. It just stopped working suddenly.
Following is my code:
Dockerfile:
FROM tomcat:9.0.13
WORKDIR /usr/local/tomcat/webapps
#COPY pom.xml .
#RUN ["mvn", "clean", "install"]
COPY /target/TestProfileManager.war .
docker-compose.yml:
version: '3'
services:
app:
container_name: VF-BACKEND
restart: always
build: .
ports:
- "8083:8080" #VF Webservice
depends_on:
- mongo
links:
- mongo
mongo:
container_name: VF-MONGO
image: mongo:4.0.2
ports:
- "27018:27017"
volumes:
- /data/vfdb:/data/db
application.properties
spring.data.mongodb.uri=mongodb://mongo:27018/tsp
If I run the application from the IDE as a standalone application, the endpoints do return the response. Only during container communication, I am getting 503. I could not find any post that answers my question.
Thanks for the help. Since, the code was working before, not pasting the classes. Let me know if I should share them as well.
It should be mongodb://mongo:27017, in service to service communication you do not need to use publish port.
It is important to note the distinction between HOST_PORT and
CONTAINER_PORT. the HOST_PORT is 27018 and the container port is
27017 . Networked service-to-service communication use the
CONTAINER_PORT
compose-networking