Running Spring Boot docker instance with Postgres docker instance - java

I'm attempting to run a Spring Boot app that connects a Postgres DB using:
docker-compose.yml (for Postgres) :
version: '3'
services:
postgres-db:
container_name: postgres-db
image: postgres:latest
restart: always
ports:
- "5432:5432"
environment:
POSTGRES_USER: my_user
POSTGRES_PASSWORD: my_password
POSTGRES_DB: shorten-db
To run the Postgres DB:
docker-compose up
.Dockerfile (for the Spring Boot app) :
FROM openjdk:12-jdk-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
In order to run the Spring app using Docker I use:
mvn package
docker build -t url-shorten/url-shorten-docker .
docker run -p 8080:8080 url-shorten/url-shorten-docker
But I receive the error when starting when running above docker command:
Caused by: 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.
In Spring application.properties I connect to the DB using:
spring.datasource.url=jdbc:postgresql://localhost:5432/shorten-db
I think this error is due to the Spring Boot app is running in a different container to DB so it cannot find the DB on localhost. Is there an idiomatic way of connecting the Spring Book docker container to the DB container. Or do I have do access the IP address of my machine and use this address to connect to the Postgres DB running on Docker?

Yes, you can't use localhost in this situation
spring.datasource.url=jdbc:postgresql://postgres-db:5432/shorten-db

In Spring application.properties, try to change DB config to:
spring.datasource.url=jdbc:postgresql://postgres-db:5432/shorten-db
In container networks, You need to use the container name as a host.

You can add both DB and app containers to one Docker network and change PostgreSQL host in datasource URL to postgres-db. Then Spring app will work with your DB.

Related

Getting "Exception opening socket" on Mongodb connection from Spring App (docker-compose)

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

Unable to link two Docker containers on a custom bridge network on Windows

I want two Docker containers to be able to communicate with each other on a Windows machine running Docker Toolbox. I am able to link the containers using the --link option; however, if I try to run the containers on a custom bridge network that I created, the containers are unable to communicate with each other :
Here are the steps I followed :
docker network create web-application-mysql-network
docker run --detach --env MYSQL_ROOT_PASSWORD=somepassword--env MYSQL_USER=some-user --env MYSQL_PASSWORD=pass --env MYSQL_DATABASE=mydb --name mysql --publish 3306:3306 --network=web-application-mysql-network mysql:5.7
docker run -p 8080:8080 -d --network=web-application-mysql-network myrepo/mywebapp:0.0.1-SNAPSHOT
The image in the last command above contains the Tomcat web server Docker image as the base image and a "WAR" (web archive file) that will be hosted in Tomcat. When I check the logs for the container started by the last command, I can see the following errors :
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
I am able to link the two containers without any issues if I used the --link option instead of running them on my custom bridge network.
Additional info : I am using localhost in my web app code for the MySQL URL. This seemed to work fine when using --link
What configuration/command parameters am I missing to make this work?
When you're using the network, you should use the container name you want to connect to in the URL. In other words, you have to use mysql in mywebapp to reach the DB.
I'd suggest you take a check to docker-compose since it allows you to avoid the manual creation of the network.
Here's an example:
version: "3"
services:
mysql:
image: mysql:5.7
env_file:
- db.env
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_USER: ${MYSQL_USER:-user}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_DATABASE: "mydb"
volumes:
- dbdata:/var/lib/mysql
mywebapp:
image: myrepo/mywebapp:${TAG_VERSION:-0.0.1-SNAPSHOT}
build:
context: ./mywebapp_location
dockerfile: Dockerfile
ports:
- "8080:8080"
volumes:
dbdata:
db.env:
MYSQL_ROOT_PASSWORD=mysql_root_password
MYSQL_USER=the_user
MYSQL_PASSWORD=the_user_password
To build you can simply execute:
docker-compose build
and to start simply:
docker-compose up
for the rest you can use the normal docker commands.

Docker postgres on local machine: connection to localhost:5432 refused. Check that the hostname and port are correct [duplicate]

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.

Application running in docker can't connect with elasticsearch docker

I am new to docker and having a simple DW(dropwizard) application that connects to elasticsearch, Which is already running in docker using the docker-compose.yml, which has the following content.
Docker-compose.yml for elasticsearch
version: '2.2'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.6.0
container_name: elasticsearch
environment:
- xpack.security.enabled=false
- discovery.type=single-node
ports:
- 8200:9200
- 8300:9300
volumes:
elasticsearch-data:
driver: local
Note: I am exposing 8200 and 8300 as ES port on my host(local mac system)
Now everything works fine when I simply run my DW application which connects to ES in 8200 on localhost, but now I am trying to dockerize my DW application and facing few issues.
Below is my Dockerfile for DW application
COPY target/my.jar my.jar
COPY config.yml config.yml
ENTRYPOINT ["java" , "-jar" , "my.jar", "server", "config.yml"]
When I run my above DW docker image, it immediately stops, using docker logs <my-container-id>, it throws below exception:
*java.io.IOException: elasticsearch: Name does not resolve*
org.elasticsearch.client.IndicesClient.exists(IndicesClient.java:827)
**Caused by: java.net.UnknownHostException: elasticsearch: Name does not resolve**
Things I have tried
The error message clearly mentions my DW app docker instance is not able to connect to elasticsearch, which I verified running fine.
Also checked the network of Elaticsearch docker and it has the network alias as elasticsearch as shown below and n/w as docker-files_default.
"Aliases": [
"elasticsearch",
"de78c684ae60"
],
Checked the n/w of my DW app docker instance and it uses bridge network and doesn't have any network alias.
Now, how can I make both my app docker and elasticsearch docker use the same network so that they can connect with each other, I guess this would solve the issue?
Two ways to solve this: First is to check what network docker-compose created for your elasticsearch setting (docker network ls) and then run your DW app with
docker run --network=<name of network> ...
Second way is to create a network docker network create elastic and use it as external network in your docker compose file as well as in your docker run command for the DW app.
Docker compose file could then look like
...
services:
elasticsearch:
networks:
elastic:
...
networks:
elastic:
external: true

Spring Boot + docker-compose + MySQL: Connection refused

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.

Categories